From e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e Mon Sep 17 00:00:00 2001 From: Chunseok Lee Date: Thu, 23 Apr 2020 14:45:49 +0900 Subject: Imported Upstream version 1.4.0 --- runtime/onert/CMakeLists.txt | 15 + runtime/onert/api/CMakeLists.txt | 21 + runtime/onert/api/include/nnfw.h | 409 + runtime/onert/api/include/nnfw_debug.h | 26 + runtime/onert/api/include/nnfw_dev.h | 65 + runtime/onert/api/include/nnfw_version.h | 26 + runtime/onert/api/src/CustomKernel.cc | 98 + runtime/onert/api/src/CustomKernel.h | 60 + runtime/onert/api/src/CustomKernelRegistry.cc | 64 + runtime/onert/api/src/CustomKernelRegistry.h | 64 + runtime/onert/api/src/OpMap.lst | 89 + runtime/onert/api/src/nnfw_api.cc | 299 + runtime/onert/api/src/nnfw_api_internal.cc | 518 + runtime/onert/api/src/nnfw_api_internal.h | 92 + runtime/onert/api/src/nnfw_debug.cc | 29 + runtime/onert/api/src/nnfw_debug_internal.cc | 25 + runtime/onert/api/src/nnfw_debug_internal.h | 29 + runtime/onert/backend/CMakeLists.txt | 8 + runtime/onert/backend/acl_cl/Backend.h | 68 + runtime/onert/backend/acl_cl/CLTimer.h | 108 + runtime/onert/backend/acl_cl/CMakeLists.txt | 19 + runtime/onert/backend/acl_cl/Config.cc | 50 + runtime/onert/backend/acl_cl/Config.h | 44 + .../onert/backend/acl_cl/ConstantInitializer.cc | 196 + runtime/onert/backend/acl_cl/ConstantInitializer.h | 63 + runtime/onert/backend/acl_cl/KernelGenerator.cc | 2023 ++++ runtime/onert/backend/acl_cl/KernelGenerator.h | 112 + runtime/onert/backend/acl_cl/Optimizer.cc | 58 + runtime/onert/backend/acl_cl/Optimizer.h | 47 + runtime/onert/backend/acl_cl/ShapeFixer.cc | 431 + runtime/onert/backend/acl_cl/ShapeFixer.h | 110 + runtime/onert/backend/acl_cl/TensorBuilder.h | 39 + runtime/onert/backend/acl_cl/TensorManager.h | 78 + runtime/onert/backend/acl_cl/acl_cl.cc | 33 + .../onert/backend/acl_cl/operand/CLSubTensor.cc | 44 + runtime/onert/backend/acl_cl/operand/CLSubTensor.h | 62 + runtime/onert/backend/acl_cl/operand/CLTensor.cc | 62 + runtime/onert/backend/acl_cl/operand/CLTensor.h | 75 + runtime/onert/backend/acl_cl/operand/ICLTensor.cc | 45 + runtime/onert/backend/acl_cl/operand/ICLTensor.h | 50 + .../backend/acl_common/AclActivationBuilder.h | 125 + runtime/onert/backend/acl_common/AclFunction.h | 69 + .../backend/acl_common/AclInternalBufferManager.h | 97 + .../backend/acl_common/AclLinearMemoryManager.h | 110 + .../onert/backend/acl_common/AclMemoryManager.h | 98 + .../backend/acl_common/AclSubTensorAnalyzer.h | 105 + .../onert/backend/acl_common/AclTensorBuilder.h | 483 + .../onert/backend/acl_common/AclTensorManager.h | 301 + runtime/onert/backend/acl_common/CMakeLists.txt | 19 + runtime/onert/backend/acl_common/Convert.cc | 198 + runtime/onert/backend/acl_common/Convert.h | 74 + runtime/onert/backend/acl_common/IACLTensor.cc | 63 + runtime/onert/backend/acl_common/IACLTensor.h | 68 + runtime/onert/backend/acl_common/ParentInfo.h | 44 + runtime/onert/backend/acl_common/Swizzle.h | 160 + runtime/onert/backend/acl_neon/Backend.h | 69 + runtime/onert/backend/acl_neon/CMakeLists.txt | 19 + runtime/onert/backend/acl_neon/Config.cc | 30 + runtime/onert/backend/acl_neon/Config.h | 45 + .../onert/backend/acl_neon/ConstantInitializer.cc | 183 + .../onert/backend/acl_neon/ConstantInitializer.h | 60 + runtime/onert/backend/acl_neon/KernelGenerator.cc | 2030 ++++ runtime/onert/backend/acl_neon/KernelGenerator.h | 112 + runtime/onert/backend/acl_neon/Optimizer.cc | 58 + runtime/onert/backend/acl_neon/Optimizer.h | 47 + runtime/onert/backend/acl_neon/ShapeFixer.cc | 437 + runtime/onert/backend/acl_neon/ShapeFixer.h | 110 + runtime/onert/backend/acl_neon/TensorBuilder.h | 39 + runtime/onert/backend/acl_neon/TensorManager.h | 77 + runtime/onert/backend/acl_neon/acl_neon.cc | 33 + .../onert/backend/acl_neon/operand/INETensor.cc | 33 + runtime/onert/backend/acl_neon/operand/INETensor.h | 46 + .../onert/backend/acl_neon/operand/NESubTensor.cc | 44 + .../onert/backend/acl_neon/operand/NESubTensor.h | 62 + runtime/onert/backend/acl_neon/operand/NETensor.cc | 45 + runtime/onert/backend/acl_neon/operand/NETensor.h | 64 + runtime/onert/backend/cpu/Backend.h | 67 + runtime/onert/backend/cpu/CMakeLists.txt | 14 + runtime/onert/backend/cpu/Config.cc | 30 + runtime/onert/backend/cpu/Config.h | 45 + runtime/onert/backend/cpu/ConstantInitializer.cc | 68 + runtime/onert/backend/cpu/ConstantInitializer.h | 54 + runtime/onert/backend/cpu/KernelGenerator.cc | 932 ++ runtime/onert/backend/cpu/KernelGenerator.h | 93 + runtime/onert/backend/cpu/ShapeFixer.cc | 181 + runtime/onert/backend/cpu/ShapeFixer.h | 85 + runtime/onert/backend/cpu/TensorBuilder.cc | 93 + runtime/onert/backend/cpu/TensorBuilder.h | 76 + runtime/onert/backend/cpu/TensorManager.cc | 114 + runtime/onert/backend/cpu/TensorManager.h | 65 + runtime/onert/backend/cpu/cpu.cc | 33 + runtime/onert/backend/cpu/kernel/AbsLayer.cc | 67 + runtime/onert/backend/cpu/kernel/AbsLayer.h | 63 + runtime/onert/backend/cpu/kernel/AddLayer.cc | 96 + runtime/onert/backend/cpu/kernel/AddLayer.h | 71 + runtime/onert/backend/cpu/kernel/AvgPoolLayer.cc | 116 + runtime/onert/backend/cpu/kernel/AvgPoolLayer.h | 81 + runtime/onert/backend/cpu/kernel/CastLayer.cc | 108 + runtime/onert/backend/cpu/kernel/CastLayer.h | 63 + runtime/onert/backend/cpu/kernel/CompareLayer.cc | 180 + runtime/onert/backend/cpu/kernel/CompareLayer.h | 65 + runtime/onert/backend/cpu/kernel/ConcatLayer.cc | 134 + runtime/onert/backend/cpu/kernel/ConcatLayer.h | 65 + .../onert/backend/cpu/kernel/ConvolutionLayer.cc | 159 + .../onert/backend/cpu/kernel/ConvolutionLayer.h | 96 + .../cpu/kernel/DepthwiseConvolutionLayer.cc | 136 + .../backend/cpu/kernel/DepthwiseConvolutionLayer.h | 83 + runtime/onert/backend/cpu/kernel/DivLayer.cc | 92 + runtime/onert/backend/cpu/kernel/DivLayer.h | 71 + runtime/onert/backend/cpu/kernel/ExpLayer.cc | 71 + runtime/onert/backend/cpu/kernel/ExpLayer.h | 63 + .../backend/cpu/kernel/FullyConnectedLayer.cc | 141 + .../onert/backend/cpu/kernel/FullyConnectedLayer.h | 81 + runtime/onert/backend/cpu/kernel/GatherLayer.cc | 77 + runtime/onert/backend/cpu/kernel/GatherLayer.h | 66 + runtime/onert/backend/cpu/kernel/LogisticLayer.cc | 71 + runtime/onert/backend/cpu/kernel/LogisticLayer.h | 63 + runtime/onert/backend/cpu/kernel/MaxLayer.cc | 78 + runtime/onert/backend/cpu/kernel/MaxLayer.h | 67 + runtime/onert/backend/cpu/kernel/MaxPoolLayer.cc | 113 + runtime/onert/backend/cpu/kernel/MaxPoolLayer.h | 81 + runtime/onert/backend/cpu/kernel/MinLayer.cc | 78 + runtime/onert/backend/cpu/kernel/MinLayer.h | 67 + runtime/onert/backend/cpu/kernel/MulLayer.cc | 92 + runtime/onert/backend/cpu/kernel/MulLayer.h | 71 + runtime/onert/backend/cpu/kernel/OneHotLayer.cc | 70 + runtime/onert/backend/cpu/kernel/OneHotLayer.h | 73 + runtime/onert/backend/cpu/kernel/OperationUtils.cc | 269 + runtime/onert/backend/cpu/kernel/OperationUtils.h | 162 + runtime/onert/backend/cpu/kernel/PackLayer.cc | 98 + runtime/onert/backend/cpu/kernel/PackLayer.h | 65 + runtime/onert/backend/cpu/kernel/PadLayer.cc | 70 + runtime/onert/backend/cpu/kernel/PadLayer.h | 71 + runtime/onert/backend/cpu/kernel/PermuteLayer.cc | 71 + runtime/onert/backend/cpu/kernel/PermuteLayer.h | 209 + runtime/onert/backend/cpu/kernel/ReduceLayer.cc | 137 + runtime/onert/backend/cpu/kernel/ReduceLayer.h | 84 + runtime/onert/backend/cpu/kernel/ReshapeLayer.cc | 55 + runtime/onert/backend/cpu/kernel/ReshapeLayer.h | 63 + runtime/onert/backend/cpu/kernel/RsqrtLayer.cc | 70 + runtime/onert/backend/cpu/kernel/RsqrtLayer.h | 59 + runtime/onert/backend/cpu/kernel/ShapeLayer.cc | 81 + runtime/onert/backend/cpu/kernel/ShapeLayer.h | 61 + runtime/onert/backend/cpu/kernel/SinLayer.cc | 69 + runtime/onert/backend/cpu/kernel/SinLayer.h | 60 + runtime/onert/backend/cpu/kernel/SliceLayer.cc | 111 + runtime/onert/backend/cpu/kernel/SliceLayer.h | 71 + runtime/onert/backend/cpu/kernel/SoftMaxLayer.cc | 173 + runtime/onert/backend/cpu/kernel/SoftMaxLayer.h | 65 + runtime/onert/backend/cpu/kernel/SplitLayer.cc | 98 + runtime/onert/backend/cpu/kernel/SplitLayer.h | 66 + .../onert/backend/cpu/kernel/StridedSliceLayer.cc | 96 + .../onert/backend/cpu/kernel/StridedSliceLayer.h | 78 + runtime/onert/backend/cpu/kernel/SubLayer.cc | 92 + runtime/onert/backend/cpu/kernel/SubLayer.h | 71 + runtime/onert/backend/cpu/kernel/TanhLayer.cc | 71 + runtime/onert/backend/cpu/kernel/TanhLayer.h | 63 + runtime/onert/backend/cpu/kernel/TransposeLayer.cc | 81 + runtime/onert/backend/cpu/kernel/TransposeLayer.h | 61 + runtime/onert/backend/cpu/kernel/UnpackLayer.cc | 104 + runtime/onert/backend/cpu/kernel/UnpackLayer.h | 66 + runtime/onert/backend/cpu/operand/Tensor.cc | 45 + runtime/onert/backend/cpu/operand/Tensor.h | 124 + runtime/onert/backend/cpu_common/Allocator.cc | 38 + runtime/onert/backend/cpu_common/Allocator.h | 56 + runtime/onert/backend/cpu_common/CMakeLists.txt | 35 + runtime/onert/backend/cpu_common/MemoryManager.cc | 91 + runtime/onert/backend/cpu_common/MemoryManager.h | 72 + runtime/onert/backend/cpu_common/MemoryPlanner.cc | 212 + runtime/onert/backend/cpu_common/MemoryPlanner.h | 200 + .../onert/backend/cpu_common/MemoryPlanner.test.cc | 193 + .../backend/cpu_common/MemoryPlannerFactory.cc | 51 + .../backend/cpu_common/MemoryPlannerFactory.h | 47 + runtime/onert/core/CMakeLists.txt | 21 + runtime/onert/core/include/backend/Backend.h | 50 + .../onert/core/include/backend/BackendContext.h | 91 + .../core/include/backend/CustomKernelBuilder.h | 77 + runtime/onert/core/include/backend/IConfig.h | 45 + .../core/include/backend/IConstantInitializer.h | 280 + .../onert/core/include/backend/IKernelGenerator.h | 76 + .../onert/core/include/backend/IMemoryManager.h | 49 + runtime/onert/core/include/backend/IOptimizer.h | 51 + runtime/onert/core/include/backend/IShapeFixer.h | 55 + runtime/onert/core/include/backend/ITensor.h | 58 + .../onert/core/include/backend/ITensorBuilder.h | 77 + .../onert/core/include/backend/ITensorManager.h | 51 + .../onert/core/include/backend/ITensorRegister.h | 97 + .../onert/core/include/compiler/BackendManager.h | 81 + .../onert/core/include/compiler/BackendResolver.h | 60 + runtime/onert/core/include/compiler/CodeMap.h | 45 + runtime/onert/core/include/compiler/Compiler.h | 118 + .../onert/core/include/compiler/ExecutionBuilder.h | 49 + runtime/onert/core/include/exec/ExecTime.h | 112 + runtime/onert/core/include/exec/Execution.h | 144 + .../onert/core/include/exec/ExecutionObservers.h | 83 + runtime/onert/core/include/exec/FunctionSequence.h | 72 + runtime/onert/core/include/exec/IExecutor.h | 72 + runtime/onert/core/include/exec/IFunction.h | 37 + runtime/onert/core/include/exec/IODescription.h | 66 + runtime/onert/core/include/exec/JSONExecTime.h | 97 + runtime/onert/core/include/exec/NopFunction.h | 54 + runtime/onert/core/include/interp/InterpExecutor.h | 70 + runtime/onert/core/include/ir/BackendSet.h | 40 + runtime/onert/core/include/ir/Coordinates.h | 113 + runtime/onert/core/include/ir/Data.h | 75 + runtime/onert/core/include/ir/DataType.h | 62 + runtime/onert/core/include/ir/Graph.h | 114 + runtime/onert/core/include/ir/Index.h | 45 + runtime/onert/core/include/ir/InternalType.h | 46 + runtime/onert/core/include/ir/Layout.h | 67 + runtime/onert/core/include/ir/LowerInfoMap.h | 42 + runtime/onert/core/include/ir/LoweredGraph.h | 78 + runtime/onert/core/include/ir/OpCode.h | 56 + runtime/onert/core/include/ir/OpSequence.h | 106 + runtime/onert/core/include/ir/OpSequences.h | 87 + runtime/onert/core/include/ir/Operand.h | 114 + runtime/onert/core/include/ir/OperandConstraint.h | 58 + runtime/onert/core/include/ir/OperandIndexMap.h | 34 + .../onert/core/include/ir/OperandIndexSequence.h | 63 + runtime/onert/core/include/ir/OperandInfo.h | 129 + runtime/onert/core/include/ir/Operands.h | 46 + runtime/onert/core/include/ir/Operation.h | 71 + runtime/onert/core/include/ir/OperationIndexList.h | 59 + runtime/onert/core/include/ir/OperationIndexMap.h | 34 + runtime/onert/core/include/ir/OperationVisitor.h | 52 + runtime/onert/core/include/ir/Operations.Include.h | 87 + runtime/onert/core/include/ir/Operations.h | 43 + runtime/onert/core/include/ir/Operations.lst | 90 + runtime/onert/core/include/ir/Padding.h | 73 + runtime/onert/core/include/ir/Shape.h | 86 + runtime/onert/core/include/ir/TypeInfo.h | 59 + runtime/onert/core/include/ir/operand/LowerInfo.h | 69 + .../onert/core/include/ir/operand/PermuteFactor.h | 130 + runtime/onert/core/include/ir/operation/Abs.h | 49 + runtime/onert/core/include/ir/operation/Add.h | 62 + runtime/onert/core/include/ir/operation/ArgMax.h | 62 + .../onert/core/include/ir/operation/AvgPool2D.h | 70 + .../core/include/ir/operation/BatchToSpaceND.h | 50 + runtime/onert/core/include/ir/operation/Cast.h | 49 + .../onert/core/include/ir/operation/Comparison.h | 72 + runtime/onert/core/include/ir/operation/Concat.h | 59 + runtime/onert/core/include/ir/operation/Conv2D.h | 69 + .../core/include/ir/operation/ConvertFp16ToFp32.h | 49 + .../core/include/ir/operation/ConvertFp32ToFp16.h | 49 + runtime/onert/core/include/ir/operation/Custom.h | 75 + .../onert/core/include/ir/operation/DepthToSpace.h | 63 + .../core/include/ir/operation/DepthwiseConv2D.h | 70 + .../onert/core/include/ir/operation/Dequantize.h | 49 + runtime/onert/core/include/ir/operation/Div.h | 62 + .../core/include/ir/operation/EmbeddingLookup.h | 50 + runtime/onert/core/include/ir/operation/Exp.h | 49 + runtime/onert/core/include/ir/operation/Floor.h | 51 + .../core/include/ir/operation/FullyConnected.h | 66 + runtime/onert/core/include/ir/operation/Gather.h | 65 + .../core/include/ir/operation/HashtableLookup.h | 57 + .../onert/core/include/ir/operation/InstanceNorm.h | 65 + .../core/include/ir/operation/L2Normalization.h | 62 + runtime/onert/core/include/ir/operation/L2Pool2D.h | 69 + runtime/onert/core/include/ir/operation/LSTM.h | 89 + .../ir/operation/LocalResponseNormalization.h | 66 + .../onert/core/include/ir/operation/LogicalAnd.h | 50 + .../onert/core/include/ir/operation/LogicalNot.h | 49 + .../onert/core/include/ir/operation/LogicalOr.h | 50 + runtime/onert/core/include/ir/operation/Logistic.h | 49 + .../onert/core/include/ir/operation/LowerInfo.h | 54 + runtime/onert/core/include/ir/operation/Max.h | 50 + .../onert/core/include/ir/operation/MaxPool2D.h | 69 + runtime/onert/core/include/ir/operation/Mean.h | 62 + runtime/onert/core/include/ir/operation/Min.h | 50 + runtime/onert/core/include/ir/operation/Mul.h | 62 + runtime/onert/core/include/ir/operation/Neg.h | 49 + runtime/onert/core/include/ir/operation/OneHot.h | 63 + runtime/onert/core/include/ir/operation/PReLU.h | 50 + runtime/onert/core/include/ir/operation/Pack.h | 53 + runtime/onert/core/include/ir/operation/Pad.h | 63 + runtime/onert/core/include/ir/operation/Permute.h | 78 + runtime/onert/core/include/ir/operation/RNN.h | 70 + runtime/onert/core/include/ir/operation/RSQRT.h | 49 + runtime/onert/core/include/ir/operation/ReLU.h | 49 + runtime/onert/core/include/ir/operation/ReLU1.h | 49 + runtime/onert/core/include/ir/operation/ReLU6.h | 49 + .../onert/core/include/ir/operation/ReduceMax.h | 65 + .../onert/core/include/ir/operation/ReduceMin.h | 65 + .../onert/core/include/ir/operation/ReduceSum.h | 63 + runtime/onert/core/include/ir/operation/Reshape.h | 52 + .../core/include/ir/operation/ResizeBilinear.h | 64 + runtime/onert/core/include/ir/operation/SQRT.h | 49 + runtime/onert/core/include/ir/operation/Shape.h | 51 + runtime/onert/core/include/ir/operation/Sin.h | 49 + runtime/onert/core/include/ir/operation/Slice.h | 64 + runtime/onert/core/include/ir/operation/Softmax.h | 63 + .../core/include/ir/operation/SpaceToBatchND.h | 53 + .../onert/core/include/ir/operation/SpaceToDepth.h | 63 + runtime/onert/core/include/ir/operation/Split.h | 59 + .../core/include/ir/operation/SquaredDifference.h | 50 + runtime/onert/core/include/ir/operation/Squeeze.h | 62 + .../onert/core/include/ir/operation/StridedSlice.h | 69 + runtime/onert/core/include/ir/operation/Sub.h | 62 + runtime/onert/core/include/ir/operation/Tanh.h | 49 + runtime/onert/core/include/ir/operation/TopKV2.h | 69 + .../onert/core/include/ir/operation/Transpose.h | 64 + .../core/include/ir/operation/TransposeConv.h | 68 + runtime/onert/core/include/ir/operation/Unpack.h | 59 + runtime/onert/core/include/util/Config.lst | 44 + runtime/onert/core/include/util/ConfigSource.h | 58 + runtime/onert/core/include/util/EnvConfigSource.h | 41 + .../onert/core/include/util/EventCollectorGlobal.h | 155 + .../onert/core/include/util/GeneralConfigSource.h | 44 + runtime/onert/core/include/util/IConfigSource.h | 46 + runtime/onert/core/include/util/ITimer.h | 59 + runtime/onert/core/include/util/Index.h | 154 + runtime/onert/core/include/util/ObjectManager.h | 148 + runtime/onert/core/include/util/Set.h | 166 + runtime/onert/core/include/util/ShapeInference.h | 90 + runtime/onert/core/include/util/Utils.h | 27 + .../onert/core/include/util/feature/nchw/Reader.h | 118 + .../onert/core/include/util/feature/nchw/View.h | 137 + .../onert/core/include/util/feature/nhwc/Reader.h | 120 + .../onert/core/include/util/feature/nhwc/View.h | 139 + runtime/onert/core/include/util/logging.h | 63 + runtime/onert/core/src/backend/BackendContext.cc | 64 + runtime/onert/core/src/compiler/BackendManager.cc | 140 + runtime/onert/core/src/compiler/BackendResolver.cc | 25 + .../onert/core/src/compiler/CachedDataDeleter.h | 103 + runtime/onert/core/src/compiler/Compiler.cc | 209 + runtime/onert/core/src/compiler/ExecutorFactory.cc | 379 + runtime/onert/core/src/compiler/ExecutorFactory.h | 62 + runtime/onert/core/src/compiler/HEScheduler.cc | 615 ++ runtime/onert/core/src/compiler/HEScheduler.h | 186 + runtime/onert/core/src/compiler/IScheduler.h | 38 + runtime/onert/core/src/compiler/Linear.cc | 280 + runtime/onert/core/src/compiler/Linear.h | 54 + runtime/onert/core/src/compiler/ManualScheduler.cc | 103 + runtime/onert/core/src/compiler/ManualScheduler.h | 41 + runtime/onert/core/src/compiler/OperandContext.cc | 45 + runtime/onert/core/src/compiler/OperandContext.h | 55 + .../onert/core/src/compiler/OperationValidator.cc | 1079 +++ .../onert/core/src/compiler/OperationValidator.h | 93 + runtime/onert/core/src/compiler/ParamChecker.cc | 33 + runtime/onert/core/src/compiler/ParamChecker.h | 73 + runtime/onert/core/src/dumper/dot/DotBuilder.cc | 83 + runtime/onert/core/src/dumper/dot/DotBuilder.h | 62 + runtime/onert/core/src/dumper/dot/DotDumper.cc | 199 + runtime/onert/core/src/dumper/dot/DotDumper.h | 69 + .../onert/core/src/dumper/dot/DotOpSequenceInfo.cc | 56 + .../onert/core/src/dumper/dot/DotOpSequenceInfo.h | 59 + runtime/onert/core/src/dumper/dot/Node.cc | 56 + runtime/onert/core/src/dumper/dot/Node.h | 127 + runtime/onert/core/src/dumper/dot/OperandNode.cc | 60 + runtime/onert/core/src/dumper/dot/OperandNode.h | 79 + runtime/onert/core/src/dumper/dot/OperationNode.cc | 46 + runtime/onert/core/src/dumper/dot/OperationNode.h | 62 + runtime/onert/core/src/exec/DataflowExecutor.cc | 175 + runtime/onert/core/src/exec/DataflowExecutor.h | 96 + runtime/onert/core/src/exec/ExecTime.cc | 137 + runtime/onert/core/src/exec/Execution.cc | 131 + runtime/onert/core/src/exec/ExecutionObservee.cc | 64 + runtime/onert/core/src/exec/ExecutionObservee.h | 56 + runtime/onert/core/src/exec/ExecutionObservers.cc | 126 + runtime/onert/core/src/exec/ExecutorBase.cc | 165 + runtime/onert/core/src/exec/ExecutorBase.h | 133 + runtime/onert/core/src/exec/FunctionSequence.cc | 62 + runtime/onert/core/src/exec/JSONExecTime.cc | 231 + runtime/onert/core/src/exec/Job.cc | 33 + runtime/onert/core/src/exec/Job.h | 69 + runtime/onert/core/src/exec/LinearExecutor.cc | 39 + runtime/onert/core/src/exec/LinearExecutor.h | 70 + runtime/onert/core/src/exec/ParallelExecutor.cc | 146 + runtime/onert/core/src/exec/ParallelExecutor.h | 67 + runtime/onert/core/src/exec/ParallelScheduler.cc | 55 + runtime/onert/core/src/exec/ParallelScheduler.h | 60 + runtime/onert/core/src/exec/Sink.h | 199 + runtime/onert/core/src/exec/Source.h | 208 + runtime/onert/core/src/exec/ThreadPool.cc | 65 + runtime/onert/core/src/exec/ThreadPool.h | 73 + runtime/onert/core/src/exec/WorkQueue.cc | 104 + runtime/onert/core/src/exec/WorkQueue.h | 87 + runtime/onert/core/src/interp/Buffer.h | 91 + runtime/onert/core/src/interp/ExecEnv.h | 162 + runtime/onert/core/src/interp/InterpExecutor.cc | 114 + runtime/onert/core/src/interp/InterpOps.lst | 89 + runtime/onert/core/src/interp/Interpreter.cc | 184 + runtime/onert/core/src/interp/Interpreter.h | 64 + runtime/onert/core/src/interp/Registration.h | 43 + runtime/onert/core/src/interp/Tensor.cc | 53 + runtime/onert/core/src/interp/Tensor.h | 177 + .../onert/core/src/interp/operations/AvgPool2D.cc | 125 + .../src/interp/operations/BinaryArithmeticOps.cc | 193 + runtime/onert/core/src/interp/operations/Concat.cc | 147 + runtime/onert/core/src/interp/operations/Conv2D.cc | 150 + .../core/src/interp/operations/DepthwiseConv2D.cc | 155 + .../core/src/interp/operations/FullyConnected.cc | 135 + runtime/onert/core/src/interp/operations/Gather.cc | 138 + .../core/src/interp/operations/InstanceNorm.cc | 121 + .../onert/core/src/interp/operations/Logistic.cc | 99 + .../onert/core/src/interp/operations/MaxPool2D.cc | 124 + .../core/src/interp/operations/OperationUtil.h | 210 + runtime/onert/core/src/interp/operations/Pad.cc | 106 + .../onert/core/src/interp/operations/Reshape.cc | 63 + .../onert/core/src/interp/operations/Softmax.cc | 160 + .../core/src/interp/operations/TransposeConv.cc | 141 + .../core/src/interp/operations/UnaryActivations.cc | 153 + runtime/onert/core/src/ir/Coordinates.cc | 50 + runtime/onert/core/src/ir/Graph.cc | 103 + runtime/onert/core/src/ir/GraphIterator.cc | 84 + runtime/onert/core/src/ir/GraphIterator.h | 74 + runtime/onert/core/src/ir/LayoutSet.cc | 66 + runtime/onert/core/src/ir/LayoutSet.h | 58 + runtime/onert/core/src/ir/LoweredGraph.cc | 496 + runtime/onert/core/src/ir/OpCode.cc | 37 + runtime/onert/core/src/ir/OpSequence.cc | 93 + runtime/onert/core/src/ir/OpSequences.cc | 88 + runtime/onert/core/src/ir/Operand.cc | 61 + runtime/onert/core/src/ir/OperandIndexSequence.cc | 65 + runtime/onert/core/src/ir/Operands.cc | 36 + runtime/onert/core/src/ir/Operation.cc | 55 + runtime/onert/core/src/ir/OperationCloner.cc | 42 + runtime/onert/core/src/ir/OperationCloner.h | 46 + runtime/onert/core/src/ir/OperationDumper.cc | 634 ++ runtime/onert/core/src/ir/OperationDumper.h | 99 + runtime/onert/core/src/ir/OperationIndexList.cc | 37 + runtime/onert/core/src/ir/Operations.cc | 37 + runtime/onert/core/src/ir/Padding.cc | 154 + runtime/onert/core/src/ir/Shape.cc | 104 + runtime/onert/core/src/ir/TypeInfo.cc | 47 + runtime/onert/core/src/ir/operation/Abs.cc | 39 + runtime/onert/core/src/ir/operation/Add.cc | 40 + runtime/onert/core/src/ir/operation/ArgMax.cc | 40 + runtime/onert/core/src/ir/operation/AvgPool2D.cc | 40 + .../onert/core/src/ir/operation/BatchToSpaceND.cc | 40 + runtime/onert/core/src/ir/operation/Cast.cc | 39 + runtime/onert/core/src/ir/operation/Comparison.cc | 40 + runtime/onert/core/src/ir/operation/Concat.cc | 40 + runtime/onert/core/src/ir/operation/Conv2D.cc | 40 + .../core/src/ir/operation/ConvertFp16ToFp32.cc | 40 + .../core/src/ir/operation/ConvertFp32ToFp16.cc | 40 + runtime/onert/core/src/ir/operation/Custom.cc | 44 + .../onert/core/src/ir/operation/DepthToSpace.cc | 40 + .../onert/core/src/ir/operation/DepthwiseConv2D.cc | 40 + runtime/onert/core/src/ir/operation/Dequantize.cc | 39 + runtime/onert/core/src/ir/operation/Div.cc | 40 + .../onert/core/src/ir/operation/EmbeddingLookup.cc | 40 + runtime/onert/core/src/ir/operation/Exp.cc | 39 + runtime/onert/core/src/ir/operation/Floor.cc | 39 + .../onert/core/src/ir/operation/FullyConnected.cc | 40 + runtime/onert/core/src/ir/operation/Gather.cc | 40 + .../onert/core/src/ir/operation/HashtableLookup.cc | 40 + .../onert/core/src/ir/operation/InstanceNorm.cc | 40 + .../onert/core/src/ir/operation/L2Normalization.cc | 40 + runtime/onert/core/src/ir/operation/L2Pool2D.cc | 40 + runtime/onert/core/src/ir/operation/LSTM.cc | 40 + .../src/ir/operation/LocalResponseNormalization.cc | 41 + runtime/onert/core/src/ir/operation/LogicalAnd.cc | 39 + runtime/onert/core/src/ir/operation/LogicalNot.cc | 39 + runtime/onert/core/src/ir/operation/LogicalOr.cc | 39 + runtime/onert/core/src/ir/operation/Logistic.cc | 39 + runtime/onert/core/src/ir/operation/LowerInfo.cc | 34 + runtime/onert/core/src/ir/operation/Max.cc | 39 + runtime/onert/core/src/ir/operation/MaxPool2D.cc | 40 + runtime/onert/core/src/ir/operation/Mean.cc | 40 + runtime/onert/core/src/ir/operation/Min.cc | 39 + runtime/onert/core/src/ir/operation/Mul.cc | 40 + runtime/onert/core/src/ir/operation/Neg.cc | 39 + runtime/onert/core/src/ir/operation/OneHot.cc | 37 + runtime/onert/core/src/ir/operation/PReLU.cc | 39 + runtime/onert/core/src/ir/operation/Pack.cc | 33 + runtime/onert/core/src/ir/operation/Pad.cc | 38 + runtime/onert/core/src/ir/operation/Permute.cc | 44 + runtime/onert/core/src/ir/operation/RNN.cc | 40 + runtime/onert/core/src/ir/operation/RSQRT.cc | 39 + runtime/onert/core/src/ir/operation/ReLU.cc | 39 + runtime/onert/core/src/ir/operation/ReLU1.cc | 39 + runtime/onert/core/src/ir/operation/ReLU6.cc | 39 + runtime/onert/core/src/ir/operation/ReduceMax.cc | 40 + runtime/onert/core/src/ir/operation/ReduceMin.cc | 40 + runtime/onert/core/src/ir/operation/ReduceSum.cc | 40 + runtime/onert/core/src/ir/operation/Reshape.cc | 39 + .../onert/core/src/ir/operation/ResizeBilinear.cc | 40 + runtime/onert/core/src/ir/operation/SQRT.cc | 39 + runtime/onert/core/src/ir/operation/Shape.cc | 39 + runtime/onert/core/src/ir/operation/Sin.cc | 39 + runtime/onert/core/src/ir/operation/Slice.cc | 37 + runtime/onert/core/src/ir/operation/Softmax.cc | 40 + .../onert/core/src/ir/operation/SpaceToBatchND.cc | 40 + .../onert/core/src/ir/operation/SpaceToDepth.cc | 40 + runtime/onert/core/src/ir/operation/Split.cc | 33 + .../core/src/ir/operation/SquaredDifference.cc | 40 + runtime/onert/core/src/ir/operation/Squeeze.cc | 37 + .../onert/core/src/ir/operation/StridedSlice.cc | 40 + runtime/onert/core/src/ir/operation/Sub.cc | 40 + runtime/onert/core/src/ir/operation/Tanh.cc | 39 + runtime/onert/core/src/ir/operation/TopKV2.cc | 40 + runtime/onert/core/src/ir/operation/Transpose.cc | 40 + .../onert/core/src/ir/operation/TransposeConv.cc | 40 + runtime/onert/core/src/ir/operation/Unpack.cc | 33 + .../core/src/ir/pass/ConstantInsertionPass.cc | 102 + .../onert/core/src/ir/pass/ConstantInsertionPass.h | 75 + .../onert/core/src/ir/pass/LoweredOperandPass.h | 52 + .../onert/core/src/ir/pass/LoweredOperationPass.h | 52 + runtime/onert/core/src/ir/pass/OperandPass.cc | 36 + runtime/onert/core/src/ir/pass/OperandPass.h | 54 + runtime/onert/core/src/ir/pass/OperationPass.cc | 38 + runtime/onert/core/src/ir/pass/OperationPass.h | 77 + runtime/onert/core/src/ir/pass/Pass.h | 55 + .../core/src/ir/pass/PermutationEliminationPass.cc | 195 + .../core/src/ir/pass/PermutationEliminationPass.h | 86 + .../core/src/ir/pass/PermutationInsertionPass.cc | 207 + .../core/src/ir/pass/PermutationInsertionPass.h | 59 + .../core/src/ir/pass/PermutationOperationPass.cc | 231 + .../core/src/ir/pass/PermutationOperationPass.h | 54 + runtime/onert/core/src/ir/verifier/Verifier.cc | 96 + runtime/onert/core/src/ir/verifier/Verifier.h | 68 + runtime/onert/core/src/library_info.cc | 17 + runtime/onert/core/src/util/ConfigSource.cc | 122 + runtime/onert/core/src/util/EnvConfigSource.cc | 40 + .../onert/core/src/util/EventCollectorGlobal.cc | 85 + runtime/onert/core/src/util/GeneralConfigSource.cc | 45 + runtime/onert/core/src/util/ShapeInference.cc | 241 + runtime/onert/core/src/util/logging.cc | 23 + runtime/onert/frontend/CMakeLists.txt | 1 + runtime/onert/frontend/base_loader/CMakeLists.txt | 7 + .../frontend/base_loader/include/base_loader.h | 1362 +++ runtime/onert/frontend/circle/CMakeLists.txt | 17 + .../onert/frontend/circle/include/circle_loader.h | 32 + runtime/onert/frontend/circle/src/circle_loader.cc | 134 + .../frontend/circle/src/circle_schema_generated.h | 9952 ++++++++++++++++++++ .../frontend/nnapi/ANeuralNetworksModel.test.cc | 25 + runtime/onert/frontend/nnapi/CMakeLists.txt | 27 + runtime/onert/frontend/nnapi/compilation.cc | 110 + runtime/onert/frontend/nnapi/event.cc | 36 + runtime/onert/frontend/nnapi/execution.cc | 480 + runtime/onert/frontend/nnapi/memory.cc | 42 + runtime/onert/frontend/nnapi/model.cc | 411 + .../nnapi/wrapper/ANeuralNetworksCompilation.cc | 42 + .../nnapi/wrapper/ANeuralNetworksCompilation.h | 42 + .../frontend/nnapi/wrapper/ANeuralNetworksEvent.cc | 42 + .../frontend/nnapi/wrapper/ANeuralNetworksEvent.h | 44 + .../nnapi/wrapper/ANeuralNetworksExecution.cc | 288 + .../nnapi/wrapper/ANeuralNetworksExecution.h | 74 + .../nnapi/wrapper/ANeuralNetworksMemory.cc | 46 + .../frontend/nnapi/wrapper/ANeuralNetworksMemory.h | 39 + .../frontend/nnapi/wrapper/ANeuralNetworksModel.cc | 267 + .../frontend/nnapi/wrapper/ANeuralNetworksModel.h | 71 + .../onert/frontend/nnapi/wrapper/NNAPIConvert.cc | 100 + .../onert/frontend/nnapi/wrapper/NNAPIConvert.h | 79 + .../frontend/nnapi/wrapper/OperationFactory.cc | 1899 ++++ .../frontend/nnapi/wrapper/OperationFactory.h | 60 + runtime/onert/frontend/tflite/CMakeLists.txt | 17 + .../onert/frontend/tflite/include/tflite_loader.h | 34 + runtime/onert/frontend/tflite/src/tflite_loader.cc | 110 + .../frontend/tflite/src/tflite_schema_generated.h | 9553 +++++++++++++++++++ .../onert/frontend/tflite/tflite_schema-1.13.1.fbs | 795 ++ runtime/onert/frontend/tflite/tflite_schema.fbs | 1095 +++ runtime/onert/sample/CMakeLists.txt | 1 + runtime/onert/sample/minimal/CMakeLists.txt | 10 + runtime/onert/sample/minimal/README.md | 13 + runtime/onert/sample/minimal/src/minimal.cc | 69 + runtime/onert/test/CMakeLists.txt | 15 + runtime/onert/test/core/compiler/Scheduler.cc | 569 ++ runtime/onert/test/core/exec/ExecInstance.cc | 306 + runtime/onert/test/core/exec/ExecTime.test.cc | 99 + runtime/onert/test/core/interp/ExecManager.cc | 333 + runtime/onert/test/graph/Graph.cc | 52 + runtime/onert/test/graph/Index.cc | 34 + runtime/onert/test/graph/MockNode.h | 47 + runtime/onert/test/graph/operand/IndexSet.cc | 52 + runtime/onert/test/graph/operand/LayoutSet.cc | 43 + runtime/onert/test/graph/operand/Set.cc | 45 + runtime/onert/test/graph/operand/UseDef.cc | 85 + runtime/onert/test/graph/operation/Set.cc | 33 + runtime/onert/test/graph/operation/SetIO.cc | 99 + runtime/onert/test/graph/verifier/Verifier.cc | 49 + runtime/onert/test/util/ObjectManager.cc | 97 + runtime/onert/test/util/ShapeInference.cc | 230 + 574 files changed, 78539 insertions(+) create mode 100644 runtime/onert/CMakeLists.txt create mode 100644 runtime/onert/api/CMakeLists.txt create mode 100644 runtime/onert/api/include/nnfw.h create mode 100644 runtime/onert/api/include/nnfw_debug.h create mode 100644 runtime/onert/api/include/nnfw_dev.h create mode 100644 runtime/onert/api/include/nnfw_version.h create mode 100644 runtime/onert/api/src/CustomKernel.cc create mode 100644 runtime/onert/api/src/CustomKernel.h create mode 100644 runtime/onert/api/src/CustomKernelRegistry.cc create mode 100644 runtime/onert/api/src/CustomKernelRegistry.h create mode 100644 runtime/onert/api/src/OpMap.lst create mode 100644 runtime/onert/api/src/nnfw_api.cc create mode 100644 runtime/onert/api/src/nnfw_api_internal.cc create mode 100644 runtime/onert/api/src/nnfw_api_internal.h create mode 100644 runtime/onert/api/src/nnfw_debug.cc create mode 100644 runtime/onert/api/src/nnfw_debug_internal.cc create mode 100644 runtime/onert/api/src/nnfw_debug_internal.h create mode 100644 runtime/onert/backend/CMakeLists.txt create mode 100644 runtime/onert/backend/acl_cl/Backend.h create mode 100644 runtime/onert/backend/acl_cl/CLTimer.h create mode 100644 runtime/onert/backend/acl_cl/CMakeLists.txt create mode 100644 runtime/onert/backend/acl_cl/Config.cc create mode 100644 runtime/onert/backend/acl_cl/Config.h create mode 100644 runtime/onert/backend/acl_cl/ConstantInitializer.cc create mode 100644 runtime/onert/backend/acl_cl/ConstantInitializer.h create mode 100644 runtime/onert/backend/acl_cl/KernelGenerator.cc create mode 100644 runtime/onert/backend/acl_cl/KernelGenerator.h create mode 100644 runtime/onert/backend/acl_cl/Optimizer.cc create mode 100644 runtime/onert/backend/acl_cl/Optimizer.h create mode 100644 runtime/onert/backend/acl_cl/ShapeFixer.cc create mode 100644 runtime/onert/backend/acl_cl/ShapeFixer.h create mode 100644 runtime/onert/backend/acl_cl/TensorBuilder.h create mode 100644 runtime/onert/backend/acl_cl/TensorManager.h create mode 100644 runtime/onert/backend/acl_cl/acl_cl.cc create mode 100644 runtime/onert/backend/acl_cl/operand/CLSubTensor.cc create mode 100644 runtime/onert/backend/acl_cl/operand/CLSubTensor.h create mode 100644 runtime/onert/backend/acl_cl/operand/CLTensor.cc create mode 100644 runtime/onert/backend/acl_cl/operand/CLTensor.h create mode 100644 runtime/onert/backend/acl_cl/operand/ICLTensor.cc create mode 100644 runtime/onert/backend/acl_cl/operand/ICLTensor.h create mode 100644 runtime/onert/backend/acl_common/AclActivationBuilder.h create mode 100644 runtime/onert/backend/acl_common/AclFunction.h create mode 100644 runtime/onert/backend/acl_common/AclInternalBufferManager.h create mode 100644 runtime/onert/backend/acl_common/AclLinearMemoryManager.h create mode 100644 runtime/onert/backend/acl_common/AclMemoryManager.h create mode 100644 runtime/onert/backend/acl_common/AclSubTensorAnalyzer.h create mode 100644 runtime/onert/backend/acl_common/AclTensorBuilder.h create mode 100644 runtime/onert/backend/acl_common/AclTensorManager.h create mode 100644 runtime/onert/backend/acl_common/CMakeLists.txt create mode 100644 runtime/onert/backend/acl_common/Convert.cc create mode 100644 runtime/onert/backend/acl_common/Convert.h create mode 100644 runtime/onert/backend/acl_common/IACLTensor.cc create mode 100644 runtime/onert/backend/acl_common/IACLTensor.h create mode 100644 runtime/onert/backend/acl_common/ParentInfo.h create mode 100644 runtime/onert/backend/acl_common/Swizzle.h create mode 100644 runtime/onert/backend/acl_neon/Backend.h create mode 100644 runtime/onert/backend/acl_neon/CMakeLists.txt create mode 100644 runtime/onert/backend/acl_neon/Config.cc create mode 100644 runtime/onert/backend/acl_neon/Config.h create mode 100644 runtime/onert/backend/acl_neon/ConstantInitializer.cc create mode 100644 runtime/onert/backend/acl_neon/ConstantInitializer.h create mode 100644 runtime/onert/backend/acl_neon/KernelGenerator.cc create mode 100644 runtime/onert/backend/acl_neon/KernelGenerator.h create mode 100644 runtime/onert/backend/acl_neon/Optimizer.cc create mode 100644 runtime/onert/backend/acl_neon/Optimizer.h create mode 100644 runtime/onert/backend/acl_neon/ShapeFixer.cc create mode 100644 runtime/onert/backend/acl_neon/ShapeFixer.h create mode 100644 runtime/onert/backend/acl_neon/TensorBuilder.h create mode 100644 runtime/onert/backend/acl_neon/TensorManager.h create mode 100644 runtime/onert/backend/acl_neon/acl_neon.cc create mode 100644 runtime/onert/backend/acl_neon/operand/INETensor.cc create mode 100644 runtime/onert/backend/acl_neon/operand/INETensor.h create mode 100644 runtime/onert/backend/acl_neon/operand/NESubTensor.cc create mode 100644 runtime/onert/backend/acl_neon/operand/NESubTensor.h create mode 100644 runtime/onert/backend/acl_neon/operand/NETensor.cc create mode 100644 runtime/onert/backend/acl_neon/operand/NETensor.h create mode 100644 runtime/onert/backend/cpu/Backend.h create mode 100644 runtime/onert/backend/cpu/CMakeLists.txt create mode 100644 runtime/onert/backend/cpu/Config.cc create mode 100644 runtime/onert/backend/cpu/Config.h create mode 100644 runtime/onert/backend/cpu/ConstantInitializer.cc create mode 100644 runtime/onert/backend/cpu/ConstantInitializer.h create mode 100644 runtime/onert/backend/cpu/KernelGenerator.cc create mode 100644 runtime/onert/backend/cpu/KernelGenerator.h create mode 100644 runtime/onert/backend/cpu/ShapeFixer.cc create mode 100644 runtime/onert/backend/cpu/ShapeFixer.h create mode 100644 runtime/onert/backend/cpu/TensorBuilder.cc create mode 100644 runtime/onert/backend/cpu/TensorBuilder.h create mode 100644 runtime/onert/backend/cpu/TensorManager.cc create mode 100644 runtime/onert/backend/cpu/TensorManager.h create mode 100644 runtime/onert/backend/cpu/cpu.cc create mode 100644 runtime/onert/backend/cpu/kernel/AbsLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/AbsLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/AddLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/AddLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/AvgPoolLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/AvgPoolLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/CastLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/CastLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/CompareLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/CompareLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/ConcatLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/ConcatLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/ConvolutionLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/ConvolutionLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/DepthwiseConvolutionLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/DepthwiseConvolutionLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/DivLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/DivLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/ExpLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/ExpLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/FullyConnectedLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/FullyConnectedLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/GatherLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/GatherLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/LogisticLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/LogisticLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/MaxLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/MaxLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/MaxPoolLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/MaxPoolLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/MinLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/MinLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/MulLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/MulLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/OneHotLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/OneHotLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/OperationUtils.cc create mode 100644 runtime/onert/backend/cpu/kernel/OperationUtils.h create mode 100644 runtime/onert/backend/cpu/kernel/PackLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/PackLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/PadLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/PadLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/PermuteLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/PermuteLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/ReduceLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/ReduceLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/ReshapeLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/ReshapeLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/RsqrtLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/RsqrtLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/ShapeLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/ShapeLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/SinLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/SinLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/SliceLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/SliceLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/SoftMaxLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/SoftMaxLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/SplitLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/SplitLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/StridedSliceLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/StridedSliceLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/SubLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/SubLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/TanhLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/TanhLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/TransposeLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/TransposeLayer.h create mode 100644 runtime/onert/backend/cpu/kernel/UnpackLayer.cc create mode 100644 runtime/onert/backend/cpu/kernel/UnpackLayer.h create mode 100644 runtime/onert/backend/cpu/operand/Tensor.cc create mode 100644 runtime/onert/backend/cpu/operand/Tensor.h create mode 100644 runtime/onert/backend/cpu_common/Allocator.cc create mode 100644 runtime/onert/backend/cpu_common/Allocator.h create mode 100644 runtime/onert/backend/cpu_common/CMakeLists.txt create mode 100644 runtime/onert/backend/cpu_common/MemoryManager.cc create mode 100644 runtime/onert/backend/cpu_common/MemoryManager.h create mode 100644 runtime/onert/backend/cpu_common/MemoryPlanner.cc create mode 100644 runtime/onert/backend/cpu_common/MemoryPlanner.h create mode 100644 runtime/onert/backend/cpu_common/MemoryPlanner.test.cc create mode 100644 runtime/onert/backend/cpu_common/MemoryPlannerFactory.cc create mode 100644 runtime/onert/backend/cpu_common/MemoryPlannerFactory.h create mode 100644 runtime/onert/core/CMakeLists.txt create mode 100644 runtime/onert/core/include/backend/Backend.h create mode 100644 runtime/onert/core/include/backend/BackendContext.h create mode 100644 runtime/onert/core/include/backend/CustomKernelBuilder.h create mode 100644 runtime/onert/core/include/backend/IConfig.h create mode 100644 runtime/onert/core/include/backend/IConstantInitializer.h create mode 100644 runtime/onert/core/include/backend/IKernelGenerator.h create mode 100644 runtime/onert/core/include/backend/IMemoryManager.h create mode 100644 runtime/onert/core/include/backend/IOptimizer.h create mode 100644 runtime/onert/core/include/backend/IShapeFixer.h create mode 100644 runtime/onert/core/include/backend/ITensor.h create mode 100644 runtime/onert/core/include/backend/ITensorBuilder.h create mode 100644 runtime/onert/core/include/backend/ITensorManager.h create mode 100644 runtime/onert/core/include/backend/ITensorRegister.h create mode 100644 runtime/onert/core/include/compiler/BackendManager.h create mode 100644 runtime/onert/core/include/compiler/BackendResolver.h create mode 100644 runtime/onert/core/include/compiler/CodeMap.h create mode 100644 runtime/onert/core/include/compiler/Compiler.h create mode 100644 runtime/onert/core/include/compiler/ExecutionBuilder.h create mode 100644 runtime/onert/core/include/exec/ExecTime.h create mode 100644 runtime/onert/core/include/exec/Execution.h create mode 100644 runtime/onert/core/include/exec/ExecutionObservers.h create mode 100644 runtime/onert/core/include/exec/FunctionSequence.h create mode 100644 runtime/onert/core/include/exec/IExecutor.h create mode 100644 runtime/onert/core/include/exec/IFunction.h create mode 100644 runtime/onert/core/include/exec/IODescription.h create mode 100644 runtime/onert/core/include/exec/JSONExecTime.h create mode 100644 runtime/onert/core/include/exec/NopFunction.h create mode 100644 runtime/onert/core/include/interp/InterpExecutor.h create mode 100644 runtime/onert/core/include/ir/BackendSet.h create mode 100644 runtime/onert/core/include/ir/Coordinates.h create mode 100644 runtime/onert/core/include/ir/Data.h create mode 100644 runtime/onert/core/include/ir/DataType.h create mode 100644 runtime/onert/core/include/ir/Graph.h create mode 100644 runtime/onert/core/include/ir/Index.h create mode 100644 runtime/onert/core/include/ir/InternalType.h create mode 100644 runtime/onert/core/include/ir/Layout.h create mode 100644 runtime/onert/core/include/ir/LowerInfoMap.h create mode 100644 runtime/onert/core/include/ir/LoweredGraph.h create mode 100644 runtime/onert/core/include/ir/OpCode.h create mode 100644 runtime/onert/core/include/ir/OpSequence.h create mode 100644 runtime/onert/core/include/ir/OpSequences.h create mode 100644 runtime/onert/core/include/ir/Operand.h create mode 100644 runtime/onert/core/include/ir/OperandConstraint.h create mode 100644 runtime/onert/core/include/ir/OperandIndexMap.h create mode 100644 runtime/onert/core/include/ir/OperandIndexSequence.h create mode 100644 runtime/onert/core/include/ir/OperandInfo.h create mode 100644 runtime/onert/core/include/ir/Operands.h create mode 100644 runtime/onert/core/include/ir/Operation.h create mode 100644 runtime/onert/core/include/ir/OperationIndexList.h create mode 100644 runtime/onert/core/include/ir/OperationIndexMap.h create mode 100644 runtime/onert/core/include/ir/OperationVisitor.h create mode 100644 runtime/onert/core/include/ir/Operations.Include.h create mode 100644 runtime/onert/core/include/ir/Operations.h create mode 100644 runtime/onert/core/include/ir/Operations.lst create mode 100644 runtime/onert/core/include/ir/Padding.h create mode 100644 runtime/onert/core/include/ir/Shape.h create mode 100644 runtime/onert/core/include/ir/TypeInfo.h create mode 100644 runtime/onert/core/include/ir/operand/LowerInfo.h create mode 100644 runtime/onert/core/include/ir/operand/PermuteFactor.h create mode 100644 runtime/onert/core/include/ir/operation/Abs.h create mode 100644 runtime/onert/core/include/ir/operation/Add.h create mode 100644 runtime/onert/core/include/ir/operation/ArgMax.h create mode 100644 runtime/onert/core/include/ir/operation/AvgPool2D.h create mode 100644 runtime/onert/core/include/ir/operation/BatchToSpaceND.h create mode 100644 runtime/onert/core/include/ir/operation/Cast.h create mode 100644 runtime/onert/core/include/ir/operation/Comparison.h create mode 100644 runtime/onert/core/include/ir/operation/Concat.h create mode 100644 runtime/onert/core/include/ir/operation/Conv2D.h create mode 100644 runtime/onert/core/include/ir/operation/ConvertFp16ToFp32.h create mode 100644 runtime/onert/core/include/ir/operation/ConvertFp32ToFp16.h create mode 100644 runtime/onert/core/include/ir/operation/Custom.h create mode 100644 runtime/onert/core/include/ir/operation/DepthToSpace.h create mode 100644 runtime/onert/core/include/ir/operation/DepthwiseConv2D.h create mode 100644 runtime/onert/core/include/ir/operation/Dequantize.h create mode 100644 runtime/onert/core/include/ir/operation/Div.h create mode 100644 runtime/onert/core/include/ir/operation/EmbeddingLookup.h create mode 100644 runtime/onert/core/include/ir/operation/Exp.h create mode 100644 runtime/onert/core/include/ir/operation/Floor.h create mode 100644 runtime/onert/core/include/ir/operation/FullyConnected.h create mode 100644 runtime/onert/core/include/ir/operation/Gather.h create mode 100644 runtime/onert/core/include/ir/operation/HashtableLookup.h create mode 100644 runtime/onert/core/include/ir/operation/InstanceNorm.h create mode 100644 runtime/onert/core/include/ir/operation/L2Normalization.h create mode 100644 runtime/onert/core/include/ir/operation/L2Pool2D.h create mode 100644 runtime/onert/core/include/ir/operation/LSTM.h create mode 100644 runtime/onert/core/include/ir/operation/LocalResponseNormalization.h create mode 100644 runtime/onert/core/include/ir/operation/LogicalAnd.h create mode 100644 runtime/onert/core/include/ir/operation/LogicalNot.h create mode 100644 runtime/onert/core/include/ir/operation/LogicalOr.h create mode 100644 runtime/onert/core/include/ir/operation/Logistic.h create mode 100644 runtime/onert/core/include/ir/operation/LowerInfo.h create mode 100644 runtime/onert/core/include/ir/operation/Max.h create mode 100644 runtime/onert/core/include/ir/operation/MaxPool2D.h create mode 100644 runtime/onert/core/include/ir/operation/Mean.h create mode 100644 runtime/onert/core/include/ir/operation/Min.h create mode 100644 runtime/onert/core/include/ir/operation/Mul.h create mode 100644 runtime/onert/core/include/ir/operation/Neg.h create mode 100644 runtime/onert/core/include/ir/operation/OneHot.h create mode 100644 runtime/onert/core/include/ir/operation/PReLU.h create mode 100644 runtime/onert/core/include/ir/operation/Pack.h create mode 100644 runtime/onert/core/include/ir/operation/Pad.h create mode 100644 runtime/onert/core/include/ir/operation/Permute.h create mode 100644 runtime/onert/core/include/ir/operation/RNN.h create mode 100644 runtime/onert/core/include/ir/operation/RSQRT.h create mode 100644 runtime/onert/core/include/ir/operation/ReLU.h create mode 100644 runtime/onert/core/include/ir/operation/ReLU1.h create mode 100644 runtime/onert/core/include/ir/operation/ReLU6.h create mode 100644 runtime/onert/core/include/ir/operation/ReduceMax.h create mode 100644 runtime/onert/core/include/ir/operation/ReduceMin.h create mode 100644 runtime/onert/core/include/ir/operation/ReduceSum.h create mode 100644 runtime/onert/core/include/ir/operation/Reshape.h create mode 100644 runtime/onert/core/include/ir/operation/ResizeBilinear.h create mode 100644 runtime/onert/core/include/ir/operation/SQRT.h create mode 100644 runtime/onert/core/include/ir/operation/Shape.h create mode 100644 runtime/onert/core/include/ir/operation/Sin.h create mode 100644 runtime/onert/core/include/ir/operation/Slice.h create mode 100644 runtime/onert/core/include/ir/operation/Softmax.h create mode 100644 runtime/onert/core/include/ir/operation/SpaceToBatchND.h create mode 100644 runtime/onert/core/include/ir/operation/SpaceToDepth.h create mode 100644 runtime/onert/core/include/ir/operation/Split.h create mode 100644 runtime/onert/core/include/ir/operation/SquaredDifference.h create mode 100644 runtime/onert/core/include/ir/operation/Squeeze.h create mode 100644 runtime/onert/core/include/ir/operation/StridedSlice.h create mode 100644 runtime/onert/core/include/ir/operation/Sub.h create mode 100644 runtime/onert/core/include/ir/operation/Tanh.h create mode 100644 runtime/onert/core/include/ir/operation/TopKV2.h create mode 100644 runtime/onert/core/include/ir/operation/Transpose.h create mode 100644 runtime/onert/core/include/ir/operation/TransposeConv.h create mode 100644 runtime/onert/core/include/ir/operation/Unpack.h create mode 100644 runtime/onert/core/include/util/Config.lst create mode 100644 runtime/onert/core/include/util/ConfigSource.h create mode 100644 runtime/onert/core/include/util/EnvConfigSource.h create mode 100644 runtime/onert/core/include/util/EventCollectorGlobal.h create mode 100644 runtime/onert/core/include/util/GeneralConfigSource.h create mode 100644 runtime/onert/core/include/util/IConfigSource.h create mode 100644 runtime/onert/core/include/util/ITimer.h create mode 100644 runtime/onert/core/include/util/Index.h create mode 100644 runtime/onert/core/include/util/ObjectManager.h create mode 100644 runtime/onert/core/include/util/Set.h create mode 100644 runtime/onert/core/include/util/ShapeInference.h create mode 100644 runtime/onert/core/include/util/Utils.h create mode 100644 runtime/onert/core/include/util/feature/nchw/Reader.h create mode 100644 runtime/onert/core/include/util/feature/nchw/View.h create mode 100644 runtime/onert/core/include/util/feature/nhwc/Reader.h create mode 100644 runtime/onert/core/include/util/feature/nhwc/View.h create mode 100644 runtime/onert/core/include/util/logging.h create mode 100644 runtime/onert/core/src/backend/BackendContext.cc create mode 100644 runtime/onert/core/src/compiler/BackendManager.cc create mode 100644 runtime/onert/core/src/compiler/BackendResolver.cc create mode 100644 runtime/onert/core/src/compiler/CachedDataDeleter.h create mode 100644 runtime/onert/core/src/compiler/Compiler.cc create mode 100644 runtime/onert/core/src/compiler/ExecutorFactory.cc create mode 100644 runtime/onert/core/src/compiler/ExecutorFactory.h create mode 100644 runtime/onert/core/src/compiler/HEScheduler.cc create mode 100644 runtime/onert/core/src/compiler/HEScheduler.h create mode 100644 runtime/onert/core/src/compiler/IScheduler.h create mode 100644 runtime/onert/core/src/compiler/Linear.cc create mode 100644 runtime/onert/core/src/compiler/Linear.h create mode 100644 runtime/onert/core/src/compiler/ManualScheduler.cc create mode 100644 runtime/onert/core/src/compiler/ManualScheduler.h create mode 100644 runtime/onert/core/src/compiler/OperandContext.cc create mode 100644 runtime/onert/core/src/compiler/OperandContext.h create mode 100644 runtime/onert/core/src/compiler/OperationValidator.cc create mode 100644 runtime/onert/core/src/compiler/OperationValidator.h create mode 100644 runtime/onert/core/src/compiler/ParamChecker.cc create mode 100644 runtime/onert/core/src/compiler/ParamChecker.h create mode 100644 runtime/onert/core/src/dumper/dot/DotBuilder.cc create mode 100644 runtime/onert/core/src/dumper/dot/DotBuilder.h create mode 100644 runtime/onert/core/src/dumper/dot/DotDumper.cc create mode 100644 runtime/onert/core/src/dumper/dot/DotDumper.h create mode 100644 runtime/onert/core/src/dumper/dot/DotOpSequenceInfo.cc create mode 100644 runtime/onert/core/src/dumper/dot/DotOpSequenceInfo.h create mode 100644 runtime/onert/core/src/dumper/dot/Node.cc create mode 100644 runtime/onert/core/src/dumper/dot/Node.h create mode 100644 runtime/onert/core/src/dumper/dot/OperandNode.cc create mode 100644 runtime/onert/core/src/dumper/dot/OperandNode.h create mode 100644 runtime/onert/core/src/dumper/dot/OperationNode.cc create mode 100644 runtime/onert/core/src/dumper/dot/OperationNode.h create mode 100644 runtime/onert/core/src/exec/DataflowExecutor.cc create mode 100644 runtime/onert/core/src/exec/DataflowExecutor.h create mode 100644 runtime/onert/core/src/exec/ExecTime.cc create mode 100644 runtime/onert/core/src/exec/Execution.cc create mode 100644 runtime/onert/core/src/exec/ExecutionObservee.cc create mode 100644 runtime/onert/core/src/exec/ExecutionObservee.h create mode 100644 runtime/onert/core/src/exec/ExecutionObservers.cc create mode 100644 runtime/onert/core/src/exec/ExecutorBase.cc create mode 100644 runtime/onert/core/src/exec/ExecutorBase.h create mode 100644 runtime/onert/core/src/exec/FunctionSequence.cc create mode 100644 runtime/onert/core/src/exec/JSONExecTime.cc create mode 100644 runtime/onert/core/src/exec/Job.cc create mode 100644 runtime/onert/core/src/exec/Job.h create mode 100644 runtime/onert/core/src/exec/LinearExecutor.cc create mode 100644 runtime/onert/core/src/exec/LinearExecutor.h create mode 100644 runtime/onert/core/src/exec/ParallelExecutor.cc create mode 100644 runtime/onert/core/src/exec/ParallelExecutor.h create mode 100644 runtime/onert/core/src/exec/ParallelScheduler.cc create mode 100644 runtime/onert/core/src/exec/ParallelScheduler.h create mode 100644 runtime/onert/core/src/exec/Sink.h create mode 100644 runtime/onert/core/src/exec/Source.h create mode 100644 runtime/onert/core/src/exec/ThreadPool.cc create mode 100644 runtime/onert/core/src/exec/ThreadPool.h create mode 100644 runtime/onert/core/src/exec/WorkQueue.cc create mode 100644 runtime/onert/core/src/exec/WorkQueue.h create mode 100644 runtime/onert/core/src/interp/Buffer.h create mode 100644 runtime/onert/core/src/interp/ExecEnv.h create mode 100644 runtime/onert/core/src/interp/InterpExecutor.cc create mode 100644 runtime/onert/core/src/interp/InterpOps.lst create mode 100644 runtime/onert/core/src/interp/Interpreter.cc create mode 100644 runtime/onert/core/src/interp/Interpreter.h create mode 100644 runtime/onert/core/src/interp/Registration.h create mode 100644 runtime/onert/core/src/interp/Tensor.cc create mode 100644 runtime/onert/core/src/interp/Tensor.h create mode 100644 runtime/onert/core/src/interp/operations/AvgPool2D.cc create mode 100644 runtime/onert/core/src/interp/operations/BinaryArithmeticOps.cc create mode 100644 runtime/onert/core/src/interp/operations/Concat.cc create mode 100644 runtime/onert/core/src/interp/operations/Conv2D.cc create mode 100644 runtime/onert/core/src/interp/operations/DepthwiseConv2D.cc create mode 100644 runtime/onert/core/src/interp/operations/FullyConnected.cc create mode 100644 runtime/onert/core/src/interp/operations/Gather.cc create mode 100644 runtime/onert/core/src/interp/operations/InstanceNorm.cc create mode 100644 runtime/onert/core/src/interp/operations/Logistic.cc create mode 100644 runtime/onert/core/src/interp/operations/MaxPool2D.cc create mode 100644 runtime/onert/core/src/interp/operations/OperationUtil.h create mode 100644 runtime/onert/core/src/interp/operations/Pad.cc create mode 100644 runtime/onert/core/src/interp/operations/Reshape.cc create mode 100644 runtime/onert/core/src/interp/operations/Softmax.cc create mode 100644 runtime/onert/core/src/interp/operations/TransposeConv.cc create mode 100644 runtime/onert/core/src/interp/operations/UnaryActivations.cc create mode 100644 runtime/onert/core/src/ir/Coordinates.cc create mode 100644 runtime/onert/core/src/ir/Graph.cc create mode 100644 runtime/onert/core/src/ir/GraphIterator.cc create mode 100644 runtime/onert/core/src/ir/GraphIterator.h create mode 100644 runtime/onert/core/src/ir/LayoutSet.cc create mode 100644 runtime/onert/core/src/ir/LayoutSet.h create mode 100644 runtime/onert/core/src/ir/LoweredGraph.cc create mode 100644 runtime/onert/core/src/ir/OpCode.cc create mode 100644 runtime/onert/core/src/ir/OpSequence.cc create mode 100644 runtime/onert/core/src/ir/OpSequences.cc create mode 100644 runtime/onert/core/src/ir/Operand.cc create mode 100644 runtime/onert/core/src/ir/OperandIndexSequence.cc create mode 100644 runtime/onert/core/src/ir/Operands.cc create mode 100644 runtime/onert/core/src/ir/Operation.cc create mode 100644 runtime/onert/core/src/ir/OperationCloner.cc create mode 100644 runtime/onert/core/src/ir/OperationCloner.h create mode 100644 runtime/onert/core/src/ir/OperationDumper.cc create mode 100644 runtime/onert/core/src/ir/OperationDumper.h create mode 100644 runtime/onert/core/src/ir/OperationIndexList.cc create mode 100644 runtime/onert/core/src/ir/Operations.cc create mode 100644 runtime/onert/core/src/ir/Padding.cc create mode 100644 runtime/onert/core/src/ir/Shape.cc create mode 100644 runtime/onert/core/src/ir/TypeInfo.cc create mode 100644 runtime/onert/core/src/ir/operation/Abs.cc create mode 100644 runtime/onert/core/src/ir/operation/Add.cc create mode 100644 runtime/onert/core/src/ir/operation/ArgMax.cc create mode 100644 runtime/onert/core/src/ir/operation/AvgPool2D.cc create mode 100644 runtime/onert/core/src/ir/operation/BatchToSpaceND.cc create mode 100644 runtime/onert/core/src/ir/operation/Cast.cc create mode 100644 runtime/onert/core/src/ir/operation/Comparison.cc create mode 100644 runtime/onert/core/src/ir/operation/Concat.cc create mode 100644 runtime/onert/core/src/ir/operation/Conv2D.cc create mode 100644 runtime/onert/core/src/ir/operation/ConvertFp16ToFp32.cc create mode 100644 runtime/onert/core/src/ir/operation/ConvertFp32ToFp16.cc create mode 100644 runtime/onert/core/src/ir/operation/Custom.cc create mode 100644 runtime/onert/core/src/ir/operation/DepthToSpace.cc create mode 100644 runtime/onert/core/src/ir/operation/DepthwiseConv2D.cc create mode 100644 runtime/onert/core/src/ir/operation/Dequantize.cc create mode 100644 runtime/onert/core/src/ir/operation/Div.cc create mode 100644 runtime/onert/core/src/ir/operation/EmbeddingLookup.cc create mode 100644 runtime/onert/core/src/ir/operation/Exp.cc create mode 100644 runtime/onert/core/src/ir/operation/Floor.cc create mode 100644 runtime/onert/core/src/ir/operation/FullyConnected.cc create mode 100644 runtime/onert/core/src/ir/operation/Gather.cc create mode 100644 runtime/onert/core/src/ir/operation/HashtableLookup.cc create mode 100644 runtime/onert/core/src/ir/operation/InstanceNorm.cc create mode 100644 runtime/onert/core/src/ir/operation/L2Normalization.cc create mode 100644 runtime/onert/core/src/ir/operation/L2Pool2D.cc create mode 100644 runtime/onert/core/src/ir/operation/LSTM.cc create mode 100644 runtime/onert/core/src/ir/operation/LocalResponseNormalization.cc create mode 100644 runtime/onert/core/src/ir/operation/LogicalAnd.cc create mode 100644 runtime/onert/core/src/ir/operation/LogicalNot.cc create mode 100644 runtime/onert/core/src/ir/operation/LogicalOr.cc create mode 100644 runtime/onert/core/src/ir/operation/Logistic.cc create mode 100644 runtime/onert/core/src/ir/operation/LowerInfo.cc create mode 100644 runtime/onert/core/src/ir/operation/Max.cc create mode 100644 runtime/onert/core/src/ir/operation/MaxPool2D.cc create mode 100644 runtime/onert/core/src/ir/operation/Mean.cc create mode 100644 runtime/onert/core/src/ir/operation/Min.cc create mode 100644 runtime/onert/core/src/ir/operation/Mul.cc create mode 100644 runtime/onert/core/src/ir/operation/Neg.cc create mode 100644 runtime/onert/core/src/ir/operation/OneHot.cc create mode 100644 runtime/onert/core/src/ir/operation/PReLU.cc create mode 100644 runtime/onert/core/src/ir/operation/Pack.cc create mode 100644 runtime/onert/core/src/ir/operation/Pad.cc create mode 100644 runtime/onert/core/src/ir/operation/Permute.cc create mode 100644 runtime/onert/core/src/ir/operation/RNN.cc create mode 100644 runtime/onert/core/src/ir/operation/RSQRT.cc create mode 100644 runtime/onert/core/src/ir/operation/ReLU.cc create mode 100644 runtime/onert/core/src/ir/operation/ReLU1.cc create mode 100644 runtime/onert/core/src/ir/operation/ReLU6.cc create mode 100644 runtime/onert/core/src/ir/operation/ReduceMax.cc create mode 100644 runtime/onert/core/src/ir/operation/ReduceMin.cc create mode 100644 runtime/onert/core/src/ir/operation/ReduceSum.cc create mode 100644 runtime/onert/core/src/ir/operation/Reshape.cc create mode 100644 runtime/onert/core/src/ir/operation/ResizeBilinear.cc create mode 100644 runtime/onert/core/src/ir/operation/SQRT.cc create mode 100644 runtime/onert/core/src/ir/operation/Shape.cc create mode 100644 runtime/onert/core/src/ir/operation/Sin.cc create mode 100644 runtime/onert/core/src/ir/operation/Slice.cc create mode 100644 runtime/onert/core/src/ir/operation/Softmax.cc create mode 100644 runtime/onert/core/src/ir/operation/SpaceToBatchND.cc create mode 100644 runtime/onert/core/src/ir/operation/SpaceToDepth.cc create mode 100644 runtime/onert/core/src/ir/operation/Split.cc create mode 100644 runtime/onert/core/src/ir/operation/SquaredDifference.cc create mode 100644 runtime/onert/core/src/ir/operation/Squeeze.cc create mode 100644 runtime/onert/core/src/ir/operation/StridedSlice.cc create mode 100644 runtime/onert/core/src/ir/operation/Sub.cc create mode 100644 runtime/onert/core/src/ir/operation/Tanh.cc create mode 100644 runtime/onert/core/src/ir/operation/TopKV2.cc create mode 100644 runtime/onert/core/src/ir/operation/Transpose.cc create mode 100644 runtime/onert/core/src/ir/operation/TransposeConv.cc create mode 100644 runtime/onert/core/src/ir/operation/Unpack.cc create mode 100644 runtime/onert/core/src/ir/pass/ConstantInsertionPass.cc create mode 100644 runtime/onert/core/src/ir/pass/ConstantInsertionPass.h create mode 100644 runtime/onert/core/src/ir/pass/LoweredOperandPass.h create mode 100644 runtime/onert/core/src/ir/pass/LoweredOperationPass.h create mode 100644 runtime/onert/core/src/ir/pass/OperandPass.cc create mode 100644 runtime/onert/core/src/ir/pass/OperandPass.h create mode 100644 runtime/onert/core/src/ir/pass/OperationPass.cc create mode 100644 runtime/onert/core/src/ir/pass/OperationPass.h create mode 100644 runtime/onert/core/src/ir/pass/Pass.h create mode 100644 runtime/onert/core/src/ir/pass/PermutationEliminationPass.cc create mode 100644 runtime/onert/core/src/ir/pass/PermutationEliminationPass.h create mode 100644 runtime/onert/core/src/ir/pass/PermutationInsertionPass.cc create mode 100644 runtime/onert/core/src/ir/pass/PermutationInsertionPass.h create mode 100644 runtime/onert/core/src/ir/pass/PermutationOperationPass.cc create mode 100644 runtime/onert/core/src/ir/pass/PermutationOperationPass.h create mode 100644 runtime/onert/core/src/ir/verifier/Verifier.cc create mode 100644 runtime/onert/core/src/ir/verifier/Verifier.h create mode 100644 runtime/onert/core/src/library_info.cc create mode 100644 runtime/onert/core/src/util/ConfigSource.cc create mode 100644 runtime/onert/core/src/util/EnvConfigSource.cc create mode 100644 runtime/onert/core/src/util/EventCollectorGlobal.cc create mode 100644 runtime/onert/core/src/util/GeneralConfigSource.cc create mode 100644 runtime/onert/core/src/util/ShapeInference.cc create mode 100644 runtime/onert/core/src/util/logging.cc create mode 100644 runtime/onert/frontend/CMakeLists.txt create mode 100644 runtime/onert/frontend/base_loader/CMakeLists.txt create mode 100644 runtime/onert/frontend/base_loader/include/base_loader.h create mode 100644 runtime/onert/frontend/circle/CMakeLists.txt create mode 100644 runtime/onert/frontend/circle/include/circle_loader.h create mode 100644 runtime/onert/frontend/circle/src/circle_loader.cc create mode 100644 runtime/onert/frontend/circle/src/circle_schema_generated.h create mode 100644 runtime/onert/frontend/nnapi/ANeuralNetworksModel.test.cc create mode 100644 runtime/onert/frontend/nnapi/CMakeLists.txt create mode 100644 runtime/onert/frontend/nnapi/compilation.cc create mode 100644 runtime/onert/frontend/nnapi/event.cc create mode 100644 runtime/onert/frontend/nnapi/execution.cc create mode 100644 runtime/onert/frontend/nnapi/memory.cc create mode 100644 runtime/onert/frontend/nnapi/model.cc create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.h create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.cc create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.h create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc create mode 100644 runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h create mode 100644 runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc create mode 100644 runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.h create mode 100644 runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc create mode 100644 runtime/onert/frontend/nnapi/wrapper/OperationFactory.h create mode 100644 runtime/onert/frontend/tflite/CMakeLists.txt create mode 100644 runtime/onert/frontend/tflite/include/tflite_loader.h create mode 100644 runtime/onert/frontend/tflite/src/tflite_loader.cc create mode 100644 runtime/onert/frontend/tflite/src/tflite_schema_generated.h create mode 100644 runtime/onert/frontend/tflite/tflite_schema-1.13.1.fbs create mode 100644 runtime/onert/frontend/tflite/tflite_schema.fbs create mode 100644 runtime/onert/sample/CMakeLists.txt create mode 100644 runtime/onert/sample/minimal/CMakeLists.txt create mode 100644 runtime/onert/sample/minimal/README.md create mode 100644 runtime/onert/sample/minimal/src/minimal.cc create mode 100644 runtime/onert/test/CMakeLists.txt create mode 100644 runtime/onert/test/core/compiler/Scheduler.cc create mode 100644 runtime/onert/test/core/exec/ExecInstance.cc create mode 100644 runtime/onert/test/core/exec/ExecTime.test.cc create mode 100644 runtime/onert/test/core/interp/ExecManager.cc create mode 100644 runtime/onert/test/graph/Graph.cc create mode 100644 runtime/onert/test/graph/Index.cc create mode 100644 runtime/onert/test/graph/MockNode.h create mode 100644 runtime/onert/test/graph/operand/IndexSet.cc create mode 100644 runtime/onert/test/graph/operand/LayoutSet.cc create mode 100644 runtime/onert/test/graph/operand/Set.cc create mode 100644 runtime/onert/test/graph/operand/UseDef.cc create mode 100644 runtime/onert/test/graph/operation/Set.cc create mode 100644 runtime/onert/test/graph/operation/SetIO.cc create mode 100644 runtime/onert/test/graph/verifier/Verifier.cc create mode 100644 runtime/onert/test/util/ObjectManager.cc create mode 100644 runtime/onert/test/util/ShapeInference.cc (limited to 'runtime/onert') diff --git a/runtime/onert/CMakeLists.txt b/runtime/onert/CMakeLists.txt new file mode 100644 index 000000000..88d52a5bd --- /dev/null +++ b/runtime/onert/CMakeLists.txt @@ -0,0 +1,15 @@ +if(NOT BUILD_ONERT) + return() +endif(NOT BUILD_ONERT) + +add_subdirectory(backend) +add_subdirectory(frontend) +add_subdirectory(core) +add_subdirectory(api) +add_subdirectory(sample) + +if(NOT ENABLE_TEST) + return() +endif(NOT ENABLE_TEST) + +add_subdirectory(test) diff --git a/runtime/onert/api/CMakeLists.txt b/runtime/onert/api/CMakeLists.txt new file mode 100644 index 000000000..3132646c4 --- /dev/null +++ b/runtime/onert/api/CMakeLists.txt @@ -0,0 +1,21 @@ +file(GLOB_RECURSE API_SRC "*.cc") + +set(ONERT_DEV nnfw-dev) +add_library(${ONERT_DEV} SHARED ${API_SRC}) + +# Public headers to publish +# nnfw_debug.h is header for runtime developer, so it will not be installed +# But runtime developer can use nnfw_debug.h by linking nnfw-dev +set(NNFW_API_HEADERS include/nnfw.h include/nnfw_dev.h) + +target_link_libraries(${ONERT_DEV} PUBLIC nnfw-nnapi-header) +target_link_libraries(${ONERT_DEV} PRIVATE onert_core) +target_link_libraries(${ONERT_DEV} PRIVATE jsoncpp tflite_loader circle_loader ${LIB_PTHREAD}) +target_link_libraries(${ONERT_DEV} PRIVATE nnfw_common) +target_link_libraries(${ONERT_DEV} PRIVATE nnfw_coverage) +target_include_directories(${ONERT_DEV} PUBLIC include) +set_target_properties(${ONERT_DEV} PROPERTIES PUBLIC_HEADER "${NNFW_API_HEADERS}") + +install(TARGETS ${ONERT_DEV} + LIBRARY DESTINATION lib + PUBLIC_HEADER DESTINATION include/nnfw) diff --git a/runtime/onert/api/include/nnfw.h b/runtime/onert/api/include/nnfw.h new file mode 100644 index 000000000..7d9fc048f --- /dev/null +++ b/runtime/onert/api/include/nnfw.h @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file nnfw.h + * @brief This file describes runtime API + */ +#ifndef __NNFW_H__ +#define __NNFW_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Session to query with runtime + * + *

nnfw_session is started and passed by calling {@link nnfw_create_session}. + * Each session has its own inference environment, such as model to inference, backend usage, etc. + * + *

Load model by calling {@link nnfw_load_model_from_file} + * + *

After loading, prepare inference by calling {@link nnfw_prepare}. + * Application can set runtime environment before prepare by calling + * {@link nnfw_set_available_backends} and {@link nnfw_set_op_backend}, and it is optional. + * + *

Application can inference by calling {@link nnfw_run}. + * Before inference, application has responsibility to set input tensor to set input data by calling + * {@link nnfw_set_output}, and output tensor to get output by calling {@link nnfw_set_input} + * + *

To support input and output setting, application can get + * input and output tensor information by calling

    + *
  • {@link nnfw_input_size}
  • + *
  • {@link nnfw_output_size}
  • + *
  • {@link nnfw_input_tensorinfo}
  • + *
  • {@link nnfw_output_tensorinfo}
  • + *
+ * + *

Application can inference many times using one session, + * but next inference can do after prior inference end + * + *

Application cannot use muitiple model using one session + */ +typedef struct nnfw_session nnfw_session; + +/** + * @brief Tensor types + * + * The type of tensor represented in {@link nnfw_tensorinfo} + */ +typedef enum { + /** A tensor of 32 bit floating point */ + NNFW_TYPE_TENSOR_FLOAT32 = 0, + /** A tensor of 32 bit signed integer */ + NNFW_TYPE_TENSOR_INT32 = 1, + /** + * A tensor of 8 bit integers that represent real numbers. + * + * real_value = (integer_value - zeroPoint) * scale. + */ + NNFW_TYPE_TENSOR_QUANT8_ASYMM = 2, + /** A tensor of boolean */ + NNFW_TYPE_TENSOR_BOOL = 3, + /** A tensor of 8 bit unsigned integer */ + NNFW_TYPE_TENSOR_UINT8 = 4, +} NNFW_TYPE; + +/** + * @brief Result Values + */ +typedef enum { + /** Successful */ + NNFW_STATUS_NO_ERROR = 0, + /** Failed */ + NNFW_STATUS_ERROR = 1, +} NNFW_STATUS; + +/** + * @brief Data format of a tensor + */ +typedef enum { + /** Don't care layout */ + NNFW_LAYOUT_NONE = 0, + /** + * Channel last layout + * If rank is 4, layout is NHWC + */ + NNFW_LAYOUT_CHANNELS_LAST = 1, + /** + * Channel first layout + * If rank is 4, layout is NCHW + */ + NNFW_LAYOUT_CHANNELS_FIRST = 2, +} NNFW_LAYOUT; + +/** + * @brief Information ID for retrieving information on nnfw (e.g. version) + */ +typedef enum { + /** nnfw runtime version + * Its value is uint32 in 0xMMmmmmPP, where MM = major, mmmm = minor, PP = patch. + */ + NNFW_INFO_ID_VERSION = 0, +} NNFW_INFO_ID; + +/** + * @brief Maximum rank expressible with nnfw + */ +#define NNFW_MAX_RANK (6) + +/** + * @brief tensor info describes the type and shape of tensors + * + *

This structure is used to describe input and output tensors. + * Application can get input and output tensor type and shape described in model by using + * {@link nnfw_input_tensorinfo} and {@link nnfw_output_tensorinfo} + * + *

Maximum rank is 6 (NNFW_MAX_RANK). And tensor's dimension value is filled in 'dims' field from + * index 0. + * For example, if tensor's rank is 4, + * application can get dimension value from dims[0], dims[1], dims[2], and dims[3] + */ +typedef struct nnfw_tensorinfo +{ + /** The data type */ + NNFW_TYPE dtype; + /** The number of dimensions (rank) */ + int32_t rank; + /** + * The dimension of tensor. + * Maximum rank is 6 (NNFW_MAX_RANK). + */ + int32_t dims[NNFW_MAX_RANK]; +} nnfw_tensorinfo; + +/** + * @brief Create a new session instance. + * + *

This only creates a session. + * Model is loaded after {@link nnfw_load_model_from_file} is invoked. + * And inference is performed after {@link nnfw_run} is invoked. + * + *

{@link nnfw_close_session} should be called once + * if session is no longer need + * + * @param[out] session The session to be created + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_create_session(nnfw_session **session); + +/** + * @brief Close a session instance + * + * After called, access to closed session by application will be invalid + * + * @param[in] session The session to be closed + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_close_session(nnfw_session *session); + +/** + * @brief Load model from nnpackage file or directory + * + * @param[in] session nnfw_session loading the given nnpackage file/dir + * @param[in] package_file_path Path to the nnpackage file or unzipped directory to be loaded + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_load_model_from_file(nnfw_session *session, const char *package_file_path); + +/** + * @brief Apply i-th input's tensor info to resize input tensor + * + * This function should be called before {@link nnfw_prepare} is invoked, and + * should be called after {@link nnfw_load_model_from_file} is invoked + * See {@link nnfw_prepare} for information applying updated tensor info + * If this function is called many times for same index, tensor info is overwritten + * + * @param[in] session Session to the input tensor info is to be set + * @param[in] index Index of input to be applied (0-indexed) + * @param[in] tensor_info Tensor info to be applied + * @return @c NNFW_STATUS_NO_ERROR if successful, otherwise return @c NNFW_STATUS_ERROR + */ +NNFW_STATUS nnfw_apply_tensorinfo(nnfw_session *session, uint32_t index, + nnfw_tensorinfo tensor_info); + +/** + * @brief Prepare session to be ready for inference + * + * This phase may finalize model compilation, scheduling, and additional settings. + * If {@link nnfw_apply_tensor} is called to apply input tensor info different with model + * before this function, tries to resize all tensors. + * + * @param[in] session the session to be prepared + * @return @c NNFW_STATUS_NO_ERROR if successful, otherwise return @c NNFW_STATUS_ERROR + */ +NNFW_STATUS nnfw_prepare(nnfw_session *session); + +/** + * @brief Run inference + * + *

This function should be called after model is loaded by {@link nnfw_load_model_from_file}, + * session is prepared for inference by {@link nnfw_prepare}, set input and output buffers + * by {@link nnfw_set_input} and {@link nnfw_set_output}.

+ * + *

This function return after inference is finished.

+ * + * @param[in] session The session to run inference + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_run(nnfw_session *session); + +/** + * @brief Set input buffer + * + * This function should be called after {@link nnfw_prepare}, and before first inference + * on session by {@link nnfw_run}. Application can reuse buffer for many inferences. + * + * @param[in] session Session to the input is to be set + * @param[in] index Index of input to be set (0-indexed) + * @param[in] type Type of the input + * @param[in] buffer Raw buffer for input + * @param[in] length Size of bytes of input buffer + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_input(nnfw_session *session, uint32_t index, NNFW_TYPE type, + const void *buffer, size_t length); + +/** + * @brief Set output buffer + * + * This function should be called after {@link nnfw_prepare}, and before first inference + * on session by {@link nnfw_run}. Application can reuse buffer for many inferences. + * + * @param[in] session Session from inference output is to be extracted + * @param[in] index Index of output to be set (0-indexed) + * @param[in] type Type of the output + * @param[out] buffer Raw buffer for output + * @param[in] length Size of bytes of output buffer + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_output(nnfw_session *session, uint32_t index, NNFW_TYPE type, void *buffer, + size_t length); + +/** + * @brief Get the number of inputs + * + * Application can call this function to get number of inputs defined in loaded model. + * This function should be called after {@link nnfw_load_model_from_file} is invoked to load model + * + * @param[in] session Session from input information is to be extracted + * @param[out] number Variable which the number of inputs is put into + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_input_size(nnfw_session *session, uint32_t *number); + +/** + * @brief Get the number of outputs + * + * Application can call this function to get number of outputs defined in loaded model. + * This function should be called after {@link nnfw_load_model_from_file} is invoked to load model + * + * @param[in] session Session from output information is to be extracted + * @param[out] number Variable which the number of outputs is put into + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_output_size(nnfw_session *session, uint32_t *number); + +/** + * @brief Set the layout of an input + * + * The input that does not call this has NNFW_LAYOUT_NHWC layout + * + * @param[in] session session from inference input is to be extracted + * @param[in] index index of input to be set (0-indexed) + * @param[in] layout layout to set to target input + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_input_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout); + +/** + * @brief Set the layout of an output + * + * The output that does not call this has NNFW_LAYOUT_NHWC layout + * + * @param[in] session session from inference output is to be extracted + * @param[in] index index of output to be set (0-indexed) + * @param[in] layout layout to set to target output + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_output_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout); + +/** + * @brief Get i-th input tensor info + * + *

Before {@link nnfw_prepare} is invoked, this function return tensor info in model, + * so updated tensor info by {@link nnfw_apply_tensorinfo} is not returned.

+ * + *

After {@link nnfw_prepare} is invoked, this function return updated tensor info + * if tensor info is updated by {@link nnfw_apply_tensorinfo}.

+ * + * @param[in] session Session from input information is to be extracted + * @param[in] index Index of input + * @param[out] tensor_info Tensor info (shape, type, etc) + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_input_tensorinfo(nnfw_session *session, uint32_t index, + nnfw_tensorinfo *tensor_info); + +/** + * @brief Get i-th output tensor info + * + *

Before {@link nnfw_prepare} is invoked, this function return tensor info in model, + * so updated tensor info by {@link nnfw_apply_tensorinfo} is not returned.

+ * + *

After {@link nnfw_prepare} is invoked, this function return updated tensor info + * if tensor info is updated by {@link nnfw_apply_tensorinfo}.

+ * + * @param[in] session Session from output information is to be extracted + * @param[in] index Index of output + * @param[out] tensor_info Tensor info (shape, type, etc) + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_output_tensorinfo(nnfw_session *session, uint32_t index, + nnfw_tensorinfo *tensor_info); + +/** + * @brief Set available backends + * + * This function should be called before {@link nnfw_prepare} is invoked. + * + *

Supported backends differs on each platforms. + * For example, `x86_64` supports "cpu" only. + * Can set multiple backends by semicolon (ex: "acl_cl;cpu"). + * Among the multiple backends, the 1st element is used as default backend.

+ * + * @note Possible backend strings are: "cpu", "acl_cl", "acl_neon", "srcn" + * + * @param[in] session session to which avilable backends are set + * @param[in] backends available backends on which nnfw uses + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_available_backends(nnfw_session *session, const char *backends); + +/** + * @brief Set the operation's backend + * + * This function should be called before {@link nnfw_prepare} is invoked. + * + *

Supported backends differs on each platforms. + * For example, `x86_64` supports "cpu" only. + * The backend for op has higher priority than available backends specified by + * nnfw_set_available_backends.

+ * + * @note Possible backend strings are: "cpu", "acl_cl", "acl_neon" + * + * @param[in] session session to be modified + * @param[in] op operation to be set + * @param[in] backend bakcend on which operation run + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_op_backend(nnfw_session *session, const char *op, const char *backend); + +/** + * @brief Retrieve uint32 type of nnfw information for given information ID. + * + *

Retrieves the information of property given by information id

+ * + * @note: The input session could be null for global information (e.g. runtime version).* + * + * @param[in] session session to be queried on. + * @param[in] information ID to be queried + * @param[out] val uint32 value to be returned. + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_query_info_u32(nnfw_session *session, NNFW_INFO_ID id, uint32_t *val); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/runtime/onert/api/include/nnfw_debug.h b/runtime/onert/api/include/nnfw_debug.h new file mode 100644 index 000000000..fe335ec4e --- /dev/null +++ b/runtime/onert/api/include/nnfw_debug.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NNFW_DEBUG_H__ +#define __NNFW_DEBUG_H__ + +#include "nnfw.h" + +NNFW_STATUS nnfw_create_debug_session(nnfw_session **session); + +NNFW_STATUS nnfw_set_config(nnfw_session *session, const char *key, const char *value); + +#endif // __NNFW_DEBUG_H__ diff --git a/runtime/onert/api/include/nnfw_dev.h b/runtime/onert/api/include/nnfw_dev.h new file mode 100644 index 000000000..ecf0597cf --- /dev/null +++ b/runtime/onert/api/include/nnfw_dev.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NNFW_DEV_H__ +#define __NNFW_DEV_H__ + +#include "nnfw.h" + +// Used for custom kernel development + +/* + * operand type, used only for custom operations + */ +typedef struct +{ + nnfw_tensorinfo type; + void *allocation; +} nnfw_operand; + +/* + * Used as input to custom operation eval function + */ +typedef struct +{ + size_t ninputs; + nnfw_operand *inputs; + + size_t noutputs; + nnfw_operand *outputs; +} nnfw_custom_kernel_params; + +/* + * Custom kernel evaluation function + * + * param[in] params custom operation parameters + * param[in] userdata pointer to user-specified buffer( kernel instance specific ) + */ +typedef void (*nnfw_custom_eval)(nnfw_custom_kernel_params *params, char *userdata, + size_t userdata_size); + +/* + * custom operation registration info + */ +typedef struct +{ + nnfw_custom_eval eval_function; +} custom_kernel_registration_info; + +NNFW_STATUS nnfw_register_custom_op_info(nnfw_session *session, const char *id, + custom_kernel_registration_info *info); + +#endif // __NNFW_DEV_H__ diff --git a/runtime/onert/api/include/nnfw_version.h b/runtime/onert/api/include/nnfw_version.h new file mode 100644 index 000000000..25be998a2 --- /dev/null +++ b/runtime/onert/api/include/nnfw_version.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NNFW_VERSION_H__ +#define __NNFW_VERSION_H__ + +/** + * NNFW_VERSION is a uint32 value representing nnfw runtime version + * in 0xMMmmmmPP, where MM = major, mmmm = minor, PP = patch + */ +#define NNFW_VERSION 0x01000300 + +#endif // __NNFW_VERSION_H__ diff --git a/runtime/onert/api/src/CustomKernel.cc b/runtime/onert/api/src/CustomKernel.cc new file mode 100644 index 000000000..a383dfe9c --- /dev/null +++ b/runtime/onert/api/src/CustomKernel.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CustomKernel.h" + +namespace onert +{ +namespace frontend +{ +namespace custom +{ + +using namespace backend::custom; + +class APIConverter +{ +public: + static nnfw_operand convertOperand(void *alloc, const TypeInfo &type) + { + nnfw_operand api_operand; + api_operand.allocation = alloc; + api_operand.type = convertType(type); + return api_operand; + } + + static nnfw_tensorinfo convertType(const TypeInfo &type) + { + nnfw_tensorinfo api_type; + api_type.rank = type.shape.rank(); + assert(type.shape.rank() <= 6); + std::copy(type.shape.dims().begin(), type.shape.dims().end(), std::begin(api_type.dims)); + + switch (type.dtype) + { + case ir::DataType::FLOAT32: + api_type.dtype = NNFW_TYPE_TENSOR_FLOAT32; + break; + case ir::DataType::INT32: + api_type.dtype = NNFW_TYPE_TENSOR_INT32; + break; + case ir::DataType::QUANT8_ASYMM: + api_type.dtype = NNFW_TYPE_TENSOR_QUANT8_ASYMM; + break; + case ir::DataType::BOOL8: + api_type.dtype = NNFW_TYPE_TENSOR_BOOL; + break; + default: + throw std::runtime_error("Unsupported tensor datatype"); + } + return api_type; + } +}; + +Kernel::Kernel(const nnfw_custom_eval evalFunction) + : _params(), _userdata(nullptr), _userdata_size(0), _evalFunction(evalFunction) +{ +} + +void Kernel::configure(CustomKernelConfigParams &&inParams) +{ + _userdata = inParams.userdata; + _userdata_size = inParams.userdata_size; + + _params.ninputs = inParams.input_allocations.size(); + _params.inputs = new nnfw_operand[_params.ninputs]; + for (size_t i = 0; i < _params.ninputs; ++i) + { + _params.inputs[i] = + APIConverter::convertOperand(inParams.input_allocations[i], inParams.input_types[i]); + } + + _params.noutputs = inParams.output_allocations.size(); + _params.outputs = new nnfw_operand[_params.noutputs]; + for (size_t i = 0; i < _params.noutputs; ++i) + { + _params.outputs[i] = + APIConverter::convertOperand(inParams.output_allocations[i], inParams.output_types[i]); + } +} + +void Kernel::run() { _evalFunction(&_params, _userdata, _userdata_size); } + +} // namespace custom +} // namespace frontend +} // namespace onert diff --git a/runtime/onert/api/src/CustomKernel.h b/runtime/onert/api/src/CustomKernel.h new file mode 100644 index 000000000..2acf5979e --- /dev/null +++ b/runtime/onert/api/src/CustomKernel.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CUSTOM_KERNEL_H__ +#define __ONERT_BACKEND_CUSTOM_KERNEL_H__ + +#include "nnfw_dev.h" + +#include "backend/CustomKernelBuilder.h" +#include "exec/IFunction.h" + +#include + +namespace onert +{ +namespace frontend +{ +namespace custom +{ + +class Kernel : public ::onert::exec::IFunction +{ +public: + explicit Kernel(nnfw_custom_eval evalFunction); + + nnfw_custom_kernel_params _params; + char *_userdata; + size_t _userdata_size; + + nnfw_custom_eval _evalFunction; + // nnfw_custom_type_infer _type_infer_function; //Unused for now + + /** + * Fills _params field used later by user specified eval function + * @param inParams custom kernel parameters + */ + virtual void configure(backend::custom::CustomKernelConfigParams &&inParams); + + void run() override; + void runSync() override { run(); } +}; + +} // namespace custom +} // namespace frontend +} // namespace onert + +#endif // __ONERT_BACKEND_CUSTOM_KERNEL_H__ diff --git a/runtime/onert/api/src/CustomKernelRegistry.cc b/runtime/onert/api/src/CustomKernelRegistry.cc new file mode 100644 index 000000000..7812609d1 --- /dev/null +++ b/runtime/onert/api/src/CustomKernelRegistry.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CustomKernelRegistry.h" + +#include + +namespace onert +{ +namespace frontend +{ +namespace custom +{ + +void KernelRegistry::registerKernel(const std::string &id, nnfw_custom_eval evalFunction) +{ + _storage.emplace(id, evalFunction); +} + +std::shared_ptr KernelRegistry::getBuilder() +{ + return std::make_unique(this); +} + +std::unique_ptr KernelRegistry::buildKernelForOp(const std::string &id) +{ + auto it = _storage.find(id); + if (it == _storage.end()) + { + throw std::runtime_error("Unable to find associated kernel for op"); + } + + return std::make_unique(it->second); +} + +// Kernel builder +std::unique_ptr +KernelBuilder::buildKernel(const std::string &id, + backend::custom::CustomKernelConfigParams &¶ms) const +{ + auto kernel = _registry->buildKernelForOp(id); + kernel->configure(std::move(params)); + + return kernel; +} + +KernelBuilder::KernelBuilder(KernelRegistry *registry) : _registry(registry) {} + +} // namespace custom +} // namespace frontend +} // namespace onert diff --git a/runtime/onert/api/src/CustomKernelRegistry.h b/runtime/onert/api/src/CustomKernelRegistry.h new file mode 100644 index 000000000..fe60d5bcc --- /dev/null +++ b/runtime/onert/api/src/CustomKernelRegistry.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CUSTOM_KERNEL_REGISTRY_H__ +#define __ONERT_BACKEND_CUSTOM_KERNEL_REGISTRY_H__ + +#include "CustomKernel.h" + +#include +#include +#include + +#include + +namespace onert +{ +namespace frontend +{ +namespace custom +{ + +class KernelRegistry +{ +public: + void registerKernel(const std::string &id, nnfw_custom_eval evalFunction); + + std::shared_ptr getBuilder(); + std::unique_ptr buildKernelForOp(const std::string &id); + +private: + std::unordered_map _storage; +}; + +class KernelBuilder : public backend::custom::IKernelBuilder +{ +public: + KernelBuilder(KernelRegistry *registry); + + std::unique_ptr + buildKernel(const std::string &id, + backend::custom::CustomKernelConfigParams &¶ms) const override; + +private: + KernelRegistry *_registry; +}; + +} // namespace custom +} // namespace frontend +} // namespace onert + +#endif // __ONERT_BACKEND_CUSTOM_KERNEL_REGISTRY_H__ diff --git a/runtime/onert/api/src/OpMap.lst b/runtime/onert/api/src/OpMap.lst new file mode 100644 index 000000000..a3d1b25ea --- /dev/null +++ b/runtime/onert/api/src/OpMap.lst @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MAP_MACRO +#error Define MAP_MACRO before including this file +#endif + +// circle operation | onert internal operation +MAP_MACRO(ADD , Add) +MAP_MACRO(SUB , Sub) +MAP_MACRO(BATCH_TO_SPACE_ND , BatchToSpaceND) +MAP_MACRO(CAST , Cast) +MAP_MACRO(CONV_2D , Conv2D) +MAP_MACRO(DEPTHWISE_CONV_2D , DepthwiseConv2D) +MAP_MACRO(AVERAGE_POOL_2D , AvgPool2D) +MAP_MACRO(MAX_POOL_2D , MaxPool2D) +MAP_MACRO(CONCATENATION , Concat) +MAP_MACRO(FULLY_CONNECTED , FullyConnected) +MAP_MACRO(SUM , ReduceSum) +MAP_MACRO(RESHAPE , Reshape) +MAP_MACRO(MUL , Mul) +MAP_MACRO(SOFTMAX , Softmax) +MAP_MACRO(SQUEEZE , Squeeze) +MAP_MACRO(SLICE , Slice) +MAP_MACRO(STRIDED_SLICE , StridedSlice) +MAP_MACRO(TANH , Tanh) +MAP_MACRO(LOGISTIC , Logistic) +MAP_MACRO(DIV , Div) +MAP_MACRO(TRANSPOSE , Transpose) +MAP_MACRO(EXP , Exp) +MAP_MACRO(REDUCE_MAX , ReduceMax) +// UNMATCHED +//MAP_MACRO(Comparison) +MAP_MACRO(LOGICAL_AND , LogicalAnd) +MAP_MACRO(LOGICAL_OR , LogicalOr) +MAP_MACRO(LOGICAL_NOT , LogicalNot) +MAP_MACRO(LSTM , LSTM) +MAP_MACRO(RSQRT , RSQRT) +MAP_MACRO(RELU , ReLU) +MAP_MACRO(RESIZE_BILINEAR , ResizeBilinear) +MAP_MACRO(RELU_N1_TO_1 , ReLU1) +MAP_MACRO(RELU6 , ReLU6) +MAP_MACRO(RNN , RNN) +MAP_MACRO(FLOOR , Floor) +MAP_MACRO(SPACE_TO_BATCH_ND , SpaceToBatchND) +MAP_MACRO(SPACE_TO_DEPTH , SpaceToDepth) +MAP_MACRO(L2_POOL_2D , L2Pool2D) +MAP_MACRO(EMBEDDING_LOOKUP , EmbeddingLookup) +MAP_MACRO(L2_NORMALIZATION , L2Normalization) +MAP_MACRO(HASHTABLE_LOOKUP , HashtableLookup) +MAP_MACRO(INSTANCE_NORM , InstanceNorm) +MAP_MACRO(PRELU , PReLU) +MAP_MACRO(TRANSPOSE_CONV , TransposeConv) +MAP_MACRO(SQRT , SQRT) +MAP_MACRO(SQUARED_DIFFERENCE , SquaredDifference) +MAP_MACRO(TOPK_V2 , TopKV2) +MAP_MACRO(GATHER , Gather) +MAP_MACRO(NEG , Neg) +MAP_MACRO(ABS , Abs) +MAP_MACRO(ARG_MAX , ArgMax) +MAP_MACRO(DEQUANTIZE , Dequantize) +MAP_MACRO(MEAN , Mean) +MAP_MACRO(LOCAL_RESPONSE_NORMALIZATION , LocalResponseNormalization) +// UNDEFINED IN CIRCLE +//MAP_MACRO(DepthToSpace) +MAP_MACRO(PACK , Pack) +MAP_MACRO(REDUCE_MIN , ReduceMin) +MAP_MACRO(SPLIT , Split) +MAP_MACRO(UNPACK , Unpack) +MAP_MACRO(PAD , Pad) +MAP_MACRO(CUSTOM , Custom) +// UNDEFINED IN CIRCLE +//MAP_MACRO(Permute) +MAP_MACRO(MINIMUM , Min) +MAP_MACRO(MAXIMUM , Max) +MAP_MACRO(ONE_HOT , OneHot) diff --git a/runtime/onert/api/src/nnfw_api.cc b/runtime/onert/api/src/nnfw_api.cc new file mode 100644 index 000000000..7e6792ff3 --- /dev/null +++ b/runtime/onert/api/src/nnfw_api.cc @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nnfw_api_internal.h" +#include "nnfw_version.h" + +/* + * Create a new session instance + * + * @param session the session to be created + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_create_session(nnfw_session **session) +{ + if (session == nullptr) + return NNFW_STATUS_ERROR; + + *session = new nnfw_session(); + + return NNFW_STATUS_NO_ERROR; +} + +/* + * Close a session instance + * + * @param session the session to be closed + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_close_session(nnfw_session *session) +{ + delete session; + return NNFW_STATUS_NO_ERROR; +} + +#define NNFW_RETURN_ERROR_IF_NULL(p) \ + do \ + { \ + if ((p) == NULL) \ + return NNFW_STATUS_ERROR; \ + } while (0) + +/* + * Load model from nnpackage file or directory + * + * @param session nnfw_session loading the given nnpackage file/dir + * @param package_file_path path to the nnpackage file or unzipped directory to be loaded + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_load_model_from_file(nnfw_session *session, const char *pacakge_file_path) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->load_model_from_file(pacakge_file_path); +} + +/* + * Prepare session to be ready for inference + * This phase may finalize model compilation, scheduling, and additional settings. + * + * @param session the session to be prepared + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_prepare(nnfw_session *session) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->prepare(); +} + +/* + * Run inference + * + * @param session the session to run inference + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_run(nnfw_session *session) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->run(); +} + +/* + * Set input + * + * @param session session to the input is to be set + * @param index index of input to be set (0-indexed) + * @param type type of the input + * @param buffer raw buffer for input + * @param length size of bytes of input + * + * @return NNFW_STATUS_NO_ERROR if successful + */ + +NNFW_STATUS nnfw_set_input(nnfw_session *session, uint32_t index, NNFW_TYPE type, + const void *buffer, size_t length) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_input(index, type, buffer, length); +} + +/* + * Set output + * + * @param session session from inference output is to be extracted + * @param index index of output to be set (0-indexed) + * @param type type of the output + * @param buffer raw buffer for output + * @param length size of bytes of output + * + * @return NNFW_STATUS_NO_ERROR if successful + */ + +NNFW_STATUS nnfw_set_output(nnfw_session *session, uint32_t index, NNFW_TYPE type, void *buffer, + size_t length) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_output(index, type, buffer, length); +} + +/* + * Get the number of inputs + * + * @param[in] session session from input information is to be extracted + * @param[out] number variable which the number of inputs is put into + * + * @return NNFW_STATUS_NO_ERROR if successful + */ + +NNFW_STATUS nnfw_input_size(nnfw_session *session, uint32_t *number) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->input_size(number); +} + +/* + * Get the number of outputs + * + * @param[in] session session from output information is to be extracted + * @param[out] number variable which the number of outputs is put into + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_output_size(nnfw_session *session, uint32_t *number) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->output_size(number); +} + +/* + * Set the layout of an input + * @note The input that does not call this has NNFW_LAYOUT_CHANNELS_LAST layout + * + * @param[in] session session from inference input is to be extracted + * @param[in] index index of input to be set (0-indexed) + * @param[in] layout layout to set to target input + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_input_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_input_layout(index, layout); +} + +/* + * Set the layout of an output + * @note The output that does not call this has NNFW_LAYOUT_CHANNELS_LAST layout + * + * @param[in] session session from inference output is to be extracted + * @param[in] index index of output to be set (0-indexed) + * @param[in] layout layout to set to target output + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_output_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_output_layout(index, layout); +} + +/* + * Get i-th input tensor info + * + * @param[in] session session from input information is to be extracted + * @param[in] index index of input + * @param[out] tensor_info nnfw_tensor_info + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_input_tensorinfo(nnfw_session *session, uint32_t index, + nnfw_tensorinfo *tensor_info) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->input_tensorinfo(index, tensor_info); +} + +/* + * Get i-th output tensor info + * + * @param[in] session session from output information is to be extracted + * @param[in] index index of output + * @param[out] tensor_info nnfw_tensor_info + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_output_tensorinfo(nnfw_session *session, uint32_t index, + nnfw_tensorinfo *tensor_info) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->output_tensorinfo(index, tensor_info); +} + +/* + * Register custom operation + * @param session session to register this operation + * @param id operation id + * @param info registration info ( eval function, etc. ) + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_register_custom_op_info(nnfw_session *session, const char *id, + custom_kernel_registration_info *info) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->register_custom_operation(id, info->eval_function); +} + +NNFW_STATUS nnfw_apply_tensorinfo(nnfw_session *session, uint32_t index, + nnfw_tensorinfo tensor_info) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->apply_tensorinfo(index, tensor_info); +} + +/* + * Set available backends + * + * @param[in] session session to which a avilable backends are set + * @param[in] backends available backends on which nnfw uses + */ +NNFW_STATUS nnfw_set_available_backends(nnfw_session *session, const char *backends) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_available_backends(backends); +} + +/* + * Set the operation's backend + * + * @param[in] session session to be modified + * @param[in] op operation to be set + * @param[in] backend bakcend on which operation run + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_op_backend(nnfw_session *session, const char *op, const char *backend) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_op_backend(op, backend); +} + +/* + * Retrieve uint32 type of nnfw information for given information ID. + * + * @param[in] session session to be queried on + * @param[in] information ID to be queried + * @param[out] val uint32 value to be returned + * + * @return @c NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_query_info_u32(nnfw_session *session, NNFW_INFO_ID id, uint32_t *val) +{ + (void)session; + switch (id) + { + case NNFW_INFO_ID_VERSION: + if (val) + { + *val = NNFW_VERSION; + return NNFW_STATUS_NO_ERROR; + } + break; + default: + return NNFW_STATUS_ERROR; + } + // It should not be reached. + return NNFW_STATUS_ERROR; +} diff --git a/runtime/onert/api/src/nnfw_api_internal.cc b/runtime/onert/api/src/nnfw_api_internal.cc new file mode 100644 index 000000000..4fff90443 --- /dev/null +++ b/runtime/onert/api/src/nnfw_api_internal.cc @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nnfw_api_internal.h" +#include "CustomKernelRegistry.h" +#include "compiler/Compiler.h" +#include "util/ConfigSource.h" +#include "exec/Execution.h" +#include "circle_loader.h" +#include "tflite_loader.h" +#include "json/json.h" +#include +#include +#include +#include +#include + +/* + * API does not accept string argument longer than max length below + */ +#define MAX_BACKEND_NAME_LENGTH 32 +#define MAX_OP_NAME_LENGTH 64 + +// Is null-terminating in length ? +static bool null_terminating(const char *str, uint32_t length) +{ + for (uint32_t i = 0; i < length; i++) + { + if (*(str + i) == '\0') + { + return true; + } + } + return false; +} + +static onert::ir::Layout convertLayout(NNFW_LAYOUT layout) +{ + if (layout == NNFW_LAYOUT_CHANNELS_LAST) + { + return onert::ir::Layout::NHWC; + } + else if (layout == NNFW_LAYOUT_CHANNELS_FIRST) + { + return onert::ir::Layout::NCHW; + } + return onert::ir::Layout::UNKNOWN; +} + +nnfw_session::nnfw_session() + : _primary_subgraph{nullptr}, _execution{nullptr}, + _kernel_registry{std::make_shared()}, + _source{std::make_unique()} +{ + // DO NOTHING +} + +nnfw_session::~nnfw_session() = default; + +NNFW_STATUS nnfw_session::load_model_from_file(const char *package_dir) +{ + // TODO : add support for zipped package file load + DIR *dir; + if (!(dir = opendir(package_dir))) + { + std::cerr << "invalid nnpackge directory: " << package_dir << std::endl; + return NNFW_STATUS_ERROR; + } + closedir(dir); + + try + { + std::string manifest_file_name(package_dir); + manifest_file_name += "/metadata/MANIFEST"; + std::ifstream mfs(manifest_file_name); + + // extract the filename of the first(index 0) model + // e.g. In MANIFEST file, { "models" : [ "firstmodel.tflite", "2nd.tflite" ] } + Json::Value root; + mfs >> root; + Json::Value models = root["models"]; + Json::Value model_types = root["model-types"]; + + auto model_file_path = package_dir + std::string("/") + models[0].asString(); // first model + auto model_type = model_types[0].asString(); // first model's type + if (model_type == "tflite") + { + _primary_subgraph = onert::tflite_loader::loadModel(model_file_path.c_str()); + } + else if (model_type == "circle") + { + _primary_subgraph = onert::circle_loader::loadModel(model_file_path.c_str()); + } + else + { + std::cerr << "Unsupported model type in MANIFEST" << std::endl; + return NNFW_STATUS_ERROR; + } + _primary_subgraph->bindKernelBuilder(_kernel_registry->getBuilder()); + } + catch (const std::exception &e) + { + std::cerr << "Error during model loading : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + + _compiler = std::make_unique(_primary_subgraph); + + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::prepare() +{ + if (!_primary_subgraph || _primary_subgraph->isBuildingPhase()) + { + std::cerr << "Error during model prepare : " + << "prepare should be run after load_model" << std::endl; + return NNFW_STATUS_ERROR; + } + + // NOTE. If users want to run prepare() more than one time, this could be removed. + if (!_source || _execution) + { + std::cerr << "Error during model prepare : " + << "prepare should be run once" << std::endl; + return NNFW_STATUS_ERROR; + } + + // TODO : add additional setting routine(executor type, backend) + // Note that we assume acl_cl backend + + _source->set("DELETE_CACHED_DATA", "1"); + + try + { + // config_source setting + using onert::util::config_source; + config_source(std::move(_source)); + + _compiler->compile(); + std::shared_ptr executor; + _compiler->release(executor); + _execution = std::make_shared(executor); + } + catch (const std::exception &e) + { + std::cerr << "Error during model prepare : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::run() +{ + if (!_execution) + { + std::cerr << "Error during nnfw_session::run : " + << "run should be run after prepare" << std::endl; + return NNFW_STATUS_ERROR; + } + + try + { + _execution->execute(); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::run : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_input(uint32_t index, NNFW_TYPE /*type*/, const void *buffer, + size_t length) +{ + try + { + _execution->setInput(onert::ir::IOIndex(index), buffer, length); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_input : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_output(uint32_t index, NNFW_TYPE /*type*/, void *buffer, + size_t length) +{ + try + { + _execution->setOutput(onert::ir::IOIndex(index), buffer, length); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_output : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::input_size(uint32_t *number) +{ + try + { + if (number == nullptr) + { + std::cerr << "Error during nnfw_session::input_size, number is null pointer." << std::endl; + return NNFW_STATUS_ERROR; + } + *number = _primary_subgraph->getInputs().size(); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::input_size : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::output_size(uint32_t *number) +{ + try + { + if (number == nullptr) + { + std::cerr << "Error during nnfw_session::output_size, number is null pointer." << std::endl; + return NNFW_STATUS_ERROR; + } + *number = _primary_subgraph->getOutputs().size(); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::output_size" << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_input_layout(uint32_t index, NNFW_LAYOUT layout) +{ + try + { + if (layout != NNFW_LAYOUT_NONE && layout != NNFW_LAYOUT_CHANNELS_FIRST && + layout != NNFW_LAYOUT_CHANNELS_LAST) + { + std::cerr << "Error during nnfw_session::set_input_layout, not supported layout" << std::endl; + return NNFW_STATUS_ERROR; + } + _execution->setInputLayout(onert::ir::IOIndex(index), convertLayout(layout)); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_input_layout : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_output_layout(uint32_t index, NNFW_LAYOUT layout) +{ + try + { + if (layout != NNFW_LAYOUT_NONE && layout != NNFW_LAYOUT_CHANNELS_FIRST && + layout != NNFW_LAYOUT_CHANNELS_LAST) + { + std::cerr << "Error during nnfw_session::set_output_layout, not supported layout" + << std::endl; + return NNFW_STATUS_ERROR; + } + _execution->setOutputLayout(onert::ir::IOIndex(index), convertLayout(layout)); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_output_layout : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +static NNFW_TYPE datatype_to_nnfw_dtype(onert::ir::DataType dt) +{ + using onert::ir::DataType; + switch (dt) + { + case DataType::FLOAT32: + return NNFW_TYPE_TENSOR_FLOAT32; + case DataType::INT32: + return NNFW_TYPE_TENSOR_INT32; + case DataType::QUANT8_ASYMM: + return NNFW_TYPE_TENSOR_QUANT8_ASYMM; + case DataType::BOOL8: + return NNFW_TYPE_TENSOR_BOOL; + case DataType::UINT8: + return NNFW_TYPE_TENSOR_UINT8; + case DataType::UINT32: + case DataType::QUANT8_SYMM: + default: + std::cerr << "Error: Model has type that runtime API does not support." << std::endl; + exit(-1); + } +} + +NNFW_STATUS nnfw_session::apply_tensorinfo(uint32_t /*index*/, nnfw_tensorinfo /*ti*/) +{ + std::cerr << "Error: NYI" << std::endl; + return NNFW_STATUS_ERROR; +} + +NNFW_STATUS nnfw_session::input_tensorinfo(uint32_t index, nnfw_tensorinfo *ti) +{ + try + { + if (ti == nullptr) + { + std::cerr << "Error during nnfw_session::input_tensorinfo, tensorinfo is null pointer." + << std::endl; + return NNFW_STATUS_ERROR; + } + if (index >= _primary_subgraph->getInputs().size()) + { + std::cerr << "Error during nnfw_session::input_tensorinfo, index is out of range." + << std::endl; + return NNFW_STATUS_ERROR; + } + auto opidx = _primary_subgraph->getInputs().at(index); + auto shape = _primary_subgraph->operands().at(opidx).shape(); + ti->rank = shape.rank(); + for (int j = 0; j < ti->rank; ++j) + { + ti->dims[j] = shape.dim(j); + } + ti->dtype = datatype_to_nnfw_dtype(_primary_subgraph->operands().at(opidx).typeInfo().type()); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::input_tensorinfo : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::output_tensorinfo(uint32_t index, nnfw_tensorinfo *ti) +{ + try + { + if (ti == nullptr) + { + std::cerr << "Error during nnfw_session::output_tensorinfo, tensorinfo is null pointer." + << std::endl; + return NNFW_STATUS_ERROR; + } + if (index >= _primary_subgraph->getOutputs().size()) + { + std::cerr << "Error during nnfw_session::output_tensorinfo, index is out of range." + << std::endl; + return NNFW_STATUS_ERROR; + } + auto opidx = _primary_subgraph->getOutputs().at(index); + auto shape = _primary_subgraph->operands().at(opidx).shape(); + ti->rank = shape.rank(); + for (int j = 0; j < ti->rank; ++j) + { + ti->dims[j] = shape.dim(j); + } + ti->dtype = datatype_to_nnfw_dtype(_primary_subgraph->operands().at(opidx).typeInfo().type()); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::output_tensorinfo : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} +NNFW_STATUS nnfw_session::register_custom_operation(const std::string &id, + nnfw_custom_eval eval_func) +{ + _kernel_registry->registerKernel(id, eval_func); + return NNFW_STATUS_NO_ERROR; +} + +static std::string get_op_backend_string(std::string op) +{ +#define MAP_MACRO(CircleName, OneRTName) {#CircleName, "OP_BACKEND_" #OneRTName}, + + static std::unordered_map operation_map = { +#include "OpMap.lst" + }; + +#undef MAP_MACRO + + auto n = operation_map.find(op); + + if (n == operation_map.end()) + { + // this return value is handled by a caller to return error code + return std::string(""); + } + else + { + return n->second; + } +} + +NNFW_STATUS nnfw_session::set_available_backends(const char *backends) +{ + try + { + if (!backends || null_terminating(backends, MAX_BACKEND_NAME_LENGTH) == false) + { + return NNFW_STATUS_ERROR; + } + + _source->set("BACKENDS", backends); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_available_backends : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_op_backend(const char *op, const char *backend) +{ + try + { + if (!op || !null_terminating(op, MAX_OP_NAME_LENGTH) || !backend || + !null_terminating(backend, MAX_BACKEND_NAME_LENGTH)) + { + return NNFW_STATUS_ERROR; + } + + auto key = get_op_backend_string(op); + + if (key.empty()) + { + return NNFW_STATUS_ERROR; + } + + _source->set(key, backend); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_op_backend : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_config(const char *key, const char *value) +{ + // The session must be in the state after model load + if (!_compiler) + return NNFW_STATUS_ERROR; + + auto &options = _compiler->options(); + + using namespace onert::util; + + if (key == config::TRACE_FILEPATH) + { + options.trace_filepath = value; + } + else if (key == config::GRAPH_DOT_DUMP) + { + options.graph_dump_level = toInt(value); + } + else if (key == config::OP_SEQ_MAX_NODE) + { + options.op_seq_max_node = toInt(value); + } + else if (key == config::EXECUTOR) + { + options.executor = value; + } + else if (key == config::OP_BACKEND_ALLOPS) + { + options.manual_scheduler_options.backend_for_all = value; + } + else if (key == config::USE_SCHEDULER) + { + options.he_scheduler = toBool(value); + } + else if (key == config::PROFILING_MODE) + { + options.he_profiling_mode = toBool(value); + } + else if (key == config::DELETE_CACHED_DATA) + { + options.delete_cached_data = toBool(value); + } + else if (key == config::DISABLE_COMPILE) + { + options.disable_compile = toBool(value); + } + else + { + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} diff --git a/runtime/onert/api/src/nnfw_api_internal.h b/runtime/onert/api/src/nnfw_api_internal.h new file mode 100644 index 000000000..7fe4e0a26 --- /dev/null +++ b/runtime/onert/api/src/nnfw_api_internal.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __API_NNFW_API_INTERNAL_H__ +#define __API_NNFW_API_INTERNAL_H__ + +#include "nnfw.h" +#include "nnfw_dev.h" + +#include + +#include +#include + +namespace onert +{ +namespace frontend +{ +namespace custom +{ +class KernelRegistry; +} +} // namespace frontend +namespace exec +{ +class Execution; +} // namespace exec +namespace ir +{ +class Graph; +} // namespace ir +namespace compiler +{ +class Compiler; +} // namespace compiler +} // namespace onert + +struct nnfw_session +{ +public: + nnfw_session(); + ~nnfw_session(); + + NNFW_STATUS load_model_from_file(const char *package_file_path); + NNFW_STATUS prepare(); + NNFW_STATUS run(); + + NNFW_STATUS set_input(uint32_t index, NNFW_TYPE type, const void *buffer, size_t length); + NNFW_STATUS set_output(uint32_t index, NNFW_TYPE type, void *buffer, size_t length); + + NNFW_STATUS input_size(uint32_t *number); + NNFW_STATUS output_size(uint32_t *number); + + NNFW_STATUS set_input_layout(uint32_t index, NNFW_LAYOUT layout); + NNFW_STATUS set_output_layout(uint32_t index, NNFW_LAYOUT layout); + + NNFW_STATUS apply_tensorinfo(uint32_t index, nnfw_tensorinfo ti); + + NNFW_STATUS input_tensorinfo(uint32_t index, nnfw_tensorinfo *ti); + NNFW_STATUS output_tensorinfo(uint32_t index, nnfw_tensorinfo *ti); + + NNFW_STATUS register_custom_operation(const std::string &id, nnfw_custom_eval eval_func); + + NNFW_STATUS set_available_backends(const char *backends); + NNFW_STATUS set_op_backend(const char *op, const char *backend); + + NNFW_STATUS set_config(const char *key, const char *value); + +private: + std::shared_ptr _primary_subgraph; + std::unique_ptr _compiler; + std::shared_ptr _execution; + std::shared_ptr _kernel_registry; + +protected: + std::unique_ptr _source; +}; + +#endif // __API_NNFW_API_INTERNAL_H__ diff --git a/runtime/onert/api/src/nnfw_debug.cc b/runtime/onert/api/src/nnfw_debug.cc new file mode 100644 index 000000000..73d0e9c86 --- /dev/null +++ b/runtime/onert/api/src/nnfw_debug.cc @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nnfw_debug_internal.h" + +NNFW_STATUS nnfw_create_debug_session(nnfw_session **session) +{ + *session = new nnfw_debug_session(); + + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_set_config(nnfw_session *session, const char *key, const char *value) +{ + return session->set_config(key, value); +} diff --git a/runtime/onert/api/src/nnfw_debug_internal.cc b/runtime/onert/api/src/nnfw_debug_internal.cc new file mode 100644 index 000000000..4fddfc93d --- /dev/null +++ b/runtime/onert/api/src/nnfw_debug_internal.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nnfw_debug_internal.h" +#include "util/EnvConfigSource.h" + +#include + +nnfw_debug_session::nnfw_debug_session() : nnfw_session() +{ + _source = std::make_unique(); +} diff --git a/runtime/onert/api/src/nnfw_debug_internal.h b/runtime/onert/api/src/nnfw_debug_internal.h new file mode 100644 index 000000000..f4984e7a1 --- /dev/null +++ b/runtime/onert/api/src/nnfw_debug_internal.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __API_NNFW_DEBUG_INTERNAL_H__ +#define __API_NNFW_DEBUG_INTERNAL_H__ + +#include "nnfw_debug.h" +#include "nnfw_api_internal.h" + +class nnfw_debug_session : public nnfw_session +{ +public: + nnfw_debug_session(); +}; + +#endif // __API_NNFW_DEBUG_INTERNAL_H__ diff --git a/runtime/onert/backend/CMakeLists.txt b/runtime/onert/backend/CMakeLists.txt new file mode 100644 index 000000000..7310571d8 --- /dev/null +++ b/runtime/onert/backend/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LIB_ONERT_BACKEND_ACL_COMMON onert_backend_acl_common) +set(LIB_ONERT_BACKEND_CPU_COMMON onert_backend_cpu_common) + +add_subdirectory(cpu) +add_subdirectory(cpu_common) +add_subdirectory(acl_cl) +add_subdirectory(acl_neon) +add_subdirectory(acl_common) diff --git a/runtime/onert/backend/acl_cl/Backend.h b/runtime/onert/backend/acl_cl/Backend.h new file mode 100644 index 000000000..fabcae38e --- /dev/null +++ b/runtime/onert/backend/acl_cl/Backend.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_BACKEND_H__ +#define __ONERT_BACKEND_ACL_CL_BACKEND_H__ + +#include +#include + +#include "Config.h" +#include "ConstantInitializer.h" +#include "KernelGenerator.h" +#include "ShapeFixer.h" +#include "TensorManager.h" +#include "Optimizer.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +class Backend : public ::onert::backend::Backend +{ +public: + Backend() : _config{std::make_shared()} {} + + std::shared_ptr config() const override { return _config; } + + std::unique_ptr newContext(const ir::Graph &graph, + const std::shared_ptr &, + bool is_linear_executor) const override + { + const auto &operands = graph.operands(); + auto context = std::make_unique(this, &graph); + auto tb = std::make_shared(operands, createTensorManager(is_linear_executor)); + context->tensor_builder = tb; + context->constant_initializer = std::make_shared(operands, tb); + context->kernel_gen = std::make_shared(operands, tb); + context->shape_fixer = std::make_shared(operands, tb); + context->tensor_register = nullptr; + context->optimizer = std::make_shared(context.get()); + return context; + } + +private: + std::shared_ptr _config; +}; + +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_BACKEND_H__ diff --git a/runtime/onert/backend/acl_cl/CLTimer.h b/runtime/onert/backend/acl_cl/CLTimer.h new file mode 100644 index 000000000..722dc68ef --- /dev/null +++ b/runtime/onert/backend/acl_cl/CLTimer.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_CLTIMER_H__ +#define __ONERT_BACKEND_ACL_CL_CLTIMER_H__ + +#include +#include +#include +#include +#include +#include + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +/** + * @brief Class to measure CL kernels execution time + */ +class CLTimer : public util::ITimer +{ +public: + /** + * @brief This function replaces CL function, which enqueues a command to execute a kernel + * with a wrapper which remembers enqueued kernels + */ + void handleBegin() override + { + _measured_events.clear(); + + _origin_enqueue_function = arm_compute::CLSymbols::get().clEnqueueNDRangeKernel_ptr; + + auto _timer_enqueue_function = [this](cl_command_queue command_queue, cl_kernel kernel, + cl_uint work_dim, const size_t *gwo, const size_t *gws, + const size_t *lws, cl_uint num_events_in_wait_list, + const cl_event *event_wait_list, cl_event *usr_event) { + cl_event event; + cl_int enqueue_res = + this->_origin_enqueue_function(command_queue, kernel, work_dim, gwo, gws, lws, + num_events_in_wait_list, event_wait_list, &event); + this->_measured_events.emplace_back(event); + + // According to spec, if NULL was provided in usr_event - event shouldn't be returned + if (usr_event != nullptr) + { + clRetainEvent(event); + *usr_event = event; + } + return enqueue_res; + }; + arm_compute::CLSymbols::get().clEnqueueNDRangeKernel_ptr = _timer_enqueue_function; + + // Set CL_QUEUE_PROFILING_ENABLE flag for the CL command-queue, if it isn't already set + auto &cl_scheduler = arm_compute::CLScheduler::get(); + auto props = cl_scheduler.queue().getInfo(); + if ((props & CL_QUEUE_PROFILING_ENABLE) == 0) + { + cl_scheduler.set_queue( + cl::CommandQueue(cl_scheduler.context(), props | CL_QUEUE_PROFILING_ENABLE)); + } + }; + + /** + * @brief Get timer result by addition executed CL kernels durations + */ + void handleEnd() override + { + _timer_res = 0; + for (auto const &event : _measured_events) + { + cl_ulong start; + cl_ulong end; + event.getProfilingInfo(CL_PROFILING_COMMAND_START, &start); + event.getProfilingInfo(CL_PROFILING_COMMAND_END, &end); + _timer_res += (end - start) / 1000.f; // nanoseconds -> microseconds + } + + // Restore origin CL enqueue function + arm_compute::CLSymbols::get().clEnqueueNDRangeKernel_ptr = _origin_enqueue_function; + }; + +private: + std::function _origin_enqueue_function; + std::list<::cl::Event> _measured_events; +}; + +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_CLTIMER_H__ diff --git a/runtime/onert/backend/acl_cl/CMakeLists.txt b/runtime/onert/backend/acl_cl/CMakeLists.txt new file mode 100644 index 000000000..3b56dca81 --- /dev/null +++ b/runtime/onert/backend/acl_cl/CMakeLists.txt @@ -0,0 +1,19 @@ +# Unsupported architecture +nnas_find_package(ARMCompute QUIET) +if(NOT ARMCompute_FOUND) + return() +endif(NOT ARMCompute_FOUND) + +set(LIB_ONERT_BACKEND_ACL_CL onert_backend_acl_cl) + +file(GLOB_RECURSE SOURCES "*.cc") + +add_library(${LIB_ONERT_BACKEND_ACL_CL} SHARED ${SOURCES}) + +target_link_libraries(${LIB_ONERT_BACKEND_ACL_CL} PRIVATE ${LIB_ONERT_BACKEND_ACL_COMMON}) +target_link_libraries(${LIB_ONERT_BACKEND_ACL_CL} PRIVATE nnfw_common) +target_link_libraries(${LIB_ONERT_BACKEND_ACL_CL} PRIVATE nnfw_coverage) + +set_target_properties(${LIB_ONERT_BACKEND_ACL_CL} PROPERTIES OUTPUT_NAME backend_acl_cl) + +install(TARGETS ${LIB_ONERT_BACKEND_ACL_CL} DESTINATION lib) diff --git a/runtime/onert/backend/acl_cl/Config.cc b/runtime/onert/backend/acl_cl/Config.cc new file mode 100644 index 000000000..1cc3cb401 --- /dev/null +++ b/runtime/onert/backend/acl_cl/Config.cc @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// For CLKernelLibraryEx initialization +#include "arm_compute/core/CL/CLHelpers.h" +#include "arm_compute/core/CL/CLKernelLibrary.h" +#include "arm_compute/core/CL/CLKernelLibraryEx.h" + +#include + +#include "Config.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +bool Config::initialize() +{ + if (!arm_compute::opencl_is_available()) + { + return false; + } + arm_compute::CLScheduler::get().default_init(); + // NOTE CLKernelLibraryEx must use the same context as CLScheduler + // It did not check whether another device is available. + arm_compute::CLKernelLibraryEx::get().init( + "./cl_kernels/", arm_compute::CLScheduler::get().context(), cl::Device::getDefault()); + + return true; +} + +} // namespace acl_cl +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_cl/Config.h b/runtime/onert/backend/acl_cl/Config.h new file mode 100644 index 000000000..a64c7923e --- /dev/null +++ b/runtime/onert/backend/acl_cl/Config.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_CONFIG_H__ +#define __ONERT_BACKEND_ACL_CL_CONFIG_H__ + +#include "CLTimer.h" +#include +#include + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +class Config : public IConfig +{ +public: + std::string id() override { return "acl_cl"; } + bool initialize() override; + bool SupportPermutation() override { return true; } + std::unique_ptr timer() override { return std::make_unique(); } +}; + +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_CONFIG_H__ diff --git a/runtime/onert/backend/acl_cl/ConstantInitializer.cc b/runtime/onert/backend/acl_cl/ConstantInitializer.cc new file mode 100644 index 000000000..d7f5f8031 --- /dev/null +++ b/runtime/onert/backend/acl_cl/ConstantInitializer.cc @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConstantInitializer.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +ConstantInitializer::ConstantInitializer(const ir::Operands &operands, + const std::shared_ptr &tensor_builder) + : IConstantInitializer{operands}, _tensor_builder{tensor_builder} +{ + // DO NOTHING +} + +void ConstantInitializer::copyInputInitialize(const ir::Operation &node, uint32_t index) +{ + assert(node.getInputs().size() > index); + + const auto &input_index = node.getInputs().at(index); + const auto &input_obj = _operands.at(input_index); + registerCopyInitializer(input_index, input_obj); +} + +void ConstantInitializer::permuteInputInitialize(const ir::Operation &node, uint32_t index) +{ + assert(node.getInputs().size() > index); + + const auto &input_index = node.getInputs().at(index); + const auto &input_obj = _operands.at(input_index); + registerPermuteInitializer(input_index, input_obj); +} + +void ConstantInitializer::visit(const ir::operation::BatchToSpaceND &node) +{ + const auto &block_size_index = node.getInputs().at(ir::operation::BatchToSpaceND::BLOCK_SIZE); + const auto &block_size_obj = _operands.at(block_size_index); + + if (block_size_obj.isConstant()) + { + _init_map[block_size_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) { + assert(model_obj.data()); + const auto &shape = model_obj.shape(); + const auto base = reinterpret_cast(model_obj.data()->base()); + assert(model_obj.shape().rank() == 1); + obj.access([&](ITensor &tensor) { + for (size_t i = 0; i < shape.num_elements(); ++i) + { + const int32_t value = base[shape.num_elements() - i - 1]; + int32_t *into = reinterpret_cast(tensor.buffer() + + tensor.calcOffset({static_cast(i)})); + *into = value; + } + }); + }; + } +} + +void ConstantInitializer::visit(const ir::operation::Conv2D &node) +{ + permuteInputInitialize(node, ir::operation::Conv2D::KERNEL); + copyInputInitialize(node, ir::operation::Conv2D::BIAS); +} + +void ConstantInitializer::visit(const ir::operation::DepthwiseConv2D &node) +{ + permuteInputInitialize(node, ir::operation::DepthwiseConv2D::KERNEL); + copyInputInitialize(node, ir::operation::DepthwiseConv2D::BIAS); +} + +void ConstantInitializer::visit(const ir::operation::EmbeddingLookup &node) +{ + copyInputInitialize(node, ir::operation::EmbeddingLookup::LOOKUPS); +} + +void ConstantInitializer::visit(const ir::operation::FullyConnected &node) +{ + copyInputInitialize(node, ir::operation::FullyConnected::WEIGHT); + copyInputInitialize(node, ir::operation::FullyConnected::BIAS); +} + +void ConstantInitializer::visit(const ir::operation::Gather &node) +{ + copyInputInitialize(node, ir::operation::Gather::INDICES); +} + +void ConstantInitializer::visit(const ir::operation::HashtableLookup &node) +{ + copyInputInitialize(node, ir::operation::HashtableLookup::LOOKUPS); + copyInputInitialize(node, ir::operation::HashtableLookup::KEYS); +} + +void ConstantInitializer::visit(const ir::operation::LSTM &node) +{ + copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_INPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_FORGET_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_CELL_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_OUTPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_INPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_FORGET_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_CELL_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_OUTPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::CELL_TO_INPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::CELL_TO_FORGET_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::CELL_TO_OUTPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::INPUT_GATE_BIAS); + copyInputInitialize(node, ir::operation::LSTM::FORGET_GATE_BIAS); + copyInputInitialize(node, ir::operation::LSTM::OUTPUT_GATE_BIAS); + copyInputInitialize(node, ir::operation::LSTM::PROJECTION_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::PROJECTION_BIAS); +} + +void ConstantInitializer::visit(const ir::operation::RNN &node) +{ + copyInputInitialize(node, ir::operation::RNN::WEIGHTS); + copyInputInitialize(node, ir::operation::RNN::RECURRENT_WEIGHTS); + copyInputInitialize(node, ir::operation::RNN::BIAS); +} + +void ConstantInitializer::visit(const ir::operation::SpaceToBatchND &node) +{ + const auto &block_size_index = node.getInputs().at(ir::operation::SpaceToBatchND::BLOCK_SIZE); + const auto &block_size_obj = _operands.at(block_size_index); + + if (block_size_obj.isConstant()) + { + _init_map[block_size_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) { + assert(model_obj.data()); + const auto &shape = model_obj.shape(); + const auto base = reinterpret_cast(model_obj.data()->base()); + assert(model_obj.shape().rank() == 1); + obj.access([&](ITensor &tensor) { + for (size_t i = 0; i < shape.num_elements(); ++i) + { + const int32_t value = base[shape.num_elements() - i - 1]; + int32_t *into = reinterpret_cast(tensor.buffer() + + tensor.calcOffset({static_cast(i)})); + *into = value; + } + }); + }; + } + + const auto &paddings_index = node.getInputs().at(ir::operation::SpaceToBatchND::PADDINGS); + const auto &paddings_obj = _operands.at(paddings_index); + if (paddings_obj.isConstant()) + { + _init_map[paddings_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) { + assert(model_obj.data()); + const auto &shape = model_obj.shape(); + const auto base = reinterpret_cast(model_obj.data()->base()); + assert(model_obj.shape().rank() == 2); + assert(obj.dimension(0) == 2); + obj.access([&](ITensor &tensor) { + for (auto i = 0; i < shape.dim(0); ++i) + { + for (auto j = 0; j < shape.dim(1); ++j) + { + const int32_t value = base[i * 2 + j]; + int32_t *into = reinterpret_cast( + tensor.buffer() + tensor.calcOffset({shape.dim(0) - i - 1, j})); + *into = value; + } + } + }); + }; + } +} + +void ConstantInitializer::visit(const ir::operation::TransposeConv &node) +{ + const auto &kernel_index = node.getInputs().at(ir::operation::TransposeConv::KERNEL); + const auto &kernel_obj = _operands.at(kernel_index); + registerPermuteInitializer(kernel_index, kernel_obj); +} + +} // namespace acl_cl +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_cl/ConstantInitializer.h b/runtime/onert/backend/acl_cl/ConstantInitializer.h new file mode 100644 index 000000000..c51f72b11 --- /dev/null +++ b/runtime/onert/backend/acl_cl/ConstantInitializer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_ACL_CL_CONSTANT_INITIALIZER_H__ +#define __ONERT_COMPILER_ACL_CL_CONSTANT_INITIALIZER_H__ + +#include +#include +#include "TensorBuilder.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +class ConstantInitializer : public IConstantInitializer +{ +public: + ConstantInitializer(const ir::Operands &operands, + const std::shared_ptr &tensor_builder); + +public: + void visit(const ir::operation::BatchToSpaceND &) override; + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::EmbeddingLookup &) override; + void visit(const ir::operation::FullyConnected &) override; + void visit(const ir::operation::Gather &) override; + void visit(const ir::operation::HashtableLookup &) override; + void visit(const ir::operation::LSTM &) override; + void visit(const ir::operation::RNN &) override; + void visit(const ir::operation::SpaceToBatchND &) override; + void visit(const ir::operation::TransposeConv &) override; + +private: + std::shared_ptr tensor_builder() const override { return _tensor_builder; } + void copyInputInitialize(const ir::Operation &node, uint32_t index); + void permuteInputInitialize(const ir::Operation &node, uint32_t index); + +private: + std::shared_ptr _tensor_builder; +}; + +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_COMPILER_ACL_CL_CONSTANT_INITIALIZER_H__ diff --git a/runtime/onert/backend/acl_cl/KernelGenerator.cc b/runtime/onert/backend/acl_cl/KernelGenerator.cc new file mode 100644 index 000000000..25588fea7 --- /dev/null +++ b/runtime/onert/backend/acl_cl/KernelGenerator.cc @@ -0,0 +1,2023 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "KernelGenerator.h" + +#include // Include all ARM Compute CL functions +#include // Include all ARM Compute EX CL functions + +#include +#include +#include +#include + +#include "ir/Index.h" +#include "ir/DataType.h" +#include "ir/InternalType.h" +#include "exec/NopFunction.h" +#include "exec/FunctionSequence.h" +#include "util/logging.h" +#include "util/Utils.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +using ::onert::backend::acl_common::asAclClFunction; +using ActivationBuilder = ::onert::backend::acl_common::AclActivationBuilder< + ::arm_compute::ICLTensor, ::arm_compute::CLActivationLayer, acl_common::AclClFunction>; + +KernelGenerator::KernelGenerator(const ir::Operands &ctx, + const std::shared_ptr &tensor_builder) + : _ctx(ctx), _tensor_builder(tensor_builder), _current_op_seq_layout(ir::Layout::UNKNOWN) +{ + // DO NOTHING +} + +void KernelGenerator::visit(const ir::OpSequence &op_seq) +{ + // TODO Move this to IKernelGenerator + // (all derivatives have the same implementation for this) + assert(!_return_fn_seq); + _return_fn_seq = std::make_unique(); + _current_op_seq_layout = op_seq.getLayout(); + for (const auto &e : op_seq.operations()) + { + const auto &node = *(e.node); + node.accept(*this); + _return_fn_seq->append(releaseFunction()); + } +} + +void KernelGenerator::visit(const ir::operation::BatchToSpaceND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::BatchToSpaceND::Input::INPUT)}; + const auto block_size_index{ + node.getInputs().at(ir::operation::BatchToSpaceND::Input::BLOCK_SIZE)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto block_size_alloc = _tensor_builder->at(block_size_index).get(); + + assert(_ctx.at(block_size_index).data()); + + auto fn = std::make_unique<::arm_compute::CLBatchToSpaceLayer>(); + + fn->configure(ifm_alloc->handle(), block_size_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Cast &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Cast::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + const auto input_sub_type = _ctx.at(ifm_index).typeInfo().type() == ir::DataType::BOOL8 + ? arm_compute::SubDataType::BOOL + : arm_compute::SubDataType::NONE; + + auto fn = std::make_unique<::arm_compute::CLCast>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), input_sub_type); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Conv2D &node) +{ + using ir::operation::Conv2D; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(Conv2D::Input::INPUT)}; + const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in]. + const auto &ker_shape = _ctx.at(ker_index).shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + + const auto stride = node.param().stride; + const auto padding = ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, + ker_width, ker_height); + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto ker_alloc = _tensor_builder->at(ker_index).get(); + auto bias_alloc = _tensor_builder->at(bias_index).get(); + + const auto conv_info = acl_common::asPadStrideInfo(padding, stride); + const auto act_info = acl_common::asActivationLayerInfo(activation); + + auto fn = std::make_unique<::arm_compute::CLConvolutionLayer>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + fn->configure(ifm_alloc->handle(), ker_alloc->handle(), bias_alloc->handle(), ofm_alloc->handle(), + conv_info, ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), act_info); + + _return_fn = asAclClFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::DepthwiseConv2D &node) +{ + using ir::operation::DepthwiseConv2D; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(DepthwiseConv2D::Input::INPUT)}; + const auto ker_index{node.getInputs().at(DepthwiseConv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(DepthwiseConv2D::Input::BIAS)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + // Kernel format is [1, kernel_height, kernel_width, depth_out]. + const auto &ker_shape = _ctx.at(ker_index).shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + + const auto stride = node.param().stride; + const auto padding = ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, + ker_width, ker_height); + const auto multiplier = node.param().multiplier; + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto ker_alloc = _tensor_builder->at(ker_index).get(); + auto bias_alloc = _tensor_builder->at(bias_index).get(); + + const auto conv_info = acl_common::asPadStrideInfo(padding, stride); + const auto act_info = acl_common::asActivationLayerInfo(activation); + + { + auto fn = std::make_unique<::arm_compute::CLDepthwiseConvolutionLayer>(); + + fn->configure(ifm_alloc->handle(), ker_alloc->handle(), bias_alloc->handle(), + ofm_alloc->handle(), conv_info, multiplier, act_info); + + _return_fn = asAclClFunction(std::move(fn)); + } +} + +void KernelGenerator::visit(const ir::operation::MaxPool2D &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::MaxPool2D::Input::INPUT)}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + + const auto kh = node.param().kh; + const auto kw = node.param().kw; + const auto stride = node.param().stride; + const auto padding = + ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh); + const auto activation = node.param().activation; + + VERBOSE(MaxPool2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(MaxPool2D) << "IFM_W: " << ifm_shape.W << std::endl; + VERBOSE(MaxPool2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(MaxPool2D) << "OFM_W: " << ofm_shape.W << std::endl; + VERBOSE(MaxPool2D) << "KER_H: " << kh << std::endl; + VERBOSE(MaxPool2D) << "KER_W: " << kw << std::endl; + VERBOSE(MaxPool2D) << "STRIDE_H: " << stride.vertical << std::endl; + VERBOSE(MaxPool2D) << "STRIDE_W: " << stride.horizontal << std::endl; + VERBOSE(MaxPool2D) << "PAD(T): " << padding.top << std::endl; + VERBOSE(MaxPool2D) << "PAD(B): " << padding.bottom << std::endl; + VERBOSE(MaxPool2D) << "PAD(L): " << padding.left << std::endl; + VERBOSE(MaxPool2D) << "PAD(R): " << padding.right << std::endl; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::MAX, + ::arm_compute::Size2D{kw, kh}, + acl_common::asPadStrideInfo(padding, stride)}; + + auto fn = std::make_unique<::arm_compute::CLPoolingLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info); + + _return_fn = std::make_unique( + asAclClFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::AvgPool2D &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::AvgPool2D::Input::INPUT)}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + + const auto kh = node.param().kh; + const auto kw = node.param().kw; + const auto stride = node.param().stride; + const auto padding = + ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh); + const auto activation = node.param().activation; + + VERBOSE(AvgPool2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(AvgPool2D) << "IFM_W: " << ifm_shape.W << std::endl; + VERBOSE(AvgPool2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(AvgPool2D) << "OFM_W: " << ofm_shape.W << std::endl; + VERBOSE(AvgPool2D) << "KER_H: " << kh << std::endl; + VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl; + VERBOSE(AvgPool2D) << "STRIDE_H: " << stride.vertical << std::endl; + VERBOSE(AvgPool2D) << "STRIDE_W: " << stride.horizontal << std::endl; + VERBOSE(AvgPool2D) << "PAD(T): " << padding.top << std::endl; + VERBOSE(AvgPool2D) << "PAD(B): " << padding.bottom << std::endl; + VERBOSE(AvgPool2D) << "PAD(L): " << padding.left << std::endl; + VERBOSE(AvgPool2D) << "PAD(R): " << padding.right << std::endl; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + ::arm_compute::PoolingLayerInfo info{ + ::arm_compute::PoolingType::AVG, ::arm_compute::Size2D{kw, kh}, + acl_common::asPadStrideInfo(padding, stride), true /* exclude_padding */}; + + auto fn = std::make_unique<::arm_compute::CLPoolingLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info); + + _return_fn = std::make_unique( + asAclClFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Concat &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + + std::vector input_indexes; + + for (const auto &input : node.getInputs()) + input_indexes.emplace_back(input); + + const auto axis = node.param().axis; + + // Concat elimination check + bool eliminated = _tensor_builder->areSubTensorsOf(ofm_index, node.getInputs()); + if (eliminated) + { + // If concat eliminated, return a NOP IFunction + VERBOSE(acl_cl_KernelGenerator_Concat) << "Concat eliminated" << std::endl; + _return_fn = std::make_unique(); + return; + } + + auto output_alloc = _tensor_builder->at(ofm_index).get(); + std::vector<::arm_compute::ICLTensor *> input_tensors; + for (auto &ifm_ind : input_indexes) + input_tensors.emplace_back(_tensor_builder->at(ifm_ind)->handle()); + + std::unique_ptr<::arm_compute::IFunction> fn; + if (input_indexes.size() < 2) + { + auto l = std::make_unique<::arm_compute::CLCopy>(); + l->configure(input_tensors.at(0), output_alloc->handle()); + fn = std::move(l); + } + else + { + auto l = std::make_unique<::arm_compute::CLConcatenateLayer>(); + const auto rank = node.param().rank; + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = output_alloc->layout(); + const auto fixed_axis = + acl_common::ToARMComputeAxis(rank, axis, frontend_layout, backend_layout).value(); + l->configure(input_tensors, output_alloc->handle(), fixed_axis); + fn = std::move(l); + } + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::FullyConnected &node) +{ + using ir::operation::FullyConnected; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)}; + const auto weight_index{node.getInputs().at(FullyConnected::Input::WEIGHT)}; + const auto bias_index{node.getInputs().at(FullyConnected::Input::BIAS)}; + + const auto input_rank = _ctx.at(input_index).shape().rank(); + + const auto output_size = + _ctx.at(output_index).shape().dim(_ctx.at(output_index).shape().rank() - 1); + UNUSED_RELEASE(output_size); + assert(_ctx.at(bias_index).shape().dim(0) == output_size); + assert(_ctx.at(weight_index).shape().dim(0) == output_size); + const auto batch_size = + _ctx.at(output_index).shape().dim(_ctx.at(output_index).shape().rank() - 2); + const auto input_size = + _ctx.at(weight_index).shape().dim(_ctx.at(weight_index).shape().rank() - 1); + + // Check for reshaping input's shape into rank-2 + bool needs_reshape = false; + ir::Shape reshape(2); + if (input_rank == 3 || input_rank == 4) + { + const auto &ifm_shape = _ctx.at(input_index).shape(); + auto feature_size = 1; + for (int i = 0; i < ifm_shape.rank(); ++i) + { + feature_size *= ifm_shape.dim(i); + } + + UNUSED_RELEASE(feature_size); + assert(feature_size == batch_size * input_size); + + // for reshaping + needs_reshape = true; + reshape.dim(0) = batch_size; /* H */ + reshape.dim(1) = input_size; /* W */ + } + + const auto activation = node.param().activation; + + auto output_alloc = _tensor_builder->at(output_index).get(); + const auto input_alloc = _tensor_builder->at(input_index).get(); + const auto weight_alloc = _tensor_builder->at(weight_index).get(); + const auto bias_alloc = _tensor_builder->at(bias_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto acl_layout = output_alloc->handle()->info()->data_layout(); + + auto fn = std::make_unique( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + arm_compute::CLFullyConnectedReshapingLayer::KernelType kernel_type = + arm_compute::CLFullyConnectedReshapingLayer::KernelType::GENERAL; + if (_ctx.at(weight_index).isConstant()) + { + kernel_type = arm_compute::CLFullyConnectedReshapingLayer::KernelType::PREPROCESSED_WEIGHTS; + assert(_ctx.at(weight_index).data()); + } + fn->configure( + input_alloc->handle(), weight_alloc->handle(), bias_alloc->handle(), output_alloc->handle(), + needs_reshape, + ::onert::backend::acl_common::asTensorShape( + reshape, frontend_layout, ::onert::backend::acl_common::asRuntimeLayout(acl_layout)), + kernel_type); + + _return_fn = std::make_unique( + asAclClFunction(std::move(fn)), + ActivationBuilder::generate(activation, output_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Mul &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Mul::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Mul::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::CLPixelWiseMultiplication>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle(), 1.0, // scale + arm_compute::ConvertPolicy::SATURATE, arm_compute::RoundingPolicy::TO_NEAREST_EVEN); + + _return_fn = std::make_unique( + asAclClFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::ReduceSum &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::ReduceSum::Input::INPUT)}; + const auto &axes{node.param().axes}; + const auto keep_dims{node.param().keep_dims}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = input_alloc->layout(); + + // Convert to ACL axes taking into account negative values and possible duplicates. + std::set acl_axes; + const int input_rank = node.param().rank; + for (int axis : axes) + { + if (axis < 0) + axis += input_rank; + acl_axes.insert( + acl_common::ToARMComputeAxis(input_rank, axis, frontend_layout, backend_layout).value()); + } + + auto fn = std::make_unique<::arm_compute::CLReduceOperation>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + fn->configure(input_alloc->handle(), output_alloc->handle(), acl_axes, keep_dims, + ::arm_compute::ReduceOperation::SUM); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Reshape &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Reshape::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + // NOTE This operation must not be changed the layout from frontend to backend + // So, PermutationOperationPass makes layouts of frontend and backend the same. + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = output_alloc->layout(); + assert((_ctx.at(input_index).shape().rank() < 4 && _ctx.at(output_index).shape().rank() < 4) || + frontend_layout == backend_layout); + UNUSED_RELEASE(frontend_layout); + UNUSED_RELEASE(backend_layout); + + auto fn = std::make_unique<::arm_compute::CLReshapeLayer>(); + + fn->configure(input_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Squeeze &node) +{ + // Squeeze is identical to reshape except that it has an optional dimensions input. + // In addition, optional dims_index is ignored since output tensor already has squeezed shape + // by freezer and toco + // TODO Support multi-layout for frontend and backend + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Squeeze::Input::INPUT)}; + const auto dims{node.param().dims}; + const auto ndim{node.param().ndim}; + (void)dims; + (void)ndim; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + auto fn = std::make_unique(); + fn->configure(input_alloc->handle(), output_alloc->handle()); + auto acl_fn = asAclClFunction(std::move(fn)); + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Tanh &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Tanh::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::TANH, 1.0f, 1.0f}; + + fn->configure(input_alloc->handle(), output_alloc->handle(), act_info); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Softmax &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Softmax::Input::INPUT)}; + + const auto beta = node.param().beta; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::CLSoftmaxLayer>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + fn->configure(input_alloc->handle(), output_alloc->handle(), beta); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Slice &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Slice::Input::INPUT)}; + const auto begins_index{node.getInputs().at(ir::operation::Slice::Input::BEGINS)}; + const auto sizes_index{node.getInputs().at(ir::operation::Slice::Input::SIZES)}; + + auto outputData_alloc = _tensor_builder->at(output_index).get(); + auto inputData_alloc = _tensor_builder->at(input_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = inputData_alloc->layout(); + + // Set initializers for indices data such as order of inputData + int input_rank = node.param().rank; + std::vector starts; + std::vector ends; + starts.resize(input_rank, 0); + ends.resize(input_rank, 0); + { + assert(_ctx.at(begins_index).data()); + assert(_ctx.at(sizes_index).data()); + auto beginData_base = _ctx.at(begins_index).data()->base(); + auto sizeData_base = _ctx.at(sizes_index).data()->base(); + const int beginData_size = _ctx.at(begins_index).shape().num_elements(); + const int sizeData_size = _ctx.at(sizes_index).shape().num_elements(); + + using ir::DataType; + + UNUSED_RELEASE(beginData_size); + UNUSED_RELEASE(sizeData_size); + + assert(_ctx.at(begins_index).typeInfo().type() == DataType::INT32); + assert(_ctx.at(sizes_index).typeInfo().type() == DataType::INT32); + assert(beginData_size == input_rank); + assert(sizeData_size == input_rank); + + assert(beginData_base != nullptr); + for (int n = 0; n < input_rank; ++n) + { + auto axis = ::onert::backend::acl_common::ToARMComputeAxis(input_rank, n, frontend_layout, + backend_layout) + .value(); + + int32_t begin_value = *(reinterpret_cast(beginData_base) + n); + starts[axis] = begin_value; + + int32_t size_value = *(reinterpret_cast(sizeData_base) + n); + ends[axis] = begin_value + size_value; + } + } + + ::arm_compute::Coordinates starts_set; + ::arm_compute::Coordinates ends_set; + + for (size_t i = 0; i < starts.size(); ++i) + { + starts_set.set(i, starts[i]); + ends_set.set(i, ends[i]); + } + + auto fn = std::make_unique<::arm_compute::CLSlice>(); + + fn->configure(inputData_alloc->handle(), outputData_alloc->handle(), starts_set, ends_set); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::StridedSlice &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)}; + const auto starts_index{node.getInputs().at(ir::operation::StridedSlice::Input::STARTS)}; + const auto ends_index{node.getInputs().at(ir::operation::StridedSlice::Input::ENDS)}; + const auto strides_index{node.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)}; + + auto outputData_alloc = _tensor_builder->at(output_index).get(); + auto inputData_alloc = _tensor_builder->at(input_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = inputData_alloc->layout(); + + // Set initializers for indices data such as order of inputData + int input_rank = node.param().rank; + std::vector starts; + std::vector ends; + std::vector strides; + starts.resize(input_rank, 0); + ends.resize(input_rank, 0); + strides.resize(input_rank, 0); + { + assert(_ctx.at(starts_index).data()); + assert(_ctx.at(ends_index).data()); + assert(_ctx.at(strides_index).data()); + auto startData_base = _ctx.at(starts_index).data()->base(); + auto endData_base = _ctx.at(ends_index).data()->base(); + auto stridesData_base = _ctx.at(strides_index).data()->base(); + const int startData_size = _ctx.at(starts_index).shape().num_elements(); + const int endData_size = _ctx.at(ends_index).shape().num_elements(); + const int stridesData_size = _ctx.at(strides_index).shape().num_elements(); + + using ir::DataType; + + UNUSED_RELEASE(startData_size); + UNUSED_RELEASE(endData_size); + UNUSED_RELEASE(stridesData_size); + + assert(_ctx.at(starts_index).typeInfo().type() == DataType::INT32); + assert(_ctx.at(ends_index).typeInfo().type() == DataType::INT32); + assert(_ctx.at(strides_index).typeInfo().type() == DataType::INT32); + assert(startData_size == input_rank); + assert(endData_size == input_rank); + assert(stridesData_size == input_rank); + + assert(startData_base != nullptr); + for (int n = 0; n < input_rank; ++n) + { + auto axis = ::onert::backend::acl_common::ToARMComputeAxis(input_rank, n, frontend_layout, + backend_layout) + .value(); + + int32_t start_value = *(reinterpret_cast(startData_base) + n); + starts[axis] = start_value; + + int32_t end_value = *(reinterpret_cast(endData_base) + n); + ends[axis] = end_value; + + int32_t strides_value = *(reinterpret_cast(stridesData_base) + n); + strides[axis] = strides_value; + } + } + + // Set mask bits such as order of inputData + const auto begin_mask = acl_common::ReorderBits(node.param().begin_mask, input_rank, + frontend_layout, backend_layout); + const auto end_mask = acl_common::ReorderBits(node.param().end_mask, input_rank, + frontend_layout, backend_layout); + const auto shrink_axis_mask = acl_common::ReorderBits( + node.param().shrink_axis_mask, input_rank, frontend_layout, backend_layout); + + ::arm_compute::Coordinates starts_set; + ::arm_compute::Coordinates ends_set; + ::arm_compute::BiStrides strides_set; + + for (size_t i = 0; i < starts.size(); ++i) + { + starts_set.set(i, starts[i]); + ends_set.set(i, ends[i]); + strides_set.set(i, strides[i]); + } + + auto fn = std::make_unique<::arm_compute::CLStridedSlice>(); + + fn->configure(inputData_alloc->handle(), outputData_alloc->handle(), starts_set, ends_set, + strides_set, begin_mask, end_mask, shrink_axis_mask); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Transpose &node) +{ + const auto ofm_idx{node.getOutputs().at(0)}; + const auto ifm_idx{node.getInputs().at(ir::operation::Transpose::Input::INPUT)}; + const auto &perm{node.param().perm}; + + const auto rank = node.param().rank; + + auto ofm_alloc = _tensor_builder->at(ofm_idx).get(); + auto ifm_alloc = _tensor_builder->at(ifm_idx).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + + std::vector pv(perm.cbegin(), perm.cend()); + // Reversed + auto backend_pv = ::onert::backend::acl_common::getARMComputePermutationVector( + rank, pv, frontend_layout, backend_layout); + + auto fn = std::make_unique<::arm_compute::CLPermute>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), backend_pv); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Add &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Add::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Add::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::CLArithmeticAddition>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle(), + arm_compute::ConvertPolicy::SATURATE); + + _return_fn = std::make_unique( + asAclClFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Sub &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Sub::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Sub::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::CLArithmeticSubtraction>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle(), + arm_compute::ConvertPolicy::SATURATE); + + _return_fn = std::make_unique( + asAclClFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Div &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Div::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Div::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::CLArithmeticDivision>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle()); + + _return_fn = std::make_unique( + asAclClFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Exp &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Exp::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::CLExpLayer>(); + + fn->configure(input_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::InstanceNorm &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::InstanceNorm::Input::INPUT)}; + const auto gamma_index{node.getInputs().at(ir::operation::InstanceNorm::Input::GAMMA)}; + const auto beta_index{node.getInputs().at(ir::operation::InstanceNorm::Input::BETA)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto gamma_alloc = _tensor_builder->at(gamma_index).get(); + auto beta_alloc = _tensor_builder->at(beta_index).get(); + auto epsilon = node.param().epsilon; + auto activation = node.param().activation; + + auto fn = std::make_unique<::arm_compute::CLInstanceNormalizationLayerEx>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), gamma_alloc->handle(), + beta_alloc->handle(), epsilon); + + _return_fn = std::make_unique( + asAclClFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Logistic &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Logistic::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LOGISTIC}; + + auto fn = std::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), act_info); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::LogicalAnd &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input0_index{node.getInputs().at(ir::operation::LogicalAnd::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::LogicalAnd::Input::INPUT1)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input0_alloc = _tensor_builder->at(input0_index).get(); + auto input1_alloc = _tensor_builder->at(input1_index).get(); + + auto fn = std::make_unique<::arm_compute::CLBinaryLogicalOp>(); + + fn->configure(input0_alloc->handle(), input1_alloc->handle(), output_alloc->handle(), + ::arm_compute::BinaryLogicalOperation::AND); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::LSTM &node) +{ + // TODO Support dynamic rnn + // TODO Fix subtle error in the case of non-CIFG, non-peephole and No Projection. + const auto scratch_buffer_index{ + node.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)}; + const auto output_state_out_index{ + node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT_STATE_OUT)}; + const auto cell_state_out_index{ + node.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)}; + const auto output_index{node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)}; + + const auto input_index{node.getInputs().at(ir::operation::LSTM::Input::INPUT)}; + const auto input_to_input_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_INPUT_WEIGHTS)}; // optional + const auto input_to_forget_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_FORGET_WEIGHTS)}; + const auto input_to_cell_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_CELL_WEIGHTS)}; + const auto input_to_output_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)}; + const auto recurrent_to_input_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)}; // optional + const auto recurrent_to_forget_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS)}; + const auto recurrent_to_cell_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_CELL_WEIGHTS)}; + const auto recurrent_to_output_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS)}; + const auto cell_to_input_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_INPUT_WEIGHTS)}; // optional + const auto cell_to_forget_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_FORGET_WEIGHTS)}; // optional + const auto cell_to_output_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_OUTPUT_WEIGHTS)}; // optional + const auto input_gate_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_GATE_BIAS)}; + const auto forget_gate_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::FORGET_GATE_BIAS)}; + const auto cell_bias_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_BIAS)}; + const auto output_gate_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_GATE_BIAS)}; + const auto projection_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_WEIGHTS)}; // optional + const auto projection_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_BIAS)}; // optional + const auto output_state_in_index{ + node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_STATE_IN)}; + const auto cell_state_in_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_STATE_IN)}; + const auto cell_threshold = node.param().cell_threshold; + const auto projection_threshold = node.param().projection_threshold; + + bool has_input_to_input_weights = _ctx.at(input_to_input_weights_index).shape().dim(0) != 0 && + _ctx.at(input_to_input_weights_index).shape().dim(1) != 0; + bool has_recurrent_to_input_weights = + _ctx.at(recurrent_to_input_weights_index).shape().dim(0) != 0 && + _ctx.at(recurrent_to_input_weights_index).shape().dim(1) != 0; + bool has_cell_to_forget_weights = _ctx.at(cell_to_forget_weights_index).shape().dim(0) != 0; + bool has_cell_to_output_weights = _ctx.at(cell_to_output_weights_index).shape().dim(0) != 0; + bool has_projection_weights = _ctx.at(projection_weights_index).shape().dim(0) != 0 && + _ctx.at(projection_weights_index).shape().dim(1) != 0; + bool has_projection_bias = _ctx.at(projection_bias_index).shape().dim(0); + + // NOTE The input_to_input_weights and the recurrent_to_input_weights do not exist in CIFG. + // true: no CIFG + // false: CIFG + // NOTE The cell_to_input_weights does not exist in non-peephole although regular LSTM(non-CIFG). + bool has_cifg_param = has_input_to_input_weights && has_recurrent_to_input_weights; + + // NOTE The cell_to_forget_weights and the cell_to_output_weights exist in peephole. + // But the cell_to_input_weights does not exist in regular CIFG although peephole. + // true: peephole + // false: no peephole + bool has_peephole_param = has_cell_to_forget_weights && has_cell_to_output_weights; + + // NOTE Although the projection weights has data the projection bias may not have data. + bool has_projection_param = has_projection_weights; + + const auto activation = node.param().activation; + const auto cell_clip = cell_threshold; + const auto projection_clip = projection_threshold; + assert(cell_clip >= 0.f && projection_clip >= 0.f); + + auto scratch_buffer_alloc = _tensor_builder->at(scratch_buffer_index).get(); + auto output_state_out_alloc = _tensor_builder->at(output_state_out_index).get(); + auto cell_state_out_alloc = _tensor_builder->at(cell_state_out_index).get(); + auto output_alloc = _tensor_builder->at(output_index).get(); + + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto input_to_forget_weights_alloc = _tensor_builder->at(input_to_forget_weights_index).get(); + auto input_to_cell_weights_alloc = _tensor_builder->at(input_to_cell_weights_index).get(); + auto input_to_output_weights_alloc = _tensor_builder->at(input_to_output_weights_index).get(); + auto recurrent_to_forget_weights_alloc = + _tensor_builder->at(recurrent_to_forget_weights_index).get(); + auto recurrent_to_cell_weights_alloc = _tensor_builder->at(recurrent_to_cell_weights_index).get(); + auto recurrent_to_output_weights_alloc = + _tensor_builder->at(recurrent_to_output_weights_index).get(); + + auto forget_gate_bias_alloc = _tensor_builder->at(forget_gate_bias_index).get(); + auto cell_bias_alloc = _tensor_builder->at(cell_bias_index).get(); + auto output_gate_bias_alloc = _tensor_builder->at(output_gate_bias_index).get(); + auto output_state_in_alloc = _tensor_builder->at(output_state_in_index).get(); + auto cell_state_in_alloc = _tensor_builder->at(cell_state_in_index).get(); + + auto act_info = ::onert::backend::acl_common::asActivationLayerInfo(activation); + + auto fn = std::make_unique<::arm_compute::CLLSTMLayer>(); + + ::arm_compute::LSTMParams<::arm_compute::ICLTensor> lstm_params{}; + if (has_cifg_param) + { + auto input_to_input_weights_alloc = + _tensor_builder->at(input_to_input_weights_index).get(); // optional + auto recurrent_to_input_weights_alloc = + _tensor_builder->at(recurrent_to_input_weights_index).get(); // optional + auto cell_to_input_weights_handle = + has_peephole_param ? _tensor_builder->at(cell_to_input_weights_index).get()->handle() + : nullptr; // optional (non-cifg && peephole) + auto input_gate_bias_alloc = _tensor_builder->at(input_gate_bias_index).get(); // optional + lstm_params.set_cifg_params(input_to_input_weights_alloc->handle(), + recurrent_to_input_weights_alloc->handle(), + cell_to_input_weights_handle, input_gate_bias_alloc->handle()); + } + if (has_peephole_param) + { + auto cell_to_forget_weights_alloc = + _tensor_builder->at(cell_to_forget_weights_index).get(); // optional + auto cell_to_output_weights_alloc = + _tensor_builder->at(cell_to_output_weights_index).get(); // optional + lstm_params.set_peephole_params(cell_to_forget_weights_alloc->handle(), + cell_to_output_weights_alloc->handle()); + } + if (has_projection_param) + { + auto projection_weights_alloc = _tensor_builder->at(projection_weights_index).get(); // optional + auto projection_bias_handle = has_projection_bias + ? _tensor_builder->at(projection_bias_index).get()->handle() + : nullptr; // optional + lstm_params.set_projection_params(projection_weights_alloc->handle(), projection_bias_handle); + } + + fn->configure( + input_alloc->handle(), input_to_forget_weights_alloc->handle(), + input_to_cell_weights_alloc->handle(), input_to_output_weights_alloc->handle(), + recurrent_to_forget_weights_alloc->handle(), recurrent_to_cell_weights_alloc->handle(), + recurrent_to_output_weights_alloc->handle(), forget_gate_bias_alloc->handle(), + cell_bias_alloc->handle(), output_gate_bias_alloc->handle(), output_state_in_alloc->handle(), + cell_state_in_alloc->handle(), scratch_buffer_alloc->handle(), + output_state_out_alloc->handle(), cell_state_out_alloc->handle(), output_alloc->handle(), + lstm_params, act_info, cell_clip, projection_clip); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReduceMax &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::ReduceMax::Input::INPUT)}; + const auto &axes{node.param().axes}; + const auto keep_dims{node.param().keep_dims}; + + auto ofm_alloc = _tensor_builder->at(output_index).get(); + auto ifm_alloc = _tensor_builder->at(input_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + + // Convert to ACL axes taking into account negative values and possible duplicates. + std::set acl_axes; + const int ifm_rank = node.param().rank; + for (int axis : axes) + { + if (axis < 0) + axis += ifm_rank; + acl_axes.insert( + acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value()); + } + + auto fn = std::make_unique<::arm_compute::CLReduceOperation>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), acl_axes, keep_dims, + arm_compute::ReduceOperation::MAX); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Comparison &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input0_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)}; + + const auto comparison_type = node.param().comparison_type; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input0_alloc = _tensor_builder->at(input0_index).get(); + auto input1_alloc = _tensor_builder->at(input1_index).get(); + + auto fn = std::make_unique<::arm_compute::CLComparison>(); + + fn->configure(input0_alloc->handle(), input1_alloc->handle(), output_alloc->handle(), + (arm_compute::ComparisonOperation)comparison_type); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Pack &node) +{ + const auto output_index{node.getOutputs().at(0)}; + auto axis{node.param().axis}; + + const auto output_rank = node.param().rank; + + std::vector input_indexes; + for (const auto &input_index : node.getInputs()) + input_indexes.emplace_back(input_index); + + auto output = _tensor_builder->at(output_index).get()->handle(); + std::vector inputs; + for (const auto &input_index : input_indexes) + inputs.emplace_back(_tensor_builder->at(input_index)->handle()); + + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = _tensor_builder->at(output_index).get()->layout(); + + if (axis < 0) + axis += output_rank; + axis = acl_common::ToARMComputeAxis(output_rank, axis, frontend_layout, backend_layout).value(); + + auto fn = std::make_unique<::arm_compute::CLStackLayer>(); + + fn->configure(inputs, axis, output); + + _return_fn = asAclClFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Permute &node) +{ + const auto ofm_idx{node.getOutputs().at(0)}; + const auto ifm_idx{node.getInputs().at(0)}; + const auto permute_type = node.getPermuteType(); + auto ofm_alloc = _tensor_builder->at(ofm_idx).get(); + auto ifm_alloc = _tensor_builder->at(ifm_idx).get(); + const auto rank = _ctx.at(ofm_idx).shape().rank(); + assert(_ctx.at(ifm_idx).shape().rank() == _ctx.at(ofm_idx).shape().rank()); + + std::unique_ptr<::arm_compute::IFunction> fn; + arm_compute::PermutationVector pv; + if (permute_type == ir::operation::Permute::Type::NCHW_TO_NHWC && rank == 4) + { + // WHCN -> CWHN + pv = arm_compute::PermutationVector{2, 0, 1}; + + auto l = std::make_unique<::arm_compute::CLPermute>(); + + l->configure(ifm_alloc->handle(), ofm_alloc->handle(), pv); + + fn = std::move(l); + } + else if (permute_type == ir::operation::Permute::Type::NHWC_TO_NCHW && rank == 4) + { + // CWHN -> WHCN + pv = arm_compute::PermutationVector{1, 2, 0}; + + auto l = std::make_unique<::arm_compute::CLPermute>(); + + l->configure(ifm_alloc->handle(), ofm_alloc->handle(), pv); + + fn = std::move(l); + } + else + { + auto l = std::make_unique<::arm_compute::CLCopy>(); + + l->configure(ifm_alloc->handle(), ofm_alloc->handle()); + + fn = std::move(l); + } + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::RSQRT &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::RSQRT::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::CLRsqrtLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle()); + + _return_fn = asAclClFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::ReLU &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::ReLU::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU}; + + fn->configure(input_alloc->handle(), output_alloc->handle(), act_info); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ResizeBilinear &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + + const auto ifm_index{node.getInputs().at(ir::operation::ResizeBilinear::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::CLScale>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), + ::arm_compute::InterpolationPolicy::BILINEAR, ::arm_compute::BorderMode::REPLICATE, + ::arm_compute::PixelValue(0.f), ::arm_compute::SamplingPolicy::TOP_LEFT); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReLU1 &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ReLU1::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f}; + + auto fn = std::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), act_info); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReLU6 &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ReLU6::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.0f}; + + auto fn = std::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), act_info); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::RNN &node) +{ + const auto output_index{node.getOutputs().at(ir::operation::RNN::Output::OUTPUT)}; + const auto hidden_state_out_index{ + node.getOutputs().at(ir::operation::RNN::Output::HIDDEN_STATE_OUT)}; + + const auto input_index{node.getInputs().at(ir::operation::RNN::Input::INPUT)}; + const auto weights_index{node.getInputs().at(ir::operation::RNN::Input::WEIGHTS)}; + const auto recurrent_weights_index{ + node.getInputs().at(ir::operation::RNN::Input::RECURRENT_WEIGHTS)}; + const auto bias_index{node.getInputs().at(ir::operation::RNN::Input::BIAS)}; + const auto hidden_state_in_index{node.getInputs().at(ir::operation::RNN::Input::HIDDEN_STATE_IN)}; + + const auto activation = node.param().activation; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto hidden_state_out_alloc = _tensor_builder->at(hidden_state_out_index).get(); + + auto input_alloc = _tensor_builder->at(input_index).get(); + auto weights_alloc = _tensor_builder->at(weights_index).get(); + auto recurrent_weights_alloc = _tensor_builder->at(recurrent_weights_index).get(); + auto bias_alloc = _tensor_builder->at(bias_index).get(); + auto hidden_state_in_alloc = _tensor_builder->at(hidden_state_in_index).get(); + auto act_info = ::onert::backend::acl_common::asActivationLayerInfo(activation); + + auto copy_layer = std::make_unique<::arm_compute::CLCopy>(); + copy_layer->configure(hidden_state_in_alloc->handle(), hidden_state_out_alloc->handle()); + _return_fn = asAclClFunction(std::move(copy_layer)); + + auto fn = std::make_unique<::arm_compute::CLRNNLayerEx>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + fn->configure(input_alloc->handle(), weights_alloc->handle(), recurrent_weights_alloc->handle(), + bias_alloc->handle(), hidden_state_out_alloc->handle(), output_alloc->handle(), + act_info); + _return_fn = asAclClFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Floor &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Floor::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::CLFloor>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::SpaceToBatchND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)}; + const auto block_size_index{ + node.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)}; + const auto paddings_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto block_size_alloc = _tensor_builder->at(block_size_index).get(); + auto paddings_alloc = _tensor_builder->at(paddings_index).get(); + + assert(_ctx.at(block_size_index).data()); + assert(_ctx.at(paddings_index).data()); + + std::unique_ptr<::arm_compute::IFunction> fn; + if (_ctx.at(ofm_index).typeInfo().type() == ir::DataType::QUANT8_ASYMM) + { + // NOTE CLSpaceToBatchLayer has a bug that padding's values are 0 even when zero point of + // QASYMM8 is not 0. + auto l = std::make_unique<::arm_compute::CLSpaceToBatchND>(); + l->configure(ifm_alloc->handle(), block_size_alloc->handle(), paddings_alloc->handle(), + ofm_alloc->handle()); + fn = std::move(l); + } + else + { + auto l = std::make_unique<::arm_compute::CLSpaceToBatchLayer>(); + l->configure(ifm_alloc->handle(), block_size_alloc->handle(), paddings_alloc->handle(), + ofm_alloc->handle()); + fn = std::move(l); + } + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::SpaceToDepth &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::SpaceToDepth::Input::INPUT)}; + + auto block_size = node.param().block_size; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::CLSpaceToDepth>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), block_size); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::L2Pool2D &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::L2Pool2D::Input::INPUT)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + + uint32_t kw = node.param().kw; + uint32_t kh = node.param().kh; + const auto stride = node.param().stride; + const auto padding = + ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh); + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + ::arm_compute::PoolingLayerInfo info{ + ::arm_compute::PoolingType::L2, ::arm_compute::Size2D{kw, kh}, + ::onert::backend::acl_common::asPadStrideInfo(padding, stride)}; + + auto fn = std::make_unique<::arm_compute::CLPoolingLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info); + + _return_fn = std::make_unique( + asAclClFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::EmbeddingLookup &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto lookups_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::LOOKUPS)}; + const auto values_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::VALUES)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto lookups_alloc = _tensor_builder->at(lookups_index).get(); + auto values_alloc = _tensor_builder->at(values_index).get(); + + auto fn = std::make_unique<::arm_compute::CLEmbeddingLookup>(); + + fn->configure(values_alloc->handle(), output_alloc->handle(), lookups_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::L2Normalization &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::L2Normalization::Input::INPUT)}; + + // {CL|Neon}L2Normalization performs the reduction only along dimension 0 + // L2 Normalization always performs the reduction along the depth axis + // Thus, we repurpose {CL|Neon}NormalizationLayers to act as depthwise L2 normalizations by + // choosing normalization parameters as below + + const auto &ifm_shape = _ctx.at(ifm_index).shape(); + // TODO Support optional constant dimension that normalization would be performed on + const auto normalization_axis = node.param().rank - 1; + int32_t radius = + 2 * ifm_shape.dim(normalization_axis) + 1; // normSize = depth(last dimension) * 2 + 1 + float alpha = 1.0f; // In the implementation to make alpha_ become 1 + float beta = 0.5f; // pow(reduction, -0.5) = 1 / sqrt(reduction) + float bias = 0.0f; // Don't offset the reduction. + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const auto norm_info = ::arm_compute::NormalizationLayerInfo(::arm_compute::NormType::CROSS_MAP, + radius, alpha, beta, bias, false); + + auto fn = std::make_unique<::arm_compute::CLNormalizationLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), norm_info); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::HashtableLookup &node) +{ + const auto output_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::OUTPUT)}; + const auto hits_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::HITS)}; + + const auto lookups_index{node.getInputs().at(ir::operation::HashtableLookup::Input::LOOKUPS)}; + const auto keys_index{node.getInputs().at(ir::operation::HashtableLookup::Input::KEYS)}; + const auto values_index{node.getInputs().at(ir::operation::HashtableLookup::Input::VALUES)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto hits_alloc = _tensor_builder->at(hits_index).get(); + + auto lookups_alloc = _tensor_builder->at(lookups_index).get(); + auto keys_alloc = _tensor_builder->at(keys_index).get(); + auto values_alloc = _tensor_builder->at(values_index).get(); + + auto fn = std::make_unique<::arm_compute::CLHashtableLookup>(); + + fn->configure(lookups_alloc->handle(), keys_alloc->handle(), values_alloc->handle(), + output_alloc->handle(), hits_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::PReLU &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::PReLU::Input::INPUT)}; + const auto alpha_index{node.getInputs().at(ir::operation::PReLU::Input::ALPHA)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto alpha_alloc = _tensor_builder->at(alpha_index).get(); + + auto fn = std::make_unique<::arm_compute::CLPReLU>(); + + fn->configure(ifm_alloc->handle(), alpha_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::TransposeConv &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ker_index{node.getInputs().at(ir::operation::TransposeConv::Input::KERNEL)}; + const auto ifm_index{node.getInputs().at(ir::operation::TransposeConv::Input::INPUT)}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ker_shape = _ctx.at(ker_index).shape().asFeature(_current_op_seq_layout); + + const auto stride = node.param().stride; + + assert((node.param().padding.type == ir::PaddingType::SAME) || + (node.param().padding.type == ir::PaddingType::VALID)); + auto padding = ir::calculatePadding(node.param().padding, ofm_shape, ifm_shape, stride, + ker_shape.W, ker_shape.H); + + uint32_t invalid_horizontal = 0; + uint32_t invalid_vertical = 0; + if (node.param().padding.type == ir::PaddingType::VALID) + { + invalid_horizontal = + ofm_shape.W - (1 + (ifm_shape.W - 1) * stride.horizontal) - (ker_shape.W - 1); + invalid_vertical = ofm_shape.H - (1 + (ifm_shape.H - 1) * stride.vertical) - (ker_shape.H - 1); + } + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto ker_alloc = _tensor_builder->at(ker_index).get(); + + const auto tconv_info = acl_common::asPadStrideInfo(padding, stride); + + auto fn = std::make_unique<::arm_compute::CLTransposeConvLayer>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + fn->configure(ifm_alloc->handle(), ker_alloc->handle(), nullptr, ofm_alloc->handle(), tconv_info, + invalid_horizontal, invalid_vertical); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::SQRT &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::SQRT::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::SQRT}; + + auto fn = std::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(input_alloc->handle(), output_alloc->handle(), act_info); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::LogicalOr &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input0_index{node.getInputs().at(ir::operation::LogicalOr::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::LogicalOr::Input::INPUT1)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input0_alloc = _tensor_builder->at(input0_index).get(); + auto input1_alloc = _tensor_builder->at(input1_index).get(); + + auto fn = std::make_unique<::arm_compute::CLBitwiseOr>(); + + fn->configure(input0_alloc->handle(), input1_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::LogicalNot &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::LogicalNot::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::CLBitwiseNot>(); + + fn->configure(input_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::SquaredDifference &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::RHS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::CLElementwiseSquaredDiff>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::TopKV2 &node) +{ + const auto outputValues_index{node.getOutputs().at(ir::operation::TopKV2::Output::OUTPUT_VALUES)}; + const auto outputIndices_index{ + node.getOutputs().at(ir::operation::TopKV2::Output::OUTPUT_INDICES)}; + + const auto inputData_index{node.getInputs().at(ir::operation::TopKV2::Input::INPUT)}; + + // Currently, we only support the vector input. + assert(_ctx.at(inputData_index).shape().rank() == 1 || + _ctx.at(inputData_index).shape().rank() == 2); + + const auto k = node.param().k; + + auto values_alloc = _tensor_builder->at(outputValues_index).get(); + auto indices_alloc = _tensor_builder->at(outputIndices_index).get(); + auto input_alloc = _tensor_builder->at(inputData_index).get(); + + auto fn = std::make_unique<::arm_compute::CLTopKV2>(); + + fn->configure(input_alloc->handle(), k, values_alloc->handle(), indices_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Gather &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + + const auto ifm_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)}; + const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + + const auto ifm_rank = node.param().rank; + const auto axis_raw = node.param().axis; + const auto axis_value = (axis_raw < 0 ? (ifm_rank + axis_raw) : axis_raw); + const int axis = ::onert::backend::acl_common::ToARMComputeAxis(ifm_rank, axis_value).value(); + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto indices_alloc = _tensor_builder->at(indices_index).get(); + + // NOTE The frontend layout and backend layout must be the same for this operation. + // If not the same, we have to add a stage(?) to perform permutation of output tensor. It + // is not not efficient even if it works well. If so, it would be better to set the + // layout of these backend tensors to the same layout. + // There is also one thing we have to think about. This operation depends on the layout of + // a model. For example, if a model in NHWC has this operation as output rank == 4, indices + // rank == 2 and axis == 2, this operation should work as the axis W and C, but the axis W + // and C are not sequential in NCHW. So the backend in NCHW cannot handle this case. + const auto backend_layout = ofm_alloc->layout(); + UNUSED_RELEASE(backend_layout); + assert(backend_layout == ifm_alloc->layout()); + assert(backend_layout == indices_alloc->layout()); + assert(ifm_rank < 4 || _current_op_seq_layout == backend_layout); + + auto fn = std::make_unique<::arm_compute::CLGatherEx>(); + + fn->configure(ifm_alloc->handle(), indices_alloc->handle(), ofm_alloc->handle(), axis); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Neg &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Neg::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::CLNeg>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Abs &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Abs::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::ABS}; + + auto fn = std::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(input_alloc->handle(), output_alloc->handle(), act_info); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ArgMax &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ArgMax::Input::INPUT)}; + + auto ifm_shape = _ctx.at(ifm_index).shape(); + auto ofm_shape = _ctx.at(ofm_index).shape(); + + assert((ifm_shape.rank() - 1) == ofm_shape.rank()); + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + const auto ifm_rank = node.param().rank; + auto frontend_layout = _current_op_seq_layout; + auto backend_layout = ifm_alloc->layout(); + + int axis_value = node.param().axis; + if (axis_value < 0) + { + axis_value += ifm_rank; + } + + auto acl_axis = + acl_common::ToARMComputeAxis(ifm_rank, axis_value, frontend_layout, backend_layout).value(); + + auto fn = std::make_unique<::arm_compute::CLArgOperation>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), {acl_axis}, + ::arm_compute::ArgOperation::MAX); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Dequantize &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Dequantize::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::CLCast>(); + + fn->configure(input_alloc->handle(), output_alloc->handle(), arm_compute::SubDataType::NONE); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Mean &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Mean::Input::INPUT)}; + const auto &axes{node.param().axes}; + const auto keep_dims{node.param().keep_dims}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + + // Convert to ACL axes taking into account negative values and possible duplicates. + std::set acl_axes; + const int ifm_rank = node.param().rank; + for (int axis : axes) + { + if (axis < 0) + axis += ifm_rank; + acl_axes.insert( + acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value()); + } + + arm_compute::Coordinates reduce_axes; + for (const auto axis : acl_axes) + { + reduce_axes.set(reduce_axes.num_dimensions(), axis); + } + + auto fn = std::make_unique<::arm_compute::CLReduceMean>(); + + fn->configure(ifm_alloc->handle(), reduce_axes, keep_dims, ofm_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::LocalResponseNormalization &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{ + node.getInputs().at(ir::operation::LocalResponseNormalization::Input::INPUT)}; + + auto radius = node.param().radius; + auto alpha = node.param().alpha; + auto beta = node.param().beta; + auto bias = node.param().bias; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const auto norm_info = ::arm_compute::NormalizationLayerInfo( + ::arm_compute::NormType::CROSS_MAP, radius * 2 + 1, alpha, beta, bias, false); + + auto fn = std::make_unique<::arm_compute::CLNormalizationLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), norm_info); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::DepthToSpace &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::DepthToSpace::Input::INPUT)}; + + auto block_size = node.param().block_size; + assert(block_size > 0); + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::CLDepthToSpace>(); + + fn->configure(input_alloc->handle(), output_alloc->handle(), block_size); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReduceMin &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ReduceMin::Input::INPUT)}; + const auto &axes{node.param().axes}; + const auto keep_dims{node.param().keep_dims}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + + // Convert to ACL axes taking into account negative values and possible duplicates. + std::set acl_axes; + const int ifm_rank = node.param().rank; + for (int axis : axes) + { + if (axis < 0) + axis += ifm_rank; + acl_axes.insert( + acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value()); + } + + auto fn = std::make_unique<::arm_compute::CLReduceOperation>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), acl_axes, keep_dims, + ::arm_compute::ReduceOperation::MIN); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Split &node) +{ + const auto ifm_index{node.getInputs().at(ir::operation::Split::Input::INPUT)}; + + assert(node.param().num_splits == static_cast(node.getOutputs().size())); + + const auto ifm_rank = node.param().rank; + std::vector output_indexes; + for (const auto &output : node.getOutputs()) + output_indexes.emplace_back(output); + + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + std::vector output_allocs; + for (const auto &ofm_ind : output_indexes) + output_allocs.emplace_back(_tensor_builder->at(ofm_ind).get()->handle()); + + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + auto axis = node.param().axis; + if (axis < 0) + axis += ifm_rank; + axis = acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value(); + + auto fn = std::make_unique<::arm_compute::CLSplit>(); + + fn->configure(ifm_alloc->handle(), output_allocs, axis); + + _return_fn = asAclClFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Unpack &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Unpack::Input::INPUT)}; + auto axis{node.param().axis}; + + const auto input_rank = node.param().rank; + + std::vector output_indexes; + for (const auto &output_index : node.getOutputs()) + output_indexes.emplace_back(output_index); + + auto input = _tensor_builder->at(input_index).get()->handle(); + std::vector outputs; + for (const auto &output_index : output_indexes) + outputs.emplace_back(_tensor_builder->at(output_index)->handle()); + + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = _tensor_builder->at(input_index).get()->layout(); + if (axis < 0) + axis += input_rank; + axis = acl_common::ToARMComputeAxis(input_rank, axis, frontend_layout, backend_layout).value(); + + auto fn = std::make_unique<::arm_compute::CLUnstack>(); + + fn->configure(input, outputs, axis); + + _return_fn = asAclClFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Pad &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)}; + const auto pad_index{node.getInputs().at(ir::operation::Pad::Input::PAD)}; + const auto output_index{node.getOutputs().at(0)}; + assert(_ctx.at(pad_index).data()); + + auto rank = node.param().rank; + auto pad_base = _ctx.at(pad_index).data()->base(); + + auto input_type = _ctx.at(input_index).typeInfo(); + auto data_type = acl_common::asDataType(input_type.type()); + auto quant_info = ::arm_compute::QuantizationInfo(input_type.scale(), input_type.offset()); + const auto pixel_value = ::arm_compute::PixelValue(0, data_type, quant_info); + + auto input = _tensor_builder->at(input_index).get()->handle(); + auto output = _tensor_builder->at(output_index).get()->handle(); + + ::arm_compute::PaddingList padding_list; + padding_list.resize(rank); + for (int32_t n = 0; n < rank; ++n) + { + const int32_t *from = reinterpret_cast(pad_base) + (n * 2); + + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = _tensor_builder->at(input_index).get()->layout(); + const auto axis = + acl_common::ToARMComputeAxis(rank, n, frontend_layout, backend_layout).value(); + padding_list[axis] = ::arm_compute::PaddingInfo{from[0], from[1]}; + } + auto fn = std::make_unique<::arm_compute::CLPadLayer>(); + fn->configure(input, output, padding_list, pixel_value); + + _return_fn = asAclClFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Min &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Min::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Min::Input::RHS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::CLElementwiseMin>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Max &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Max::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Max::Input::RHS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::CLElementwiseMax>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclClFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +} // namespace acl_cl +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_cl/KernelGenerator.h b/runtime/onert/backend/acl_cl/KernelGenerator.h new file mode 100644 index 000000000..c7e1a2178 --- /dev/null +++ b/runtime/onert/backend/acl_cl/KernelGenerator.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_KERNEL_GENERATOR_H__ +#define __ONERT_BACKEND_ACL_CL_KERNEL_GENERATOR_H__ + +#include + +#include "ir/Operands.h" +#include "TensorBuilder.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +class KernelGenerator : public IKernelGenerator +{ +public: + KernelGenerator(const ir::Operands &ctx, const std::shared_ptr &tensor_builder); + + void visit(const ir::OpSequence &) override; + void visit(const ir::operation::BatchToSpaceND &) override; + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::MaxPool2D &) override; + void visit(const ir::operation::AvgPool2D &) override; + void visit(const ir::operation::Concat &) override; + void visit(const ir::operation::FullyConnected &) override; + void visit(const ir::operation::Mul &) override; + void visit(const ir::operation::ReduceSum &) override; + void visit(const ir::operation::Reshape &) override; + void visit(const ir::operation::Squeeze &) override; + void visit(const ir::operation::Tanh &) override; + void visit(const ir::operation::Softmax &) override; + void visit(const ir::operation::Slice &) override; + void visit(const ir::operation::StridedSlice &) override; + void visit(const ir::operation::Transpose &) override; + void visit(const ir::operation::Add &) override; + void visit(const ir::operation::Sub &) override; + void visit(const ir::operation::Cast &) override; + void visit(const ir::operation::Div &) override; + void visit(const ir::operation::Exp &) override; + void visit(const ir::operation::InstanceNorm &) override; + void visit(const ir::operation::Logistic &) override; + void visit(const ir::operation::ReduceMax &) override; + void visit(const ir::operation::Comparison &) override; + void visit(const ir::operation::LogicalAnd &) override; + void visit(const ir::operation::LSTM &) override; + void visit(const ir::operation::Pack &) override; + void visit(const ir::operation::Permute &) override; + void visit(const ir::operation::RSQRT &) override; + void visit(const ir::operation::ReLU &) override; + void visit(const ir::operation::ResizeBilinear &) override; + void visit(const ir::operation::ReLU1 &) override; + void visit(const ir::operation::ReLU6 &) override; + void visit(const ir::operation::RNN &) override; + void visit(const ir::operation::Floor &) override; + void visit(const ir::operation::SpaceToBatchND &) override; + void visit(const ir::operation::SpaceToDepth &) override; + void visit(const ir::operation::L2Pool2D &) override; + void visit(const ir::operation::EmbeddingLookup &) override; + void visit(const ir::operation::L2Normalization &) override; + void visit(const ir::operation::HashtableLookup &) override; + void visit(const ir::operation::PReLU &) override; + void visit(const ir::operation::TransposeConv &) override; + void visit(const ir::operation::SQRT &) override; + void visit(const ir::operation::LogicalOr &) override; + void visit(const ir::operation::LogicalNot &) override; + void visit(const ir::operation::SquaredDifference &) override; + void visit(const ir::operation::TopKV2 &) override; + void visit(const ir::operation::Gather &) override; + void visit(const ir::operation::Neg &) override; + void visit(const ir::operation::Abs &) override; + void visit(const ir::operation::ArgMax &) override; + void visit(const ir::operation::Dequantize &) override; + void visit(const ir::operation::Mean &) override; + void visit(const ir::operation::LocalResponseNormalization &) override; + void visit(const ir::operation::DepthToSpace &) override; + void visit(const ir::operation::ReduceMin &) override; + void visit(const ir::operation::Split &) override; + void visit(const ir::operation::Unpack &) override; + void visit(const ir::operation::Pad &) override; + void visit(const ir::operation::Min &) override; + void visit(const ir::operation::Max &) override; + +private: + const ir::Operands &_ctx; + std::shared_ptr _tensor_builder; + ir::Layout _current_op_seq_layout; +}; + +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_KERNEL_GENERATOR_H__ diff --git a/runtime/onert/backend/acl_cl/Optimizer.cc b/runtime/onert/backend/acl_cl/Optimizer.cc new file mode 100644 index 000000000..6ba3143e8 --- /dev/null +++ b/runtime/onert/backend/acl_cl/Optimizer.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Optimizer.h" + +#include "ParentInfo.h" + +#include +#include +#include +#include "AclSubTensorAnalyzer.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +Optimizer::Optimizer(BackendContext *context) + : _context{context}, + _tensor_builder{std::dynamic_pointer_cast(context->tensor_builder)} +{ + assert(context); +} + +void Optimizer::optimize() +{ + // Concat elimination (build subtensor info) + { + acl_common::AclSubTensorAnalyzer sa{*_context->graph()}; + for (auto op_info : _context->operation_list()) + { + auto &op = _context->graph()->operations().at(op_info.index); + sa.setLayout(op_info.layout); + op.accept(sa); + } + + _tensor_builder->parent_map(sa.releaseParentMap()); + } +} + +} // namespace acl_cl +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_cl/Optimizer.h b/runtime/onert/backend/acl_cl/Optimizer.h new file mode 100644 index 000000000..18d38ec1b --- /dev/null +++ b/runtime/onert/backend/acl_cl/Optimizer.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_OPTIMIZER_H__ +#define __ONERT_BACKEND_ACL_CL_OPTIMIZER_H__ + +#include +#include +#include "TensorBuilder.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +class Optimizer : public IOptimizer +{ +public: + Optimizer(BackendContext *context); + + void optimize() override; + +private: + BackendContext *_context; + std::shared_ptr _tensor_builder; +}; + +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_OPTIMIZER_H__ diff --git a/runtime/onert/backend/acl_cl/ShapeFixer.cc b/runtime/onert/backend/acl_cl/ShapeFixer.cc new file mode 100644 index 000000000..d73cf151d --- /dev/null +++ b/runtime/onert/backend/acl_cl/ShapeFixer.cc @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ShapeFixer.h" + +#include // Include all ARM Compute CL functions +#include // Include all ARM Compute EX CL functions + +#include +#include +#include + +#include "ir/Index.h" +#include "exec/NopFunction.h" +#include "util/logging.h" +#include "util/Utils.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +using ::onert::backend::acl_common::asAclFunction; + +ShapeFixer::ShapeFixer(const ir::Operands &ctx, + const std::shared_ptr &tensor_builder) + : _ctx(ctx), _tensor_builder(tensor_builder) +{ + assert(tensor_builder); +} + +void ShapeFixer::visit(const ir::operation::BatchToSpaceND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::BatchToSpaceND::Input::INPUT)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); +} + +void ShapeFixer::visit(const ir::operation::Cast &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Conv2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::DepthwiseConv2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::MaxPool2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::AvgPool2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Concat &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + _tensor_builder->dimCorrection(ofm_index, false); + for (const auto &input : node.getInputs()) + _tensor_builder->dimCorrection(input, false); +} + +void ShapeFixer::visit(const ir::operation::FullyConnected &node) +{ + using ir::operation::FullyConnected; + const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)}; + const auto input_rank = _ctx.at(input_index).shape().rank(); + // Check for reshaping input's shape into rank-2 + if (input_rank == 3 || input_rank == 4) + _tensor_builder->dimCorrection(input_index, false); +} + +void ShapeFixer::visit(const ir::operation::Mul &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Mul::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Mul::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::ReduceSum &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Reshape &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Reshape::Input::INPUT)}; + _tensor_builder->dimCorrection(input_index, false); + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::Squeeze &node) +{ + const auto output_index{node.getOutputs().at(0)}; + if (_ctx.at(output_index).shape().rank() == 0) + const_cast(_ctx.at(output_index).shape()).extendRank(1); + const auto input_index{node.getInputs().at(ir::operation::Squeeze::Input::INPUT)}; + _tensor_builder->dimCorrection(input_index, false); + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::Tanh &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Softmax &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Slice &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::StridedSlice &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); +} + +void ShapeFixer::visit(const ir::operation::Transpose &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Add &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Add::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Add::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Sub &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Sub::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Sub::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Div &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Div::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Div::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Exp &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::InstanceNorm &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Logistic &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::LogicalAnd &node) +{ + const auto input0_index{node.getInputs().at(ir::operation::LogicalAnd::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::LogicalAnd::Input::INPUT1)}; + + if (!(_ctx.at(input0_index).shape() == _ctx.at(input1_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input0_index).shape().rank(), _ctx.at(input1_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(input0_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(input1_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::LSTM &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReduceMax &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Comparison &node) +{ + const auto input0_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)}; + + if (!(_ctx.at(input0_index).shape() == _ctx.at(input1_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input0_index).shape().rank(), _ctx.at(input1_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(input0_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(input1_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Pack &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + _tensor_builder->dimCorrection(ofm_index, false); + for (const auto &inputs : node.getInputs()) + { + _tensor_builder->dimCorrection(inputs, false); + const auto ofm_rank = _ctx.at(ofm_index).shape().rank(); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(inputs).shape()).extendRank(ofm_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Permute &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::RSQRT &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReLU &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ResizeBilinear &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReLU1 &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReLU6 &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::RNN &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Floor &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::SpaceToBatchND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); +} + +void ShapeFixer::visit(const ir::operation::SpaceToDepth &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::SpaceToDepth::Input::INPUT)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); +} + +void ShapeFixer::visit(const ir::operation::L2Pool2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::EmbeddingLookup &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto values_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::VALUES)}; + _tensor_builder->dimCorrection(values_index, false); + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::L2Normalization &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::HashtableLookup &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::PReLU &node) +{ + const auto ifm_index{node.getInputs().at(ir::operation::PReLU::Input::INPUT)}; + const auto alpha_index{node.getInputs().at(ir::operation::PReLU::Input::ALPHA)}; + + if (!(_ctx.at(ifm_index).shape() == _ctx.at(alpha_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(ifm_index).shape().rank(), _ctx.at(alpha_index).shape().rank()); + const_cast(_ctx.at(ifm_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(alpha_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::TransposeConv &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::SQRT &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::LogicalOr &node) +{ + const auto input0_index{node.getInputs().at(ir::operation::LogicalOr::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::LogicalOr::Input::INPUT1)}; + + if (!(_ctx.at(input0_index).shape() == _ctx.at(input1_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input0_index).shape().rank(), _ctx.at(input1_index).shape().rank()); + const_cast(_ctx.at(input0_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(input1_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::LogicalNot &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::SquaredDifference &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::TopKV2 &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Gather &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)}; + const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); + _tensor_builder->dimCorrection(indices_index, false); +} + +void ShapeFixer::visit(const ir::operation::Neg &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Abs &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ArgMax &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ArgMax::Input::INPUT)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); +} + +void ShapeFixer::visit(const ir::operation::Dequantize &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Mean &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::LocalResponseNormalization &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::DepthToSpace &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReduceMin &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Split &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Split::Input::INPUT)}; + _tensor_builder->dimCorrection(input_index, false); + for (const auto &output : node.getOutputs()) + _tensor_builder->dimCorrection(output, false); +} + +void ShapeFixer::visit(const ir::operation::Unpack &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Unpack::Input::INPUT)}; + _tensor_builder->dimCorrection(input_index, false); + for (const auto &output_index : node.getOutputs()) + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::Pad &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)}; + const auto output_index{node.getOutputs().at(0)}; + _tensor_builder->dimCorrection(input_index, false); + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::Min &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Min::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Min::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Max &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Max::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Max::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +} // namespace acl_cl +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_cl/ShapeFixer.h b/runtime/onert/backend/acl_cl/ShapeFixer.h new file mode 100644 index 000000000..5b3e9b248 --- /dev/null +++ b/runtime/onert/backend/acl_cl/ShapeFixer.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_SHAPE_FIXER_H__ +#define __ONERT_BACKEND_ACL_CL_SHAPE_FIXER_H__ + +#include + +#include "ir/Operands.h" +#include "TensorBuilder.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +class ShapeFixer : public IShapeFixer +{ +public: + ShapeFixer(const ir::Operands &ctx, const std::shared_ptr &tensor_builder); + + void visit(const ir::operation::BatchToSpaceND &) override; + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::MaxPool2D &) override; + void visit(const ir::operation::AvgPool2D &) override; + void visit(const ir::operation::Concat &) override; + void visit(const ir::operation::FullyConnected &) override; + void visit(const ir::operation::Mul &) override; + void visit(const ir::operation::ReduceSum &) override; + void visit(const ir::operation::Reshape &) override; + void visit(const ir::operation::Squeeze &) override; + void visit(const ir::operation::Tanh &) override; + void visit(const ir::operation::Softmax &) override; + void visit(const ir::operation::Slice &) override; + void visit(const ir::operation::StridedSlice &) override; + void visit(const ir::operation::Transpose &) override; + void visit(const ir::operation::Add &) override; + void visit(const ir::operation::Sub &) override; + void visit(const ir::operation::Cast &) override; + void visit(const ir::operation::Div &) override; + void visit(const ir::operation::Exp &) override; + void visit(const ir::operation::InstanceNorm &) override; + void visit(const ir::operation::Logistic &) override; + void visit(const ir::operation::ReduceMax &) override; + void visit(const ir::operation::Comparison &) override; + void visit(const ir::operation::LogicalAnd &) override; + void visit(const ir::operation::LSTM &) override; + void visit(const ir::operation::Pack &) override; + void visit(const ir::operation::Permute &) override; + void visit(const ir::operation::RSQRT &) override; + void visit(const ir::operation::ReLU &) override; + void visit(const ir::operation::ResizeBilinear &) override; + void visit(const ir::operation::ReLU1 &) override; + void visit(const ir::operation::ReLU6 &) override; + void visit(const ir::operation::RNN &) override; + void visit(const ir::operation::Floor &) override; + void visit(const ir::operation::SpaceToBatchND &) override; + void visit(const ir::operation::SpaceToDepth &) override; + void visit(const ir::operation::L2Pool2D &) override; + void visit(const ir::operation::EmbeddingLookup &) override; + void visit(const ir::operation::L2Normalization &) override; + void visit(const ir::operation::HashtableLookup &) override; + void visit(const ir::operation::PReLU &) override; + void visit(const ir::operation::TransposeConv &) override; + void visit(const ir::operation::SQRT &) override; + void visit(const ir::operation::LogicalOr &) override; + void visit(const ir::operation::LogicalNot &) override; + void visit(const ir::operation::SquaredDifference &) override; + void visit(const ir::operation::TopKV2 &) override; + void visit(const ir::operation::Gather &) override; + void visit(const ir::operation::Neg &) override; + void visit(const ir::operation::Abs &) override; + void visit(const ir::operation::ArgMax &) override; + void visit(const ir::operation::Dequantize &) override; + void visit(const ir::operation::Mean &) override; + void visit(const ir::operation::LocalResponseNormalization &) override; + void visit(const ir::operation::DepthToSpace &) override; + void visit(const ir::operation::ReduceMin &) override; + void visit(const ir::operation::Split &) override; + void visit(const ir::operation::Unpack &) override; + void visit(const ir::operation::Pad &) override; + void visit(const ir::operation::Min &) override; + void visit(const ir::operation::Max &) override; + +private: + const ir::Operands &_ctx; + std::shared_ptr _tensor_builder; +}; + +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_SHAPE_FIXER_H__ diff --git a/runtime/onert/backend/acl_cl/TensorBuilder.h b/runtime/onert/backend/acl_cl/TensorBuilder.h new file mode 100644 index 000000000..91502d39a --- /dev/null +++ b/runtime/onert/backend/acl_cl/TensorBuilder.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_TENSOR_BUILDER_H__ +#define __ONERT_BACKEND_ACL_CL_TENSOR_BUILDER_H__ + +#include + +#include "operand/CLTensor.h" +#include "operand/CLSubTensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +using TensorBuilder = + acl_common::AclTensorBuilder; + +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_TENSOR_BUILDER_H__ diff --git a/runtime/onert/backend/acl_cl/TensorManager.h b/runtime/onert/backend/acl_cl/TensorManager.h new file mode 100644 index 000000000..bdbd0364e --- /dev/null +++ b/runtime/onert/backend/acl_cl/TensorManager.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_TENSOR_MANAGER_H__ +#define __ONERT_BACKEND_ACL_CL_TENSOR_MANAGER_H__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "operand/CLTensor.h" +#include "operand/CLSubTensor.h" + +#include "util/logging.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ + +using MemoryManager = + acl_common::AclMemoryManager; + +using LinearMemoryManager = acl_common::AclLinearMemoryManager< + operand::ICLTensor, operand::CLTensor, operand::CLSubTensor, + ::arm_compute::MemoryManagerOnDemand, ::arm_compute::PoolManager, + ::arm_compute::BlobLifetimeManager, ::arm_compute::CLBufferAllocator, + ::arm_compute::MemoryGroup>; + +using InternalBufferManager = acl_common::AclInternalBufferManager< + ::arm_compute::MemoryManagerOnDemand, ::arm_compute::PoolManager, + ::arm_compute::BlobLifetimeManager, ::arm_compute::CLBufferAllocator>; + +using TensorManager = + acl_common::AclTensorManager; + +TensorManager *createTensorManager(bool is_linear_executor) +{ + if (is_linear_executor) + { + VERBOSE(acl_cl_createTensorManager) << "AclTensorManager as Linear" << std::endl; + return new TensorManager(new MemoryManager(), new LinearMemoryManager(), + new InternalBufferManager()); + } + else + { + VERBOSE(acl_cl_createTensorManager) << "AclTensorManager" << std::endl; + return new TensorManager(new MemoryManager(), new MemoryManager(), new InternalBufferManager()); + } +} + +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_TENSOR_MANAGER_H__ diff --git a/runtime/onert/backend/acl_cl/acl_cl.cc b/runtime/onert/backend/acl_cl/acl_cl.cc new file mode 100644 index 000000000..88378b13a --- /dev/null +++ b/runtime/onert/backend/acl_cl/acl_cl.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Backend.h" + +extern "C" { +onert::backend::Backend *onert_backend_create() +{ + VERBOSE(onert_backend_create) << "'acl_cl' loaded\n"; + return new onert::backend::acl_cl::Backend; +} + +void onert_backend_destroy(onert::backend::Backend *backend) +{ + VERBOSE(onert_backend_create) << "'acl_cl' unloaded\n"; + delete backend; +} +} diff --git a/runtime/onert/backend/acl_cl/operand/CLSubTensor.cc b/runtime/onert/backend/acl_cl/operand/CLSubTensor.cc new file mode 100644 index 000000000..234229787 --- /dev/null +++ b/runtime/onert/backend/acl_cl/operand/CLSubTensor.cc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CLSubTensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +CLSubTensor::CLSubTensor(ICLTensor *parent, const arm_compute::TensorShape &tensor_shape, + const arm_compute::Coordinates &coords, size_t rank, bool extend_parent) + : _cl_sub_tensor(std::make_shared(parent->handle(), tensor_shape, + coords, extend_parent)), + _rank{rank} +{ + // DO NOTHING +} + +const arm_compute::CLSubTensor *CLSubTensor::handle() const { return _cl_sub_tensor.get(); } + +arm_compute::CLSubTensor *CLSubTensor::handle() { return _cl_sub_tensor.get(); } + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_cl/operand/CLSubTensor.h b/runtime/onert/backend/acl_cl/operand/CLSubTensor.h new file mode 100644 index 000000000..fedc17fc2 --- /dev/null +++ b/runtime/onert/backend/acl_cl/operand/CLSubTensor.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__ +#define __ONERT_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__ + +#include +#include "ICLTensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +class CLSubTensor : public ICLTensor +{ +public: + CLSubTensor() = delete; + +public: + CLSubTensor(ICLTensor *parent, const arm_compute::TensorShape &tensor_shape, + const arm_compute::Coordinates &coords, size_t rank, bool extend_parent = false); + +public: + size_t num_dimensions() const final { return _rank; } + +public: + const arm_compute::CLSubTensor *handle() const override; + arm_compute::CLSubTensor *handle() override; + +public: + // This method is used to prevent the use of memcpy for SubTensor + bool has_padding() const override { return true; } + +private: + std::shared_ptr _cl_sub_tensor; + size_t _rank; +}; + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__ diff --git a/runtime/onert/backend/acl_cl/operand/CLTensor.cc b/runtime/onert/backend/acl_cl/operand/CLTensor.cc new file mode 100644 index 000000000..cd5aaa1fd --- /dev/null +++ b/runtime/onert/backend/acl_cl/operand/CLTensor.cc @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CLTensor.h" + +#include +#include +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +CLTensor::CLTensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses) + : _cl_tensor(std::make_shared()), _rank{rank}, _num_uses{num_uses} +{ + allocator()->init(info); +} + +const arm_compute::CLTensor *CLTensor::handle() const { return _cl_tensor.get(); } + +arm_compute::CLTensor *CLTensor::handle() { return _cl_tensor.get(); } + +arm_compute::CLTensorAllocator *CLTensor::allocator() { return _cl_tensor->allocator(); } + +void CLTensor::map(bool blocking) { _cl_tensor->map(blocking); } + +void CLTensor::unmap() { _cl_tensor->unmap(); } + +void CLTensor::setBuffer(void *host_ptr) +{ + // Constructs a Buffer on a user-supplied memory + auto buffer = cl::Buffer(arm_compute::CLScheduler::get().context(), + CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, info()->total_size(), host_ptr); + // import memory + allocator()->import_memory(buffer); +} + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_cl/operand/CLTensor.h b/runtime/onert/backend/acl_cl/operand/CLTensor.h new file mode 100644 index 000000000..abad866c3 --- /dev/null +++ b/runtime/onert/backend/acl_cl/operand/CLTensor.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__ +#define __ONERT_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__ + +#include +#include +#include +#include "arm_compute/runtime/CL/CLTensorAllocator.h" +#include "ICLTensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +class CLTensor : public ICLTensor +{ +public: + CLTensor() = delete; + +public: + CLTensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses); + +public: + size_t num_dimensions() const final { return _rank; } + +public: + const arm_compute::CLTensor *handle() const override; + arm_compute::CLTensor *handle() override; + size_t num_uses() const { return _num_uses; } + +public: + arm_compute::CLTensorAllocator *allocator(); + void map(bool blocking = true); + void unmap(); + /** Set given buffer as the buffer of the tensor + * + * @note Ownership of the memory is not transferred to this object. + * Thus management (allocate/free) should be done by the client. + * + * @param[in] host_ptr Storage to be used. + */ + void setBuffer(void *host_ptr); + +private: + std::shared_ptr _cl_tensor; + size_t _rank; + size_t _num_uses; +}; + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__ diff --git a/runtime/onert/backend/acl_cl/operand/ICLTensor.cc b/runtime/onert/backend/acl_cl/operand/ICLTensor.cc new file mode 100644 index 000000000..b400ef9cf --- /dev/null +++ b/runtime/onert/backend/acl_cl/operand/ICLTensor.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ICLTensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +void ICLTensor::access(const std::function &fn) +{ + auto &queue = ::arm_compute::CLScheduler::get().queue(); + + // This is an optional input + if (total_size() == 0) + return; + + map(queue); + fn(*this); + unmap(queue); +} +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_cl/operand/ICLTensor.h b/runtime/onert/backend/acl_cl/operand/ICLTensor.h new file mode 100644 index 000000000..f709fe465 --- /dev/null +++ b/runtime/onert/backend/acl_cl/operand/ICLTensor.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__ +#define __ONERT_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__ + +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace acl_cl +{ +namespace operand +{ + +class ICLTensor : public acl_common::IACLTensor +{ +public: + const arm_compute::ICLTensor *handle() const override = 0; + arm_compute::ICLTensor *handle() override = 0; + +public: + void map(cl::CommandQueue &q, bool blocking = true) { return handle()->map(q, blocking); } + void unmap(cl::CommandQueue &q) { return handle()->unmap(q); } + void access(const std::function &fn) final; +}; + +} // namespace operand +} // namespace acl_cl +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__ diff --git a/runtime/onert/backend/acl_common/AclActivationBuilder.h b/runtime/onert/backend/acl_common/AclActivationBuilder.h new file mode 100644 index 000000000..bfdea6ea0 --- /dev/null +++ b/runtime/onert/backend/acl_common/AclActivationBuilder.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_ACL_ACTIVATION_BUILDER_H__ +#define __ONERT_BACKEND_ACL_COMMON_ACL_ACTIVATION_BUILDER_H__ + +#include + +#include +#include +#include + +#include "Convert.h" + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +template +class AclActivationBuilder +{ +private: + static std::unique_ptr generateReLU(T_Tensor *ifm_alloc); + static std::unique_ptr generateReLU1(T_Tensor *ifm_alloc); + static std::unique_ptr generateReLU6(T_Tensor *ifm_alloc); + +public: + static std::unique_ptr generate(ir::Activation code, T_Tensor *ifm_alloc); +}; + +template +std::unique_ptr +AclActivationBuilder::generateReLU(T_Tensor *ifm_alloc) +{ + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU}; + + auto fn = std::make_unique(); + + fn->configure(ifm_alloc, nullptr, act_info); + + return asFunction(std::move(fn)); +} + +template +std::unique_ptr +AclActivationBuilder::generateReLU1( + T_Tensor *ifm_alloc) +{ + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f}; + + auto fn = std::make_unique(); + + fn->configure(ifm_alloc, nullptr, act_info); + + return asFunction(std::move(fn)); +} + +template +std::unique_ptr +AclActivationBuilder::generateReLU6( + T_Tensor *ifm_alloc) +{ + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f}; + + auto fn = std::make_unique(); + + fn->configure(ifm_alloc, nullptr, act_info); + + return asFunction(std::move(fn)); +} + +template +std::unique_ptr +AclActivationBuilder::generate(ir::Activation code, + T_Tensor *ifm_alloc) +{ + switch (code) + { + case ir::Activation::NONE: + { + return std::make_unique(); + } + case ir::Activation::RELU: + { + return generateReLU(ifm_alloc); + } + case ir::Activation::RELU1: + { + return generateReLU1(ifm_alloc); + } + case ir::Activation::RELU6: + { + return generateReLU6(ifm_alloc); + } + default: + { + throw std::runtime_error("Not supported, yet"); + } + } +} + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_ACL_ACTIVATION_BUILDER_H__ diff --git a/runtime/onert/backend/acl_common/AclFunction.h b/runtime/onert/backend/acl_common/AclFunction.h new file mode 100644 index 000000000..99972ac9c --- /dev/null +++ b/runtime/onert/backend/acl_common/AclFunction.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_KERNEL_ACL_FUNCTION_H__ +#define __ONERT_BACKEND_ACL_COMMON_KERNEL_ACL_FUNCTION_H__ + +#include +#include +#include +#include + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +class AclFunction : public ::onert::exec::IFunction +{ +public: + AclFunction() = delete; + +public: + AclFunction(std::unique_ptr<::arm_compute::IFunction> &&func) : _func(std::move(func)) + { + // DO NOTHING + } + +public: + void run() override { _func->run(); } + void runSync() override { run(); } + void prepare() override { _func->prepare(); } + +private: + std::unique_ptr<::arm_compute::IFunction> _func; +}; + +class AclClFunction : public AclFunction +{ +public: + using AclFunction::AclFunction; + +public: + void runSync() final + { + run(); + arm_compute::CLScheduler::get().sync(); + } +}; + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_KERNEL_ACL_FUNCTION_H__ diff --git a/runtime/onert/backend/acl_common/AclInternalBufferManager.h b/runtime/onert/backend/acl_common/AclInternalBufferManager.h new file mode 100644 index 000000000..f893bb44b --- /dev/null +++ b/runtime/onert/backend/acl_common/AclInternalBufferManager.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_INTERNAL_BUFFER_MANAGER_H__ +#define __ONERT_BACKEND_ACL_COMMON_INTERNAL_BUFFER_MANAGER_H__ + +#include +#include +#include +#include + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +// NOTE. If any backend can use something like InternalBufferManager, +// this interface can be moved to core/include/backend/ +/** + * @brief Interface for InternalBufferManager which has ::arm_compute::IMemoryManager pointer + */ +struct IInternalBufferManager : public backend::IMemoryManager +{ + virtual ~IInternalBufferManager() = default; + + /** + * @brief Get shared_ptr of ::arm_compute::IMemoryManager + */ + virtual std::shared_ptr<::arm_compute::IMemoryManager> internal_buffer_manager(void) = 0; +}; + +/** + * @brief class for InternalBufferManager which has ::arm_compute::IMemoryManager pointer + */ +template +class AclInternalBufferManager : public IInternalBufferManager +{ +public: + AclInternalBufferManager() : _allocator{nullptr} + { + std::shared_ptr lifetime_mgr = std::make_shared(); + std::shared_ptr pool_mgr = std::make_shared(); + + _internal_manager = std::make_shared(lifetime_mgr, pool_mgr); + assert(_internal_manager); + } + + virtual ~AclInternalBufferManager() = default; + + /** + * @brief Allocate the internal buffer manager on acl + */ + void allocate(void) override + { + _allocator = std::make_shared(); + _internal_manager->populate(*_allocator, 1); + } + + /** + * @brief Deallocate the internal buffer manager on acl + */ + void deallocate(void) override { _internal_manager->clear(); } + + /** + * @brief Get shared_ptr of ::arm_compute::IMemoryManager + */ + std::shared_ptr<::arm_compute::IMemoryManager> internal_buffer_manager(void) override + { + return _internal_manager; + } + +private: + std::shared_ptr _allocator; + std::shared_ptr _internal_manager; +}; + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_INTERNAL_BUFFER_MANAGER_H__ diff --git a/runtime/onert/backend/acl_common/AclLinearMemoryManager.h b/runtime/onert/backend/acl_common/AclLinearMemoryManager.h new file mode 100644 index 000000000..09f25e7a8 --- /dev/null +++ b/runtime/onert/backend/acl_common/AclLinearMemoryManager.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_LINEAR_MEMORY_MANAGER_H__ +#define __ONERT_BACKEND_ACL_COMMON_LINEAR_MEMORY_MANAGER_H__ + +#include + +#include "AclMemoryManager.h" +#include "ir/OperandIndexMap.h" +#include "util/logging.h" + +namespace +{ + +template +std::shared_ptr createMemoryManager() +{ + std::shared_ptr lifetime_mgr = std::make_shared(); + std::shared_ptr pool_mgr = std::make_shared(); + + std::shared_ptr mem_mgr = + std::make_shared(lifetime_mgr, pool_mgr); + return mem_mgr; +} + +} // namespace + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +template +class AclLinearMemoryManager : public AclMemoryManager +{ +public: + AclLinearMemoryManager() + : _allocator{nullptr}, + _io_manager{createMemoryManager()}, + _io_group{std::make_shared(_io_manager)} + { + // DO NOTHING + } + + virtual ~AclLinearMemoryManager() = default; + + void allocate(void) override + { + _allocator = std::make_shared(); + _io_manager->populate(*_allocator, 1); + _io_group->acquire(); + } + + void deallocate(void) override + { + _io_group->release(); + _io_manager->clear(); + } + + void startLifetime(const ir::OperandIndex &ind) override + { + auto &tensors = this->tensors(); + assert(tensors.find(ind) != tensors.end()); + + auto tensor = tensors[ind]; + assert(tensor->handle()); + + _io_group->manage(tensor->handle()); + } + + void finishLifetime(const ir::OperandIndex &ind) override + { + auto &tensors = this->tensors(); + assert(tensors.find(ind) != tensors.end()); + + auto tensor = tensors[ind]; + assert(tensor->allocator()); + + tensor->allocator()->allocate(); + } + +private: + std::shared_ptr _allocator; + std::shared_ptr _io_manager; + std::shared_ptr _io_group; +}; + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_LINEAR_MEMORY_MANAGER_H__ diff --git a/runtime/onert/backend/acl_common/AclMemoryManager.h b/runtime/onert/backend/acl_common/AclMemoryManager.h new file mode 100644 index 000000000..eefcec130 --- /dev/null +++ b/runtime/onert/backend/acl_common/AclMemoryManager.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_MEMORY_MANAGER_H__ +#define __ONERT_BACKEND_ACL_COMMON_MEMORY_MANAGER_H__ + +#include +#include +#include + +#include "backend/IMemoryManager.h" +#include "ir/OperandIndexMap.h" +#include "Convert.h" +#include "util/logging.h" + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +template +class AclMemoryManager : public backend::IMemoryManager +{ +public: + AclMemoryManager() + { + // DO NOTHING + } + + virtual ~AclMemoryManager() = default; + + void allocate(void) override + { + for (const auto &tensor_entry : _tensors) + { + auto tensor = tensor_entry.second; + tensor->allocator()->allocate(); + } + } + + void deallocate(void) override + { + for (const auto &tensor_entry : _tensors) + { + auto tensor = tensor_entry.second; + tensor->allocator()->free(); + } + } + + virtual void startLifetime(const ir::OperandIndex &) { /* DO NOTHING */} + virtual void finishLifetime(const ir::OperandIndex &) { /* DO NOTHING */} + + void buildTensor(const ir::OperandIndex &ind, const ::arm_compute::TensorInfo &info, size_t rank, + size_t num_uses) + { + auto tensor = std::make_shared(info, rank, num_uses); + _tensors[ind] = tensor; + } + + void buildSubtensor(std::shared_ptr parent_tensor, const ir::OperandIndex &child_ind, + const ::arm_compute::TensorShape &shape, + const ::arm_compute::Coordinates &coordinates, size_t rank, + bool extent_parent) + { + auto subtensor = + std::make_shared(parent_tensor.get(), shape, coordinates, rank, extent_parent); + _subtensors[child_ind] = subtensor; + } + + ir::OperandIndexMap> &tensors(void) { return _tensors; } + + ir::OperandIndexMap> &subtensors(void) { return _subtensors; } + +private: + ir::OperandIndexMap> _tensors; + ir::OperandIndexMap> _subtensors; +}; + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_MEMORY_MANAGER_H__ diff --git a/runtime/onert/backend/acl_common/AclSubTensorAnalyzer.h b/runtime/onert/backend/acl_common/AclSubTensorAnalyzer.h new file mode 100644 index 000000000..83d7ad6fd --- /dev/null +++ b/runtime/onert/backend/acl_common/AclSubTensorAnalyzer.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_ACL_SUB_TENSOR_ANALYZER_H__ +#define __ONERT_BACKEND_ACL_COMMON_ACL_SUB_TENSOR_ANALYZER_H__ + +#include +#include +#include "ParentInfo.h" + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +/** + * @brief Class to analyze tensor subsumption + */ +class AclSubTensorAnalyzer : public ir::OperationVisitor +{ +public: + /** + * @brief Construct a new SubTensorAnalyzer object + * @param[in] ctx Graph operand set + */ + AclSubTensorAnalyzer(const ir::Graph &graph) : _graph{graph} + { + // DO NOTHING + } + +public: + void setLayout(ir::Layout layout) { _current_op_layout = layout; } + + void visit(const ir::operation::Concat &node) override + { + // If operator is concat, fill subsumption info + int32_t axis_raw = node.param().axis; + + const auto &output_index = node.getOutputs().at(0); + const auto &inputs = node.getInputs(); + + int32_t axis_point = 0; + const auto rank = _graph.operands().at(output_index).shape().rank(); + int32_t axis = axis_raw < 0 ? (axis_raw + rank) : axis_raw; + assert(rank > axis); + + for (const auto &ind : inputs) + { + // NOTE Not support the case that concat's input is a constant or a input of model + if (_graph.operands().at(ind).isConstant() || _graph.getInputs().contains(ind)) + { + return; + } + } + + for (const auto &input_index : inputs) + { + auto input_shape = _graph.operands().at(input_index).shape(); + assert(rank == input_shape.rank()); + + ir::Coordinates coordinate_info{}; + for (int i = 0; i < rank; i++) + { + coordinate_info.set(i, 0); + } + coordinate_info.set(axis, axis_point); + + _parent_map.emplace( + input_index, acl_common::ParentInfo{output_index, _current_op_layout, coordinate_info}); + + axis_point += input_shape.dim(axis); + } + } + + std::unordered_map &&releaseParentMap() + { + return std::move(_parent_map); + } + +private: + const ir::Graph &_graph; + std::unordered_map _parent_map; + ir::Layout _current_op_layout{ir::Layout::UNKNOWN}; +}; + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_ACL_SUB_TENSOR_ANALYZER_H__ diff --git a/runtime/onert/backend/acl_common/AclTensorBuilder.h b/runtime/onert/backend/acl_common/AclTensorBuilder.h new file mode 100644 index 000000000..be8d43209 --- /dev/null +++ b/runtime/onert/backend/acl_common/AclTensorBuilder.h @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__ +#define __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__ + +#include +#include + +#include +#include +#include "ir/OperandIndexMap.h" +#include +#include "AclTensorManager.h" +#include +#include "ParentInfo.h" +#include + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +enum class UsesType +{ + FIRST, + LAST +}; + +template +class AclTensorBuilder : public ITensorBuilder +{ +public: + using T_AclTensorManager = AclTensorManager; + + AclTensorBuilder(const ir::Operands &operands, T_AclTensorManager *tensor_mgr); + + /** + * @brief Register tensor information to allocate on ACL-CL backend + * @param[in] ind Operand index + * @param[in] info Tensor information + * @param[in] layout Tensor data layout + */ + void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info, + ir::Layout backend_layout, bool as_const) override; + + void notifyFirstUse(const ir::OperandIndex &) override; + void notifyLastUse(const ir::OperandIndex &) override; + + bool isRegistered(const ir::OperandIndex &) const override; + + void prepare(void) override; + void allocate() override; + void postFunctionPrepare() override; + + std::shared_ptr tensorAt(const ir::OperandIndex &ind) override; + void iterate(const IterateFunction &fn) override; + + std::unique_ptr releaseTensorManager(void) override; + + std::shared_ptr at(const ir::OperandIndex &ind); + + void dimCorrection(const ir::OperandIndex &index, bool apply_dim_correction); + + T_AclTensorManager *acl_tensor_manager(void) { return _tensor_mgr.get(); } + + void setUsesCount(const ir::OperandIndex &index, size_t num_uses) + { + assert(_uses_count_map.find(index) != _uses_count_map.end() ? _uses_count_map[index] == num_uses + : true); + _uses_count_map[index] = num_uses; + } + + void parent_map(std::unordered_map &&parent_map) + { + _parent_map = std::move(parent_map); + } + + bool areSubTensorsOf(const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq); + + /** + * @brief Check child tensor is allocated as subtensor of parent tensor + * @param[in] parent Index of parent + * @param[in] child Index of child + * @return @c true if child is allocated as subtensor of parent, otherwise @c false + */ + bool isSubTensorOf(const ir::OperandIndex &parent, const ir::OperandIndex &child); + +private: + void buildTensors(void); + ir::OperandIndex findRootParent(ir::OperandIndex index); + +private: + const ir::Operands &_operands; + ir::OperandIndexMap _tensor_info_map; + ir::OperandIndexMap _apply_dim_correction_map; + ir::OperandIndexMap _tensor_layout_map; + ir::OperandIndexMap _uses_count_map; + + std::unique_ptr _tensor_mgr; + ir::OperandIndexSequence _constants; + + // for linear executor + std::vector> _lifetime_seq; + + // Extra info for concat elimination + ir::OperandIndexMap _parent_map; +}; + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#include +#include + +#include "Convert.h" + +#include "util/logging.h" + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +template +AclTensorBuilder::AclTensorBuilder(const ir::Operands &operands, + T_AclTensorManager *tensor_mgr) + : _operands{operands}, _tensor_mgr{tensor_mgr} +{ + assert(_tensor_mgr); +} + +template +void AclTensorBuilder::registerTensorInfo( + const ir::OperandIndex &ind, const ir::OperandInfo &info, ir::Layout backend_layout, + bool as_const) +{ + assert(_tensor_mgr->constTensors().size() == 0); + assert(_tensor_mgr->nonconstTensors().size() == 0); + + _uses_count_map[ind] = _operands.at(ind).getUses().size(); + + if (_parent_map.count(ind) == 0) + { + // Normal Tensors + _tensor_info_map.emplace(ind, info); + _apply_dim_correction_map.emplace(ind, true); + _tensor_layout_map.insert({ind, backend_layout}); + if (as_const) + _constants.append(ind); + } + else + { + // SubTensors + + assert(!as_const && "Subtensors of constants are not supported yet."); + + // Update offset info and emplace + auto &parent_info = _parent_map[ind]; + const auto &obj = _operands.at(ind); + auto parent_index = parent_info.parent; + auto &offset = parent_info.coordinates; + auto frontend_layout = parent_info.frontend_layout; + + assert(obj.shape().rank() <= 4); + auto shape = obj.shape(); + if (_operands.at(parent_index).shape().rank() == 4 && frontend_layout == ir::Layout::NHWC && + backend_layout == ir::Layout::NCHW) + { + shape.extendRank(4); + offset = {offset[0], offset[3], offset[1], offset[2]}; + } + else if (_operands.at(parent_index).shape().rank() == 4 && + frontend_layout == ir::Layout::NHWC && backend_layout == ir::Layout::NCHW) + { + shape.extendRank(4); + offset = {offset[0], offset[2], offset[3], offset[1]}; + } + auto new_shape = permuteShape(shape, frontend_layout, backend_layout); + ir::OperandInfo oi{new_shape, obj.typeInfo()}; + _tensor_info_map.emplace(ind, oi); + + _apply_dim_correction_map.emplace(ind, true); + } +} + +template +void AclTensorBuilder::notifyFirstUse(const ir::OperandIndex &ind) +{ + _lifetime_seq.emplace_back(UsesType::FIRST, ind); +} + +template +void AclTensorBuilder::notifyLastUse(const ir::OperandIndex &ind) +{ + _lifetime_seq.emplace_back(UsesType::LAST, ind); +} + +template +bool AclTensorBuilder::isRegistered( + const ir::OperandIndex &ind) const +{ + return _tensor_info_map.find(ind) != _tensor_info_map.end(); +} + +template +void AclTensorBuilder::prepare(void) +{ + buildTensors(); +} + +template +void AclTensorBuilder::allocate(void) +{ + // Update lifetime sequence to apply subtensor optimization + + std::unordered_map root_map; + std::function find_root = + [&](ir::OperandIndex ind) -> ir::OperandIndex & { + ir::OperandIndex &ret = root_map[ind]; + + // We know the root parent value already + if (ret.valid()) + return ret; + + auto itr = _parent_map.find(ind); + if (itr == _parent_map.end()) + { + // If there is no parent, let's store the value of itself + return ret = ind; + } + else + { + return ret = find_root(itr->second.parent); + } + }; + + ir::OperandIndexMap first_use_check; + ir::OperandIndexMap last_use_check; + std::map> lifetime_map; + for (size_t i = 0; i < _lifetime_seq.size(); i++) + { + auto &entry = _lifetime_seq[i]; + if (entry.first != UsesType::FIRST) + continue; + auto root_ind = find_root(entry.second); + if (first_use_check[root_ind]) + continue; + first_use_check[root_ind] = true; + lifetime_map[i] = {UsesType::FIRST, root_ind}; + } + + for (int i = _lifetime_seq.size() - 1; i >= 0; i--) + { + auto &entry = _lifetime_seq[i]; + if (entry.first != UsesType::LAST) + continue; + auto root_ind = find_root(entry.second); + if (last_use_check[root_ind]) + continue; + last_use_check[root_ind] = true; + lifetime_map[i] = {UsesType::LAST, root_ind}; + } + + for (auto &entry : lifetime_map) + { + auto &use = entry.second; + auto use_type = use.first; + auto use_index = use.second; + assert(use_index.valid()); + if (use_type == UsesType::FIRST) + _tensor_mgr->startLifetime(use_index); + else + _tensor_mgr->finishLifetime(use_index); + } + + assert(_constants.size() == _tensor_mgr->constTensors().size()); + _tensor_mgr->allocateConsts(); + + // TODO Since `_parent_map` is filled for all Concat nodes even if the node this backend uses + // After refactoring BackendContext we can uncomment this + // assert(_tensor_info_map.size() == + // _tensor_mgr->nonconstTensors().size() + _constants.size() + _parent_map.size()); + _tensor_mgr->allocateNonconsts(); + + _tensor_mgr->allocateInternalBufferManager(); +} + +template +void AclTensorBuilder::postFunctionPrepare(void) +{ + _tensor_mgr->tryDeallocConstants(); +} + +template +std::shared_ptr +AclTensorBuilder::tensorAt(const ir::OperandIndex &ind) +{ + return _tensor_mgr->at(ind); +} + +template +void AclTensorBuilder::iterate(const IterateFunction &fn) +{ + _tensor_mgr->iterate(fn); +} + +template +std::shared_ptr +AclTensorBuilder::at(const ir::OperandIndex &ind) +{ + auto ret = _tensor_mgr->at(ind); + assert(ret != nullptr); + return ret; +} + +template +void AclTensorBuilder::dimCorrection( + const ir::OperandIndex &index, bool apply_dim_correction) +{ + _apply_dim_correction_map[index] = apply_dim_correction; +} + +template +std::unique_ptr +AclTensorBuilder::releaseTensorManager(void) +{ + return std::move(_tensor_mgr); +} + +template +void AclTensorBuilder::buildTensors(void) +{ + assert(_tensor_mgr->constTensors().size() == 0); + assert(_tensor_mgr->nonconstTensors().size() == 0); + + // Normal tensors + for (auto &entry : _tensor_info_map) + { + auto ind = entry.first; + if (_parent_map.count(ind) > 0) + continue; + + const auto &info = entry.second; + const auto &backend_layout = _tensor_layout_map[ind]; + auto tensor_info = asTensorInfo(info.shape(), info.typeInfo(), ir::Layout::UNKNOWN, + backend_layout, _apply_dim_correction_map[ind]); + _tensor_mgr->buildTensor(ind, tensor_info, info.shape().rank(), _constants.contains(ind), + _uses_count_map[ind]); + } + + // Subtensors + assert(_tensor_mgr->nonconstSubtensors().size() == 0); + // TODO Iterate `_parent_map` instead, once the optimizer bug is fixed + // `Optimizer` iterates the entire OpSequences, so there is a bug if iterating _parent_map + for (auto &entry : _tensor_info_map) + { + auto ind = entry.first; + if (_parent_map.count(ind) == 0) + continue; + + // To make subtensor, parent tensor must be made first + // For this condition, use stack + // 1) Push one subtensor index to stack (iterate subtensors) + // 2) If tensor at stack top is already made, pop and go to 4) + // 3) If tensor pushed at 1) is not made, check parent tensor + // 3-1) If parent tensor is already made, we can make child tensor + // Make child tensor and pop, go to 4) + // 3-2) If parent tensor is not made, we can't make child tensor yet + // Push parent tensor index to stack and return to 4) + // 4) If stack is empty, return to 1), else return to 2) + auto &subtensors = _tensor_mgr->nonconstSubtensors(); + + std::stack stack; + stack.push(ind); + + while (!stack.empty()) + { + const auto current = stack.top(); + const auto &tensor_info = _tensor_info_map.at(current); + const auto &parent_info = _parent_map.at(current); + + // Already generated SubTensor + if (subtensors.find(current) != subtensors.end()) + { + stack.pop(); + continue; + } + + auto parent = parent_info.parent; + std::shared_ptr parent_tensor = _tensor_mgr->findTensorAsParent(parent); + if (!parent_tensor) + { + // Cannot find allocated parent tensor: allocate parent first + assert(_parent_map.count(parent) > 0); + stack.push(parent); + continue; + } + assert(parent_tensor != nullptr); + + // Child's type should be same with parent + assert(tensor_info.typeInfo().offset() == + parent_tensor->info()->quantization_info().uniform().offset); + assert(tensor_info.typeInfo().scale() == + parent_tensor->info()->quantization_info().uniform().scale); + assert(asDataType(tensor_info.typeInfo().type()) == parent_tensor->info()->data_type()); + + // NOTE SubTensor's layout must be the same with layout of parent tensor + const auto &root_parent = findRootParent(parent); + const auto &backend_layout = _tensor_layout_map[root_parent]; + + auto shape = asTensorShape(tensor_info.shape(), ir::Layout::UNKNOWN, backend_layout, + _apply_dim_correction_map[current]); + ::arm_compute::Coordinates coordinates = + asTensorCoordinate(parent_info.coordinates, ir::Layout::UNKNOWN, backend_layout); + _tensor_mgr->buildSubtensor(parent, current, shape, coordinates, tensor_info.shape().rank(), + true); + stack.pop(); + } + } +} + +template +bool AclTensorBuilder::areSubTensorsOf( + const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq) +{ + for (auto &cand : seq) + { + if (!isSubTensorOf(parent, cand)) + { + return false; + } + } + return true; +} + +template +bool AclTensorBuilder::isSubTensorOf( + const ir::OperandIndex &parent, const ir::OperandIndex &child) +{ + auto itr = _parent_map.find(child); + if (itr == _parent_map.end()) + { + return false; + } + + return itr->second.parent == parent; +} + +template +ir::OperandIndex +AclTensorBuilder::findRootParent(ir::OperandIndex ind) +{ + if (_parent_map.find(ind) == _parent_map.end()) + return ind; + + auto parent_ind = _parent_map.at(ind).parent; + return findRootParent(parent_ind); +} + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__ diff --git a/runtime/onert/backend/acl_common/AclTensorManager.h b/runtime/onert/backend/acl_common/AclTensorManager.h new file mode 100644 index 000000000..b999a39a9 --- /dev/null +++ b/runtime/onert/backend/acl_common/AclTensorManager.h @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_TENSOR_MANAGER_H__ +#define __ONERT_BACKEND_ACL_COMMON_TENSOR_MANAGER_H__ + +#include + +#include "backend/ITensorManager.h" +#include "AclMemoryManager.h" +#include "AclInternalBufferManager.h" +#include "ir/OperandIndexMap.h" + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +template +class AclTensorManager : public backend::ITensorManager +{ +public: + using T_AclMemoryManager = AclMemoryManager; + + AclTensorManager(T_AclMemoryManager *const_mgr, T_AclMemoryManager *nonconst_mgr, + IInternalBufferManager *inter_mgr); + + virtual ~AclTensorManager() = default; + + void allocateConsts(void); + void allocateNonconsts(void); + void deallocateConsts(void); + void deallocateNonconsts(void); + + void allocateInternalBufferManager(void); + void deallocateInternalBufferManager(void); + + void buildTensor(const ir::OperandIndex &ind, const ::arm_compute::TensorInfo &info, size_t rank, + bool as_const, size_t num_uses); + void buildSubtensor(const ir::OperandIndex &parent, const ir::OperandIndex &child, + const ::arm_compute::TensorShape &shape, + const ::arm_compute::Coordinates &coordinates, size_t rank, + bool extent_parent); + + std::shared_ptr findTensorAsParent(const ir::OperandIndex &ind); + + void startLifetime(const ir::OperandIndex &ind); + void finishLifetime(const ir::OperandIndex &ind); + + std::shared_ptr at(const ir::OperandIndex &ind); + + ir::OperandIndexMap> &constTensors(void); + ir::OperandIndexMap> &nonconstTensors(void); + ir::OperandIndexMap> &nonconstSubtensors(void); + + std::shared_ptr<::arm_compute::IMemoryManager> internal_buffer_manager(void); + + void iterate(const std::function &fn); + + void tryDeallocConstants(void); + +private: + std::unique_ptr _const_mgr; + std::unique_ptr _nonconst_mgr; + std::unique_ptr _inter_mgr; + ir::OperandIndexMap _ind_to_mgr; +}; + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#include +#include "util/logging.h" + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +template +AclTensorManager::AclTensorManager( + T_AclMemoryManager *const_mgr, T_AclMemoryManager *nonconst_mgr, + IInternalBufferManager *inter_mgr) + : _const_mgr{const_mgr}, _nonconst_mgr{nonconst_mgr}, _inter_mgr{inter_mgr} +{ + // DO NOTHING +} + +template +void AclTensorManager::allocateConsts(void) +{ + _const_mgr->allocate(); +} + +template +void AclTensorManager::allocateNonconsts(void) +{ + _nonconst_mgr->allocate(); +} + +template +void AclTensorManager::deallocateConsts(void) +{ + _const_mgr->deallocate(); +} + +template +void AclTensorManager::deallocateNonconsts(void) +{ + _nonconst_mgr->deallocate(); +} + +template +void AclTensorManager::allocateInternalBufferManager(void) +{ + _inter_mgr->allocate(); +} + +template +void AclTensorManager::deallocateInternalBufferManager(void) +{ + _inter_mgr->deallocate(); +} + +template +void AclTensorManager::buildTensor( + const ir::OperandIndex &ind, const ::arm_compute::TensorInfo &info, size_t rank, bool as_const, + size_t num_uses) +{ + assert(_ind_to_mgr.find(ind) == _ind_to_mgr.end()); + if (as_const) + { + _const_mgr->buildTensor(ind, info, rank, num_uses); + _ind_to_mgr.insert({ind, *_const_mgr}); + } + else + { + _nonconst_mgr->buildTensor(ind, info, rank, num_uses); + _ind_to_mgr.insert({ind, *_nonconst_mgr}); + } +} + +template +void AclTensorManager::buildSubtensor( + const ir::OperandIndex &parent, const ir::OperandIndex &child, + const ::arm_compute::TensorShape &shape, const ::arm_compute::Coordinates &coordinates, + size_t rank, bool extent_parent) +{ + assert(_ind_to_mgr.find(child) == _ind_to_mgr.end()); + std::shared_ptr parent_tensor = findTensorAsParent(parent); + assert(parent_tensor); + _nonconst_mgr->buildSubtensor(parent_tensor, child, shape, coordinates, rank, extent_parent); + _ind_to_mgr.insert({child, *_nonconst_mgr}); +} + +template +std::shared_ptr +AclTensorManager::findTensorAsParent(const ir::OperandIndex &ind) +{ + + auto &tensors = _nonconst_mgr->tensors(); + auto &subtensors = _nonconst_mgr->subtensors(); + if (tensors.find(ind) != tensors.end()) + { + // Parent is allocated as tensor + return tensors[ind]; + } + else if (subtensors.find(ind) != subtensors.end()) + { + // Parent is allocated as subtensor + return subtensors[ind]; + } + else + { + return nullptr; + } +} + +template +void AclTensorManager::startLifetime(const ir::OperandIndex &ind) +{ + assert(_ind_to_mgr.find(ind) != _ind_to_mgr.end()); + _ind_to_mgr.at(ind).startLifetime(ind); +} + +template +void AclTensorManager::finishLifetime(const ir::OperandIndex &ind) +{ + assert(_ind_to_mgr.find(ind) != _ind_to_mgr.end()); + _ind_to_mgr.at(ind).finishLifetime(ind); +} + +template +std::shared_ptr +AclTensorManager::at(const ir::OperandIndex &ind) +{ + if (_ind_to_mgr.find(ind) == _ind_to_mgr.end()) + return nullptr; + + auto &tensors = _ind_to_mgr.at(ind).tensors(); + if (tensors.find(ind) != tensors.end()) + { + return tensors.at(ind); + } + else + { + return _ind_to_mgr.at(ind).subtensors().at(ind); + } +} + +template +ir::OperandIndexMap> & +AclTensorManager::constTensors(void) +{ + return _const_mgr->tensors(); +} + +template +ir::OperandIndexMap> & +AclTensorManager::nonconstTensors(void) +{ + return _nonconst_mgr->tensors(); +} + +template +ir::OperandIndexMap> & +AclTensorManager::nonconstSubtensors(void) +{ + return _nonconst_mgr->subtensors(); +} + +template +std::shared_ptr<::arm_compute::IMemoryManager> +AclTensorManager::internal_buffer_manager(void) +{ + return _inter_mgr->internal_buffer_manager(); +} + +template +void AclTensorManager::iterate( + const std::function &fn) +{ + for (auto it : _nonconst_mgr->tensors()) + fn(it.first); + + for (auto it : _nonconst_mgr->subtensors()) + fn(it.first); + + for (auto it : _const_mgr->tensors()) + fn(it.first); +} + +template +void AclTensorManager::tryDeallocConstants(void) +{ + auto &tensors = _const_mgr->tensors(); + + for (auto it = tensors.begin(); it != tensors.end();) + { + const auto &ind = it->first; + auto tensor = it->second; + // NOTE The condition "tensor->num_uses() < 2" is used to prevent deallocating a constant tensor + // used in several nodes. + if (tensor->handle() && !tensor->handle()->is_used() && tensor->num_uses() < 2) + { + VERBOSE(AclTensorManager) << "Tensor #" << ind.value() + << " will be deallocated as an unused constant tensor" << std::endl; + tensor->allocator()->free(); + tensor.reset(); + it = tensors.erase(it); + } + else + { + ++it; + } + } +} + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_TENSOR_MANAGER_H__ diff --git a/runtime/onert/backend/acl_common/CMakeLists.txt b/runtime/onert/backend/acl_common/CMakeLists.txt new file mode 100644 index 000000000..b87db2621 --- /dev/null +++ b/runtime/onert/backend/acl_common/CMakeLists.txt @@ -0,0 +1,19 @@ +# Unsupported architecture +nnas_find_package(ARMCompute QUIET) +if(NOT ARMCompute_FOUND) + return() +endif(NOT ARMCompute_FOUND) + +file(GLOB SOURCES "*.cc") + +add_library(${LIB_ONERT_BACKEND_ACL_COMMON} STATIC ${SOURCES}) + +target_include_directories(${LIB_ONERT_BACKEND_ACL_COMMON} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PUBLIC onert_core) +target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PUBLIC arm_compute arm_compute_ex) +target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PUBLIC nnfw_lib_misc) +target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PRIVATE nnfw_common) +target_link_libraries(${LIB_ONERT_BACKEND_ACL_COMMON} PRIVATE nnfw_coverage) + +set_target_properties(${LIB_ONERT_BACKEND_ACL_COMMON} PROPERTIES POSITION_INDEPENDENT_CODE ON) +set_target_properties(${LIB_ONERT_BACKEND_ACL_COMMON} PROPERTIES OUTPUT_NAME backend_acl_common) diff --git a/runtime/onert/backend/acl_common/Convert.cc b/runtime/onert/backend/acl_common/Convert.cc new file mode 100644 index 000000000..0ea2be010 --- /dev/null +++ b/runtime/onert/backend/acl_common/Convert.cc @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Convert.h" + +#include "Swizzle.h" +#include "ir/DataType.h" +#include + +namespace +{ + +::arm_compute::DataLayout asDataLayout(onert::ir::Layout layout) +{ + switch (layout) + { + case onert::ir::Layout::NHWC: + return ::arm_compute::DataLayout::NHWC; + case onert::ir::Layout::NCHW: + return ::arm_compute::DataLayout::NCHW; + default: + return ::arm_compute::DataLayout::UNKNOWN; + } +} + +} // namespace + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +::arm_compute::TensorShape asTensorShape(const ir::Shape &shape, ir::Layout frontend_layout, + ir::Layout backend_layout, bool apply_dim_correction) +{ + const uint32_t rank = shape.rank(); + + ::arm_compute::TensorShape res{}; + + res.set_num_dimensions(rank); + + for (uint32_t axis = 0; axis < rank; ++axis) + { + // NOTE In some cases, in incorrect dimensions is required. + // For example, intput_size is 1 in LSTM. The input-to-input weights([num_units, input_size]) of + // LSTM is used as the weight of the FullyConnected. + // The FullyConnected's weight must be greater or equal than 2-dimensions. + // However, if the dimension correction is applied to input_to_input_weights with input_size + // equal to 1, it will be changed to 1-D. + // So input_to_input_weights is not used by the weight of FullyConnected. + res.set(ToARMComputeAxis(rank, axis, frontend_layout, backend_layout).value(), shape.dim(axis), + apply_dim_correction); + } + + return res; +} + +::arm_compute::Coordinates asTensorCoordinate(const ir::Coordinates &coord, + ir::Layout frontend_layout, ir::Layout backend_layout) +{ + const uint32_t rank = coord.size(); + + ::arm_compute::Coordinates res{}; + + res.set_num_dimensions(rank); + + for (uint32_t axis = 0; axis < rank; ++axis) + { + res.set(ToARMComputeAxis(rank, axis, frontend_layout, backend_layout).value(), coord[axis]); + } + + return res; +} + +::arm_compute::DataType asDataType(const ir::DataType type) +{ + switch (type) + { + case ir::DataType::FLOAT32: + return ::arm_compute::DataType::F32; + case ir::DataType::INT32: + return ::arm_compute::DataType::S32; + case ir::DataType::UINT32: + return ::arm_compute::DataType::U32; + case ir::DataType::QUANT8_ASYMM: + return ::arm_compute::DataType::QASYMM8; + case ir::DataType::BOOL8: + case ir::DataType::UINT8: + return ::arm_compute::DataType::U8; + case ir::DataType::QUANT8_SYMM: + return ::arm_compute::DataType::S8; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +::arm_compute::QuantizationInfo asQuantizationInfo(const float scale, const int32_t offset) +{ + return ::arm_compute::QuantizationInfo(scale, offset); +} + +::arm_compute::TensorInfo asTensorInfo(const ir::Shape &shape, const ir::TypeInfo &typeInfo, + ir::Layout frontend_layout, ir::Layout backend_layout, + bool apply_dim_correction) +{ + ::arm_compute::TensorInfo info( + asTensorShape(shape, frontend_layout, backend_layout, apply_dim_correction), 1, + asDataType(typeInfo.type()), asQuantizationInfo(typeInfo.scale(), typeInfo.offset())); + info.set_data_layout(asDataLayout(backend_layout)); + return info; +} + +::arm_compute::PadStrideInfo asPadStrideInfo(const ir::ExplicitPadding &padding, + const ir::Stride &stride) +{ + return ::arm_compute::PadStrideInfo{stride.horizontal, + stride.vertical, + padding.left, + padding.right, + padding.top, + padding.bottom, + ::arm_compute::DimensionRoundingType::FLOOR}; +} + +::arm_compute::ActivationLayerInfo asActivationLayerInfo(const ir::Activation act_code) +{ + switch (act_code) + { + case ir::Activation::NONE: + return ::arm_compute::ActivationLayerInfo{}; + case ir::Activation::RELU: + return ::arm_compute::ActivationLayerInfo{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU}; + case ir::Activation::RELU1: + return ::arm_compute::ActivationLayerInfo{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f}; + case ir::Activation::RELU6: + return ::arm_compute::ActivationLayerInfo{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f}; + // Cases for activation of LSTM. + case ir::Activation::TANH: + return ::arm_compute::ActivationLayerInfo{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::TANH, 1.0f, 1.0f}; + case ir::Activation::SIGMOID: + // NOTE The sigmoid function is a special case of the Logistic function when L=1, k=1, x0=0. + // TODO In ACL and nnapi sepc, currently, Logistic's L always is 1, k always is 1, x0 always + // 0(always sigmoid) regardless of values of the parameter. + // If ACL support non-sigmoid logistic, should fix param values. + return ::arm_compute::ActivationLayerInfo{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LOGISTIC, 0.0f, 0.0f}; + default: + throw std::runtime_error{"Not supported, yet"}; + break; + } +} + +std::unique_ptr asAclFunction(std::unique_ptr<::arm_compute::IFunction> &&layer) +{ + return std::make_unique(std::move(layer)); +} + +std::unique_ptr asAclClFunction(std::unique_ptr<::arm_compute::IFunction> &&layer) +{ + return std::make_unique(std::move(layer)); +} + +ir::Layout asRuntimeLayout(::arm_compute::DataLayout data_layout) +{ + switch (data_layout) + { + case ::arm_compute::DataLayout::NHWC: + return ir::Layout::NHWC; + case ::arm_compute::DataLayout::NCHW: + return ir::Layout::NCHW; + default: + return ir::Layout::UNKNOWN; + } +} + +} // namespace acl_common +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_common/Convert.h b/runtime/onert/backend/acl_common/Convert.h new file mode 100644 index 000000000..760a73f51 --- /dev/null +++ b/runtime/onert/backend/acl_common/Convert.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_CONVERT_H__ +#define __ONERT_BACKEND_ACL_COMMON_CONVERT_H__ + +#include +#include +#include + +#include "ir/Layout.h" +#include "ir/InternalType.h" +#include "ir/Operand.h" +#include "ir/Shape.h" +#include "ir/TypeInfo.h" +#include "ir/Coordinates.h" +#include "ir/Padding.h" +#include "misc/feature/Shape.h" +#include "misc/kernel/Shape.h" + +#include "AclFunction.h" + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +::arm_compute::TensorShape asTensorShape(const ir::Shape &shape, ir::Layout frontend_layout, + ir::Layout backend_layout, + bool apply_dim_correction = true); +::arm_compute::Coordinates asTensorCoordinate(const ir::Coordinates &coord, + ir::Layout frontend_layout, + ir::Layout backend_layout); +::arm_compute::DataType asDataType(ir::DataType type); +::arm_compute::TensorInfo asTensorInfo(const ir::Shape &shape, const ir::TypeInfo &typeInfo, + ir::Layout frontend_layout, ir::Layout backend_layout, + bool apply_dim_correction = true); + +::arm_compute::PadStrideInfo asPadStrideInfo(const ir::ExplicitPadding &padding, + const ir::Stride &stride); + +::arm_compute::ActivationLayerInfo asActivationLayerInfo(ir::Activation act_code); + +std::unique_ptr asAclFunction(std::unique_ptr<::arm_compute::IFunction> &&layer); +std::unique_ptr asAclClFunction(std::unique_ptr<::arm_compute::IFunction> &&layer); + +template +std::unique_ptr asFunction(std::unique_ptr<::arm_compute::IFunction> &&fn) +{ + return std::make_unique(std::move(fn)); +} + +ir::Layout asRuntimeLayout(::arm_compute::DataLayout data_layout); + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_CONVERT_H__ diff --git a/runtime/onert/backend/acl_common/IACLTensor.cc b/runtime/onert/backend/acl_common/IACLTensor.cc new file mode 100644 index 000000000..3796b9e4b --- /dev/null +++ b/runtime/onert/backend/acl_common/IACLTensor.cc @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "IACLTensor.h" +#include "Convert.h" +#include "Swizzle.h" + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +size_t IACLTensor::num_dimensions() const +{ + throw std::runtime_error("No definition of num_dimensions()"); + return 0; +} + +size_t IACLTensor::dimension(size_t index) const +{ + // Assume that the front is higher dimensional. + // i.g. N: 0, C: 1, H: 2, W: 3 for NCHW layout + // NOTE This tensor must not be applied dim correction + assert(num_dimensions() > index); + const ARMComputeAxis reversed{(static_cast(num_dimensions() - index) - 1)}; + return info()->dimension(reversed.value()); +} + +size_t IACLTensor::calcOffset(const ir::Coordinates &coords) const +{ + const auto rank = num_dimensions(); + assert(rank == coords.size()); + + ::arm_compute::Coordinates acl_coords; + for (uint32_t i = 0; i < rank; ++i) + { + const ARMComputeAxis reversed{static_cast((rank - i) - 1)}; + acl_coords.set(reversed.value(), coords[i]); + } + + return info()->offset_element_in_bytes(acl_coords); +} + +ir::Layout IACLTensor::layout() const { return acl_common::asRuntimeLayout(info()->data_layout()); } + +} // namespace acl_common +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_common/IACLTensor.h b/runtime/onert/backend/acl_common/IACLTensor.h new file mode 100644 index 000000000..36a5d2107 --- /dev/null +++ b/runtime/onert/backend/acl_common/IACLTensor.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_I_ACL_TENSOR_H__ +#define __ONERT_BACKEND_ACL_COMMON_I_ACL_TENSOR_H__ + +#include +#include + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +/** + * @brief Class representing Tensor for ACL + * @todo Override is_dynamic() method. We don't support dynamic tensor for ACL yet as of Apr, 2020. + * FYI, ACL ITensorInfo has is_dynamic() method, which seems currently not used. + * Maybe for ACL, this method can be implemented using ITensorInfo::is_dynamic() in future. + */ +class IACLTensor : public ITensor +{ +public: + IACLTensor() = default; + IACLTensor(const IACLTensor &) = delete; + IACLTensor &operator=(const IACLTensor &) = delete; + IACLTensor(IACLTensor &&) = default; + IACLTensor &operator=(IACLTensor &&) = default; + +public: + uint8_t *buffer() const final { return handle()->buffer(); } + size_t total_size() const final { return info()->total_size(); } + size_t dimension(size_t index) const final; + size_t num_dimensions() const override; + size_t calcOffset(const ir::Coordinates &coords) const final; + ir::Layout layout() const final; + bool has_padding() const override { return info()->has_padding(); } + +public: + virtual const arm_compute::ITensor *handle() const = 0; + virtual arm_compute::ITensor *handle() = 0; + + const arm_compute::ITensorInfo *info() const { return handle()->info(); } + arm_compute::ITensorInfo *info() { return handle()->info(); } + + arm_compute::DataType data_type() const { return info()->data_type(); } +}; + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif //__ONERT_BACKEND_ACL_COMMON_I_ACL_TENSOR_H__ diff --git a/runtime/onert/backend/acl_common/ParentInfo.h b/runtime/onert/backend/acl_common/ParentInfo.h new file mode 100644 index 000000000..708436327 --- /dev/null +++ b/runtime/onert/backend/acl_common/ParentInfo.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_PARENT_INFO_H__ +#define __ONERT_BACKEND_ACL_COMMON_PARENT_INFO_H__ + +#include +#include + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +/** + * @brief Struct to represent parent operand in child operand + */ +struct ParentInfo +{ + ir::OperandIndex parent; + ir::Layout frontend_layout; + ir::Coordinates coordinates; +}; + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_PARENT_INFO_H__ diff --git a/runtime/onert/backend/acl_common/Swizzle.h b/runtime/onert/backend/acl_common/Swizzle.h new file mode 100644 index 000000000..e1c7f8041 --- /dev/null +++ b/runtime/onert/backend/acl_common/Swizzle.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_COMMON_SWIZZLE_H__ +#define __ONERT_BACKEND_ACL_COMMON_SWIZZLE_H__ + +#include +#include + +namespace onert +{ +namespace backend +{ +namespace acl_common +{ + +class ARMComputeAxis +{ +public: + ARMComputeAxis() = default; + +public: + explicit ARMComputeAxis(uint32_t value) : _value{value} + { + // DO NOTHING + } + +public: + uint32_t value(void) const { return _value; } + +private: + uint32_t _value; +}; + +// Convert axis in acl order +inline ARMComputeAxis ToARMComputeAxis(uint32_t rank, uint32_t axis, + const ir::Layout org_layout = ir::Layout::UNKNOWN, + const ir::Layout acl_layout = ir::Layout::UNKNOWN) +{ + assert(rank > axis); + + const ARMComputeAxis reversed{(rank - axis) - 1}; + + if (rank >= 4 && org_layout == ir::Layout::NHWC && acl_layout == ir::Layout::NCHW) + { + // NHWC -> WHCN + // DEPTH + if (0 == reversed.value()) + { + return ARMComputeAxis{2}; + } + // WIDTH + if (1 == reversed.value()) + { + return ARMComputeAxis{0}; + } + // HEIGHT + if (2 == reversed.value()) + { + return ARMComputeAxis{1}; + } + } + if (rank >= 4 && org_layout == ir::Layout::NCHW && acl_layout == ir::Layout::NHWC) + { + // NCHW -> CWHN + // WIDTH + if (0 == reversed.value()) + { + return ARMComputeAxis{1}; + } + // HEIGHT + if (1 == reversed.value()) + { + return ARMComputeAxis{2}; + } + // DEPTH + if (2 == reversed.value()) + { + return ARMComputeAxis{0}; + } + } + + return reversed; +} + +inline ::arm_compute::Coordinates +getARMComputeAxises(uint32_t rank, const ir::Layout org_layout = ir::Layout::UNKNOWN, + const ir::Layout acl_layout = ir::Layout::UNKNOWN) +{ + ::arm_compute::Coordinates res{}; + + res.set_num_dimensions(rank); + + for (uint32_t axis = 0; axis < rank; ++axis) + { + res.set(axis, ToARMComputeAxis(rank, axis, org_layout, acl_layout).value()); + } + + return res; +} + +// Restructure runtime_permutationVector to ACL_permutationVector +inline ::arm_compute::PermutationVector +getARMComputePermutationVector(uint32_t rank, const std::vector runtime_pv, + const ir::Layout org_layout = ir::Layout::UNKNOWN, + const ir::Layout acl_layout = ir::Layout::UNKNOWN) +{ + // rank upto 4 is supported + assert(rank <= 4); + assert(runtime_pv.size() > 0); + + int new_pv[4] = {0}; + ::arm_compute::Coordinates axises = getARMComputeAxises(rank, org_layout, acl_layout); + + for (uint32_t i = 0; i < rank; ++i) + { + new_pv[axises[i]] = ToARMComputeAxis(rank, runtime_pv[i], org_layout, acl_layout).value(); + } + + ::arm_compute::PermutationVector ACL_PV = + ::arm_compute::PermutationVector{new_pv[0], new_pv[1], new_pv[2], new_pv[3]}; + ACL_PV.set_num_dimensions(rank); + + return ACL_PV; +} + +template +inline T ReorderBits(T in, size_t numOfBits, const ir::Layout org_layout = ir::Layout::UNKNOWN, + const ir::Layout acl_layout = ir::Layout::UNKNOWN) +{ + assert(numOfBits > 0); + T out = 0; + for (int32_t i = numOfBits - 1; i >= 0; --i) + { + const uint32_t toShift = + numOfBits - ToARMComputeAxis(numOfBits, i, org_layout, acl_layout).value() - 1; + out += ((in & 1) << toShift); + in >>= 1; + } + return out; +} + +} // namespace acl_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_COMMON_SWIZZLE_H__ diff --git a/runtime/onert/backend/acl_neon/Backend.h b/runtime/onert/backend/acl_neon/Backend.h new file mode 100644 index 000000000..609545dd9 --- /dev/null +++ b/runtime/onert/backend/acl_neon/Backend.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_BACKEND_H__ +#define __ONERT_BACKEND_ACL_NEON_BACKEND_H__ + +#include +#include +#include + +#include "Config.h" +#include "ConstantInitializer.h" +#include "KernelGenerator.h" +#include "ShapeFixer.h" +#include "TensorManager.h" +#include "Optimizer.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +class Backend : public ::onert::backend::Backend +{ +public: + Backend() : _config{std::make_shared()} {} + + std::shared_ptr config() const override { return _config; } + + std::unique_ptr newContext(const ir::Graph &graph, + const std::shared_ptr &, + bool is_linear_executor) const override + { + const auto &operands = graph.operands(); + auto context = std::make_unique(this, &graph); + auto tb = std::make_shared(operands, createTensorManager(is_linear_executor)); + context->tensor_builder = tb; + context->constant_initializer = std::make_shared(operands, tb); + context->kernel_gen = std::make_shared(operands, tb); + context->shape_fixer = std::make_shared(operands, tb); + context->tensor_register = nullptr; + context->optimizer = std::make_shared(context.get()); + return context; + } + +private: + std::shared_ptr _config; +}; + +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_BACKEND_H__ diff --git a/runtime/onert/backend/acl_neon/CMakeLists.txt b/runtime/onert/backend/acl_neon/CMakeLists.txt new file mode 100644 index 000000000..05343dd8c --- /dev/null +++ b/runtime/onert/backend/acl_neon/CMakeLists.txt @@ -0,0 +1,19 @@ +# Unsupported architecture +nnas_find_package(ARMCompute QUIET) +if(NOT ARMCompute_FOUND) + return() +endif(NOT ARMCompute_FOUND) + +set(LIB_ONERT_BACKEND_ACL_NEON onert_backend_acl_neon) + +file(GLOB_RECURSE SOURCES "*.cc") + +add_library(${LIB_ONERT_BACKEND_ACL_NEON} SHARED ${SOURCES}) + +target_link_libraries(${LIB_ONERT_BACKEND_ACL_NEON} PRIVATE ${LIB_ONERT_BACKEND_ACL_COMMON}) +target_link_libraries(${LIB_ONERT_BACKEND_ACL_NEON} PRIVATE nnfw_common) +target_link_libraries(${LIB_ONERT_BACKEND_ACL_NEON} PRIVATE nnfw_coverage) + +set_target_properties(${LIB_ONERT_BACKEND_ACL_NEON} PROPERTIES OUTPUT_NAME backend_acl_neon) + +install(TARGETS ${LIB_ONERT_BACKEND_ACL_NEON} DESTINATION lib) diff --git a/runtime/onert/backend/acl_neon/Config.cc b/runtime/onert/backend/acl_neon/Config.cc new file mode 100644 index 000000000..2033f5b4e --- /dev/null +++ b/runtime/onert/backend/acl_neon/Config.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Config.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +bool Config::initialize() { return true; } + +} // namespace acl_neon +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_neon/Config.h b/runtime/onert/backend/acl_neon/Config.h new file mode 100644 index 000000000..a6d6b4673 --- /dev/null +++ b/runtime/onert/backend/acl_neon/Config.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_CONFIG_H__ +#define __ONERT_BACKEND_ACL_NEON_CONFIG_H__ + +#include +#include +#include + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +class Config : public IConfig +{ +public: + std::string id() override { return "acl_neon"; } + bool initialize() override; + bool SupportPermutation() override { return true; } + + std::unique_ptr timer() override { return std::make_unique(); } +}; + +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_CONFIG_H__ diff --git a/runtime/onert/backend/acl_neon/ConstantInitializer.cc b/runtime/onert/backend/acl_neon/ConstantInitializer.cc new file mode 100644 index 000000000..4191b277f --- /dev/null +++ b/runtime/onert/backend/acl_neon/ConstantInitializer.cc @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConstantInitializer.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +ConstantInitializer::ConstantInitializer(const ir::Operands &operands, + const std::shared_ptr &tensor_builder) + : IConstantInitializer{operands}, _tensor_builder{tensor_builder} +{ + // DO NOTHING +} + +void ConstantInitializer::copyInputInitialize(const ir::Operation &node, uint32_t index) +{ + assert(node.getInputs().size() > index); + + const auto &input_index = node.getInputs().at(index); + const auto &input_obj = _operands.at(input_index); + registerCopyInitializer(input_index, input_obj); +} + +void ConstantInitializer::permuteInputInitialize(const ir::Operation &node, uint32_t index) +{ + assert(node.getInputs().size() > index); + + const auto &input_index = node.getInputs().at(index); + const auto &input_obj = _operands.at(input_index); + registerPermuteInitializer(input_index, input_obj); +} + +void ConstantInitializer::visit(const ir::operation::BatchToSpaceND &node) +{ + const auto &block_size_index = node.getInputs().at(ir::operation::BatchToSpaceND::BLOCK_SIZE); + const auto &block_size_obj = _operands.at(block_size_index); + + if (block_size_obj.isConstant()) + { + _init_map[block_size_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) { + assert(model_obj.data()); + const auto &shape = model_obj.shape(); + const auto base = reinterpret_cast(model_obj.data()->base()); + assert(model_obj.shape().rank() == 1); + obj.access([&](ITensor &tensor) { + for (size_t i = 0; i < shape.num_elements(); ++i) + { + const int32_t value = base[shape.num_elements() - i - 1]; + int32_t *into = reinterpret_cast(tensor.buffer() + + tensor.calcOffset({static_cast(i)})); + *into = value; + } + }); + }; + } +} + +void ConstantInitializer::visit(const ir::operation::Conv2D &node) +{ + permuteInputInitialize(node, ir::operation::Conv2D::KERNEL); + copyInputInitialize(node, ir::operation::Conv2D::BIAS); +} + +void ConstantInitializer::visit(const ir::operation::DepthwiseConv2D &node) +{ + permuteInputInitialize(node, ir::operation::DepthwiseConv2D::KERNEL); + copyInputInitialize(node, ir::operation::DepthwiseConv2D::BIAS); +} + +void ConstantInitializer::visit(const ir::operation::FullyConnected &node) +{ + copyInputInitialize(node, ir::operation::FullyConnected::WEIGHT); + copyInputInitialize(node, ir::operation::FullyConnected::BIAS); +} + +void ConstantInitializer::visit(const ir::operation::LSTM &node) +{ + copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_INPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_FORGET_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_CELL_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::INPUT_TO_OUTPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_INPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_FORGET_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_CELL_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::RECURRENT_TO_OUTPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::CELL_TO_INPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::CELL_TO_FORGET_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::CELL_TO_OUTPUT_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::INPUT_GATE_BIAS); + copyInputInitialize(node, ir::operation::LSTM::FORGET_GATE_BIAS); + copyInputInitialize(node, ir::operation::LSTM::OUTPUT_GATE_BIAS); + copyInputInitialize(node, ir::operation::LSTM::PROJECTION_WEIGHTS); + copyInputInitialize(node, ir::operation::LSTM::PROJECTION_BIAS); +} + +void ConstantInitializer::visit(const ir::operation::RNN &node) +{ + copyInputInitialize(node, ir::operation::RNN::WEIGHTS); + copyInputInitialize(node, ir::operation::RNN::RECURRENT_WEIGHTS); + copyInputInitialize(node, ir::operation::RNN::BIAS); +} + +void ConstantInitializer::visit(const ir::operation::SpaceToBatchND &node) +{ + const auto &block_size_index = node.getInputs().at(ir::operation::SpaceToBatchND::BLOCK_SIZE); + const auto &block_size_obj = _operands.at(block_size_index); + + if (block_size_obj.isConstant()) + { + _init_map[block_size_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) { + assert(model_obj.data()); + const auto &shape = model_obj.shape(); + const auto base = reinterpret_cast(model_obj.data()->base()); + assert(model_obj.shape().rank() == 1); + obj.access([&](ITensor &tensor) { + for (size_t i = 0; i < shape.num_elements(); ++i) + { + const int32_t value = base[shape.num_elements() - i - 1]; + int32_t *into = reinterpret_cast(tensor.buffer() + + tensor.calcOffset({static_cast(i)})); + *into = value; + } + }); + }; + } + + const auto &paddings_index = node.getInputs().at(ir::operation::SpaceToBatchND::PADDINGS); + const auto &paddings_obj = _operands.at(paddings_index); + if (paddings_obj.isConstant()) + { + _init_map[paddings_index] = [](const ir::Operand &model_obj, backend::ITensor &obj) { + assert(model_obj.data()); + const auto &shape = model_obj.shape(); + const auto base = reinterpret_cast(model_obj.data()->base()); + assert(model_obj.shape().rank() == 2); + assert(shape.dim(0) == 2); + assert(shape.dim(1) == 2); + obj.access([&](ITensor &tensor) { + for (auto i = 0; i < shape.dim(0); ++i) + { + for (auto j = 0; j < shape.dim(1); ++j) + { + const int32_t value = base[i * 2 + j]; + int32_t *into = reinterpret_cast( + // The coordinates of NETensor are different from the coordiantes of CLTensor in + // this operand. + // NEON : {j, reversed i} + // CL : {reversed i, j} + tensor.buffer() + tensor.calcOffset({j, shape.dim(0) - i - 1})); + *into = value; + } + } + }); + }; + } +} + +void ConstantInitializer::visit(const ir::operation::TransposeConv &node) +{ + permuteInputInitialize(node, ir::operation::TransposeConv::KERNEL); +} + +} // namespace acl_neon +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_neon/ConstantInitializer.h b/runtime/onert/backend/acl_neon/ConstantInitializer.h new file mode 100644 index 000000000..6b4c1f145 --- /dev/null +++ b/runtime/onert/backend/acl_neon/ConstantInitializer.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_ACL_NEON_CONSTANT_INITIALIZER_H__ +#define __ONERT_COMPILER_ACL_NEON_CONSTANT_INITIALIZER_H__ + +#include +#include +#include "TensorBuilder.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +class ConstantInitializer : public IConstantInitializer +{ +public: + ConstantInitializer(const ir::Operands &operands, + const std::shared_ptr &tensor_builder); + +public: + void visit(const ir::operation::BatchToSpaceND &) override; + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::FullyConnected &) override; + void visit(const ir::operation::LSTM &) override; + void visit(const ir::operation::RNN &) override; + void visit(const ir::operation::SpaceToBatchND &) override; + void visit(const ir::operation::TransposeConv &) override; + +private: + std::shared_ptr tensor_builder() const override { return _tensor_builder; } + void copyInputInitialize(const ir::Operation &node, uint32_t index); + void permuteInputInitialize(const ir::Operation &node, uint32_t index); + +private: + std::shared_ptr _tensor_builder; +}; + +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_COMPILER_ACL_NEON_CONSTANT_INITIALIZER_H__ diff --git a/runtime/onert/backend/acl_neon/KernelGenerator.cc b/runtime/onert/backend/acl_neon/KernelGenerator.cc new file mode 100644 index 000000000..42a115438 --- /dev/null +++ b/runtime/onert/backend/acl_neon/KernelGenerator.cc @@ -0,0 +1,2030 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "KernelGenerator.h" + +#include // Include all ARM Compute NEON functions +#include // Include all ARM Compute EX NEON functions +#include + +#include +#include +#include +#include + +#include "ir/Index.h" +#include "ir/DataType.h" +#include "ir/InternalType.h" +#include "exec/NopFunction.h" +#include "util/logging.h" +#include "util/Utils.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +using ::onert::backend::acl_common::asAclFunction; +using ActivationBuilder = ::onert::backend::acl_common::AclActivationBuilder< + ::arm_compute::ITensor, ::arm_compute::NEActivationLayer, acl_common::AclFunction>; + +KernelGenerator::KernelGenerator(const ir::Operands &ctx, + const std::shared_ptr &tensor_builder) + : _ctx(ctx), _tensor_builder(tensor_builder), _current_op_seq_layout(ir::Layout::UNKNOWN) +{ + // DO NOTHING +} + +void KernelGenerator::visit(const ir::OpSequence &op_seq) +{ + // TODO Move this to IKernelGenerator + // (all derivatives have the same implementation for this) + assert(!_return_fn_seq); + _return_fn_seq = std::make_unique(); + _current_op_seq_layout = op_seq.getLayout(); + for (const auto &e : op_seq.operations()) + { + const auto &node = *(e.node); + node.accept(*this); + _return_fn_seq->append(releaseFunction()); + } +} + +void KernelGenerator::visit(const ir::operation::Abs &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Abs::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::ABS}; + + auto fn = std::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(input_alloc->handle(), output_alloc->handle(), act_info); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ArgMax &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ArgMax::Input::INPUT)}; + + const auto ifm_rank = node.param().rank; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto frontend_layout = _current_op_seq_layout; + auto backend_layout = ifm_alloc->layout(); + + int axis_value = node.param().axis; + if (axis_value < 0) + { + axis_value += ifm_rank; + } + assert(axis_value >= 0 && axis_value < ifm_rank); + const auto fixed_axis = + acl_common::ToARMComputeAxis(ifm_rank, axis_value, frontend_layout, backend_layout).value(); + + auto fn = std::make_unique<::arm_compute::NEArgMinMaxLayer>(); + + fn->configure(ifm_alloc->handle(), fixed_axis, ofm_alloc->handle(), + arm_compute::ReductionOperation::ARG_IDX_MAX); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::BatchToSpaceND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::BatchToSpaceND::Input::INPUT)}; + const auto block_size_index{ + node.getInputs().at(ir::operation::BatchToSpaceND::Input::BLOCK_SIZE)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto block_size_alloc = _tensor_builder->at(block_size_index).get(); + + assert(_ctx.at(block_size_index).data()); + + auto fn = std::make_unique<::arm_compute::NEBatchToSpaceLayer>(); + + fn->configure(ifm_alloc->handle(), block_size_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Cast &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Cast::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::NECast>(); + + auto input_sub_type = _ctx.at(ifm_index).typeInfo().type() == ir::DataType::BOOL8 + ? arm_compute::SubDataType::BOOL + : arm_compute::SubDataType::NONE; + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), input_sub_type); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Conv2D &node) +{ + using ir::operation::Conv2D; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(Conv2D::Input::INPUT)}; + const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in]. + const auto &ker_shape = _ctx.at(ker_index).shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + + const auto stride = node.param().stride; + const auto padding = ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, + ker_width, ker_height); + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto ker_alloc = _tensor_builder->at(ker_index).get(); + auto bias_alloc = _tensor_builder->at(bias_index).get(); + + const auto conv_info = acl_common::asPadStrideInfo(padding, stride); + const auto act_info = acl_common::asActivationLayerInfo(activation); + + auto fn = std::make_unique<::arm_compute::NEConvolutionLayer>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + fn->configure(ifm_alloc->handle(), ker_alloc->handle(), bias_alloc->handle(), ofm_alloc->handle(), + conv_info, ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), act_info); + + _return_fn = asAclFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::DepthToSpace &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::DepthToSpace::Input::INPUT)}; + + auto block_size = node.param().block_size; + assert(block_size > 0); + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::NEDepthToSpaceLayerEx>(); + + fn->configure(input_alloc->handle(), output_alloc->handle(), block_size); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::DepthwiseConv2D &node) +{ + using ir::operation::DepthwiseConv2D; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(DepthwiseConv2D::Input::INPUT)}; + const auto ker_index{node.getInputs().at(DepthwiseConv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(DepthwiseConv2D::Input::BIAS)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + // Kernel format is [1, kernel_height, kernel_width, depth_out]. + const auto &ker_shape = _ctx.at(ker_index).shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + + const auto stride = node.param().stride; + const auto padding = ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, + ker_width, ker_height); + const auto multiplier = node.param().multiplier; + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto ker_alloc = _tensor_builder->at(ker_index).get(); + auto bias_alloc = _tensor_builder->at(bias_index).get(); + + const auto conv_info = acl_common::asPadStrideInfo(padding, stride); + const auto act_info = acl_common::asActivationLayerInfo(activation); + + { + auto fn = std::make_unique<::arm_compute::NEDepthwiseConvolutionLayer>(); + + fn->configure(ifm_alloc->handle(), ker_alloc->handle(), bias_alloc->handle(), + ofm_alloc->handle(), conv_info, multiplier, act_info); + + _return_fn = asAclFunction(std::move(fn)); + } +} + +void KernelGenerator::visit(const ir::operation::Dequantize &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Dequantize::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::NEDequantizationLayer>(); + + fn->configure(input_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::MaxPool2D &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::MaxPool2D::Input::INPUT)}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + + const auto kh = node.param().kh; + const auto kw = node.param().kw; + const auto stride = node.param().stride; + const auto padding = + ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh); + const auto activation = node.param().activation; + + VERBOSE(MaxPool2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(MaxPool2D) << "IFM_W: " << ifm_shape.W << std::endl; + VERBOSE(MaxPool2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(MaxPool2D) << "OFM_W: " << ofm_shape.W << std::endl; + VERBOSE(MaxPool2D) << "KER_H: " << kh << std::endl; + VERBOSE(MaxPool2D) << "KER_W: " << kw << std::endl; + VERBOSE(MaxPool2D) << "STRIDE_H: " << stride.vertical << std::endl; + VERBOSE(MaxPool2D) << "STRIDE_W: " << stride.horizontal << std::endl; + VERBOSE(MaxPool2D) << "PAD(T): " << padding.top << std::endl; + VERBOSE(MaxPool2D) << "PAD(B): " << padding.bottom << std::endl; + VERBOSE(MaxPool2D) << "PAD(L): " << padding.left << std::endl; + VERBOSE(MaxPool2D) << "PAD(R): " << padding.right << std::endl; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::MAX, + ::arm_compute::Size2D{kw, kh}, + acl_common::asPadStrideInfo(padding, stride)}; + + auto fn = std::make_unique<::arm_compute::NEPoolingLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info); + + _return_fn = std::make_unique( + asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Mean &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Mean::Input::INPUT)}; + const auto &axes{node.param().axes}; + const auto keep_dims{node.param().keep_dims}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + + // Convert to ACL axes taking into account negative values and possible duplicates. + std::set acl_axes; + const int ifm_rank = node.param().rank; + for (int axis : axes) + { + if (axis < 0) + axis += ifm_rank; + acl_axes.insert( + acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value()); + } + + arm_compute::Coordinates fixed_axis; + for (const auto axis : acl_axes) + { + fixed_axis.set(fixed_axis.num_dimensions(), axis); + } + + // NOTE NEReduceMean has a bug that does not support NHWC layout + // NEReduceMean intermediate tensors are always NCHW layout + auto fn = std::make_unique<::arm_compute::NEReduceMeanEx>(); + + fn->configure(ifm_alloc->handle(), fixed_axis, keep_dims, ofm_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::AvgPool2D &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::AvgPool2D::Input::INPUT)}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + + const auto kh = node.param().kh; + const auto kw = node.param().kw; + const auto stride = node.param().stride; + const auto padding = + ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh); + const auto activation = node.param().activation; + + VERBOSE(AvgPool2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(AvgPool2D) << "IFM_W: " << ifm_shape.W << std::endl; + VERBOSE(AvgPool2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(AvgPool2D) << "OFM_W: " << ofm_shape.W << std::endl; + VERBOSE(AvgPool2D) << "KER_H: " << kh << std::endl; + VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl; + VERBOSE(AvgPool2D) << "STRIDE_H: " << stride.vertical << std::endl; + VERBOSE(AvgPool2D) << "STRIDE_W: " << stride.horizontal << std::endl; + VERBOSE(AvgPool2D) << "PAD(T): " << padding.top << std::endl; + VERBOSE(AvgPool2D) << "PAD(B): " << padding.bottom << std::endl; + VERBOSE(AvgPool2D) << "PAD(L): " << padding.left << std::endl; + VERBOSE(AvgPool2D) << "PAD(R): " << padding.right << std::endl; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + ::arm_compute::PoolingLayerInfo info{ + ::arm_compute::PoolingType::AVG, ::arm_compute::Size2D{kw, kh}, + acl_common::asPadStrideInfo(padding, stride), true /* exclude_padding */}; + + auto fn = std::make_unique<::arm_compute::NEPoolingLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info); + + _return_fn = std::make_unique( + asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Concat &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + + std::vector input_indexes; + for (const auto &input : node.getInputs()) + input_indexes.emplace_back(input); + + const auto axis = node.param().axis; + + // Concat elimination check + bool eliminated = _tensor_builder->areSubTensorsOf(ofm_index, node.getInputs()); + if (eliminated) + { + // If concat eliminated, return a NOP IFunction + VERBOSE(acl_neon_KernelGenerator_Concat) << "Concat eliminated" << std::endl; + _return_fn = std::make_unique(); + return; + } + + auto output_alloc = _tensor_builder->at(ofm_index).get(); + std::vector<::arm_compute::ITensor *> input_tensors; + for (const auto &ifm_ind : input_indexes) + input_tensors.emplace_back(_tensor_builder->at(ifm_ind)->handle()); + + std::unique_ptr<::arm_compute::IFunction> fn; + if (input_indexes.size() < 2) + { + auto l = std::make_unique<::arm_compute::NECopy>(); + l->configure(input_tensors.at(0), output_alloc->handle()); + fn = std::move(l); + } + else + { + auto l = std::make_unique<::arm_compute::NEConcatenateLayer>(); + const auto rank = node.param().rank; + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = output_alloc->layout(); + const auto fixed_axis = + acl_common::ToARMComputeAxis(rank, axis, frontend_layout, backend_layout).value(); + l->configure(input_tensors, output_alloc->handle(), fixed_axis); + fn = std::move(l); + } + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::EmbeddingLookup &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto lookups_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::LOOKUPS)}; + const auto values_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::VALUES)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto lookups_alloc = _tensor_builder->at(lookups_index).get(); + auto values_alloc = _tensor_builder->at(values_index).get(); + + auto fn = std::make_unique<::arm_compute::NEEmbeddingLookup>(); + + fn->configure(values_alloc->handle(), output_alloc->handle(), lookups_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Floor &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Floor::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::NEFloor>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::FullyConnected &node) +{ + using ir::operation::FullyConnected; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)}; + const auto weight_index{node.getInputs().at(FullyConnected::Input::WEIGHT)}; + const auto bias_index{node.getInputs().at(FullyConnected::Input::BIAS)}; + + const auto input_rank = _ctx.at(input_index).shape().rank(); + + const auto output_size = + _ctx.at(output_index).shape().dim(_ctx.at(output_index).shape().rank() - 1); + UNUSED_RELEASE(output_size); + assert(_ctx.at(bias_index).shape().dim(0) == output_size); + assert(_ctx.at(weight_index).shape().dim(0) == output_size); + const auto batch_size = + _ctx.at(output_index).shape().dim(_ctx.at(output_index).shape().rank() - 2); + const auto input_size = + _ctx.at(weight_index).shape().dim(_ctx.at(weight_index).shape().rank() - 1); + + // Check for reshaping input's shape into rank-2 + bool needs_reshape = false; + ir::Shape reshape(2); + if (input_rank == 3 || input_rank == 4) + { + const auto &ifm_shape = _ctx.at(input_index).shape(); + auto feature_size = 1; + for (int i = 0; i < ifm_shape.rank(); ++i) + { + feature_size *= ifm_shape.dim(i); + } + + UNUSED_RELEASE(feature_size); + assert(feature_size == batch_size * input_size); + + // for reshaping + needs_reshape = true; + reshape.dim(0) = batch_size; /* H */ + reshape.dim(1) = input_size; /* W */ + } + + const auto activation = node.param().activation; + + auto output_alloc = _tensor_builder->at(output_index).get(); + const auto input_alloc = _tensor_builder->at(input_index).get(); + const auto weight_alloc = _tensor_builder->at(weight_index).get(); + const auto bias_alloc = _tensor_builder->at(bias_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto acl_layout = output_alloc->handle()->info()->data_layout(); + + auto fn = std::make_unique( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + arm_compute::NEFullyConnectedReshapingLayer::KernelType kernel_type = + arm_compute::NEFullyConnectedReshapingLayer::KernelType::GENERAL; + if (_ctx.at(weight_index).isConstant()) + { + kernel_type = arm_compute::NEFullyConnectedReshapingLayer::KernelType::PREPROCESSED_WEIGHTS; + assert(_ctx.at(weight_index).data()); + } + + fn->configure( + input_alloc->handle(), weight_alloc->handle(), bias_alloc->handle(), output_alloc->handle(), + needs_reshape, + ::onert::backend::acl_common::asTensorShape( + reshape, frontend_layout, ::onert::backend::acl_common::asRuntimeLayout(acl_layout)), + kernel_type); + + _return_fn = std::make_unique( + asAclFunction(std::move(fn)), + ActivationBuilder::generate(activation, output_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::HashtableLookup &node) +{ + const auto output_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::OUTPUT)}; + const auto hits_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::HITS)}; + + const auto lookups_index{node.getInputs().at(ir::operation::HashtableLookup::Input::LOOKUPS)}; + const auto keys_index{node.getInputs().at(ir::operation::HashtableLookup::Input::KEYS)}; + const auto values_index{node.getInputs().at(ir::operation::HashtableLookup::Input::VALUES)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto hits_alloc = _tensor_builder->at(hits_index).get(); + + auto lookups_alloc = _tensor_builder->at(lookups_index).get(); + auto keys_alloc = _tensor_builder->at(keys_index).get(); + auto values_alloc = _tensor_builder->at(values_index).get(); + + auto fn = std::make_unique<::arm_compute::NEHashtableLookup>(); + + fn->configure(lookups_alloc->handle(), keys_alloc->handle(), values_alloc->handle(), + output_alloc->handle(), hits_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Gather &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + + const auto ifm_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)}; + const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + + const auto ifm_rank = node.param().rank; + const auto axis_raw = node.param().axis; + const auto axis_value = (axis_raw < 0 ? (ifm_rank + axis_raw) : axis_raw); + // Converting in reverse order + const int axis = ::onert::backend::acl_common::ToARMComputeAxis(ifm_rank, axis_value).value(); + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto indices_alloc = _tensor_builder->at(indices_index).get(); + const auto backend_layout = ofm_alloc->layout(); + UNUSED_RELEASE(backend_layout); + + // NOTE The frontend layout and backend layout must be the same for this operation. + // If not the same, we have to add a stage(?) to perform permutation of output tensor. It + // is not not efficient even if it works well. If so, it would be better to set the + // layout of these backend tensors to the same layout. + // There is also one thing we have to think about. This operation depends on the layout of + // a model. For example, if a model in NHWC has this operation as output rank == 4, indices + // rank == 2 and axis == 2, this operation should work as the axis W and C, but the axis W + // and C are not sequential in NCHW. So the backend in NCHW cannot handle this case. + assert(backend_layout == ifm_alloc->layout()); + assert(backend_layout == indices_alloc->layout()); + assert(ifm_rank < 4 || _current_op_seq_layout == backend_layout); + + auto fn = std::make_unique<::arm_compute::NEGatherEx>(); + + fn->configure(ifm_alloc->handle(), indices_alloc->handle(), ofm_alloc->handle(), axis); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::InstanceNorm &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::InstanceNorm::Input::INPUT)}; + const auto gamma_index{node.getInputs().at(ir::operation::InstanceNorm::Input::GAMMA)}; + const auto beta_index{node.getInputs().at(ir::operation::InstanceNorm::Input::BETA)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto gamma_alloc = _tensor_builder->at(gamma_index).get(); + auto beta_alloc = _tensor_builder->at(beta_index).get(); + auto epsilon = node.param().epsilon; + auto activation = node.param().activation; + + auto fn = std::make_unique<::arm_compute::NEInstanceNormalizationLayerEx>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), gamma_alloc->handle(), + beta_alloc->handle(), epsilon); + + _return_fn = std::make_unique( + asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::L2Normalization &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::L2Normalization::Input::INPUT)}; + + // {CL|Neon}L2Normalization performs the reduction only along dimension 0 + // L2 Normalization always performs the reduction along the depth axis + // Thus, we repurpose {CL|Neon}NormalizationLayers to act as depthwise L2 normalizations by + // choosing normalization parameters as below + + const auto &ifm_shape = _ctx.at(ifm_index).shape(); + // TODO Support optional constant dimension that normalization would be performed on + const auto normalization_axis = node.param().rank - 1; + int32_t radius = + 2 * ifm_shape.dim(normalization_axis) + 1; // normSize = depth(last dimension) * 2 + 1 + float alpha = 1.0f; // In the implementation to make alpha_ become 1 + float beta = 0.5f; // pow(reduction, -0.5) = 1 / sqrt(reduction) + float bias = 0.0f; // Don't offset the reduction. + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const auto norm_info = ::arm_compute::NormalizationLayerInfo(::arm_compute::NormType::CROSS_MAP, + radius, alpha, beta, bias, false); + + auto fn = std::make_unique<::arm_compute::NENormalizationLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), norm_info); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::L2Pool2D &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::L2Pool2D::Input::INPUT)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + + uint32_t kw = node.param().kw; + uint32_t kh = node.param().kh; + const auto stride = node.param().stride; + const auto padding = + ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh); + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + ::arm_compute::PoolingLayerInfo info{ + ::arm_compute::PoolingType::L2, ::arm_compute::Size2D{kw, kh}, + ::onert::backend::acl_common::asPadStrideInfo(padding, stride)}; + + auto fn = std::make_unique<::arm_compute::NEPoolingLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info); + + _return_fn = std::make_unique( + asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::LocalResponseNormalization &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{ + node.getInputs().at(ir::operation::LocalResponseNormalization::Input::INPUT)}; + + auto radius = node.param().radius; + auto alpha = node.param().alpha; + auto beta = node.param().beta; + auto bias = node.param().bias; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const auto norm_info = ::arm_compute::NormalizationLayerInfo( + ::arm_compute::NormType::CROSS_MAP, radius * 2 + 1, alpha, beta, bias, false); + + auto fn = std::make_unique<::arm_compute::NENormalizationLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), norm_info); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::LogicalAnd &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input0_index{node.getInputs().at(ir::operation::LogicalAnd::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::LogicalAnd::Input::INPUT1)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input0_alloc = _tensor_builder->at(input0_index).get(); + auto input1_alloc = _tensor_builder->at(input1_index).get(); + + auto fn = std::make_unique<::arm_compute::NELogicalAnd>(); + + fn->configure(input0_alloc->handle(), input1_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::LogicalNot &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::LogicalNot::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::NEBitwiseNot>(); + + fn->configure(input_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::LogicalOr &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input0_index{node.getInputs().at(ir::operation::LogicalOr::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::LogicalOr::Input::INPUT1)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input0_alloc = _tensor_builder->at(input0_index).get(); + auto input1_alloc = _tensor_builder->at(input1_index).get(); + + auto fn = std::make_unique<::arm_compute::NELogicalOr>(); + + fn->configure(input0_alloc->handle(), input1_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Logistic &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Logistic::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LOGISTIC}; + + // NOTE NEActivationLayer can generate produce erroneous results. it were caused by 'vexpq_f32()'. + // The neon function returns a value outside of the limit of representation in float as 'NaN' + // instead of 'INF', and then the result of this op will be errors due to the 'NaN'. + auto fn = std::make_unique<::arm_compute::NEActivationLayerEx>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), act_info); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::LSTM &node) +{ + // TODO Support dynamic rnn + // TODO Fix subtle error in the case of non-CIFG, non-peephole and No Projection. + const auto scratch_buffer_index{ + node.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)}; + const auto output_state_out_index{ + node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT_STATE_OUT)}; + const auto cell_state_out_index{ + node.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)}; + const auto output_index{node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)}; + + const auto input_index{node.getInputs().at(ir::operation::LSTM::Input::INPUT)}; + const auto input_to_input_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_INPUT_WEIGHTS)}; // optional + const auto input_to_forget_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_FORGET_WEIGHTS)}; + const auto input_to_cell_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_CELL_WEIGHTS)}; + const auto input_to_output_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)}; + const auto recurrent_to_input_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)}; // optional + const auto recurrent_to_forget_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS)}; + const auto recurrent_to_cell_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_CELL_WEIGHTS)}; + const auto recurrent_to_output_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS)}; + const auto cell_to_input_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_INPUT_WEIGHTS)}; // optional + const auto cell_to_forget_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_FORGET_WEIGHTS)}; // optional + const auto cell_to_output_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_OUTPUT_WEIGHTS)}; // optional + const auto input_gate_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_GATE_BIAS)}; + const auto forget_gate_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::FORGET_GATE_BIAS)}; + const auto cell_bias_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_BIAS)}; + const auto output_gate_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_GATE_BIAS)}; + const auto projection_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_WEIGHTS)}; // optional + const auto projection_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_BIAS)}; // optional + const auto output_state_in_index{ + node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_STATE_IN)}; + const auto cell_state_in_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_STATE_IN)}; + const auto cell_threshold = node.param().cell_threshold; + const auto projection_threshold = node.param().projection_threshold; + + bool has_input_to_input_weights = _ctx.at(input_to_input_weights_index).shape().dim(0) != 0 && + _ctx.at(input_to_input_weights_index).shape().dim(1) != 0; + bool has_recurrent_to_input_weights = + _ctx.at(recurrent_to_input_weights_index).shape().dim(0) != 0 && + _ctx.at(recurrent_to_input_weights_index).shape().dim(1) != 0; + bool has_cell_to_forget_weights = _ctx.at(cell_to_forget_weights_index).shape().dim(0) != 0; + bool has_cell_to_output_weights = _ctx.at(cell_to_output_weights_index).shape().dim(0) != 0; + bool has_projection_weights = _ctx.at(projection_weights_index).shape().dim(0) != 0 && + _ctx.at(projection_weights_index).shape().dim(1) != 0; + bool has_projection_bias = _ctx.at(projection_bias_index).shape().dim(0); + + // NOTE The input_to_input_weights and the recurrent_to_input_weights do not exist in CIFG. + // true: no CIFG + // false: CIFG + // NOTE The cell_to_input_weights does not exist in non-peephole although regular LSTM(non-CIFG). + bool has_cifg_param = has_input_to_input_weights && has_recurrent_to_input_weights; + + // NOTE The cell_to_forget_weights and the cell_to_output_weights exist in peephole. + // But the cell_to_input_weights does not exist in regular CIFG although peephole. + // true: peephole + // false: no peephole + bool has_peephole_param = has_cell_to_forget_weights && has_cell_to_output_weights; + + // NOTE Although the projection weights has data the projection bias may not have data. + bool has_projection_param = has_projection_weights; + + const auto activation = node.param().activation; + const auto cell_clip = cell_threshold; + const auto projection_clip = projection_threshold; + assert(cell_clip >= 0.f && projection_clip >= 0.f); + + auto scratch_buffer_alloc = _tensor_builder->at(scratch_buffer_index).get(); + auto output_state_out_alloc = _tensor_builder->at(output_state_out_index).get(); + auto cell_state_out_alloc = _tensor_builder->at(cell_state_out_index).get(); + auto output_alloc = _tensor_builder->at(output_index).get(); + + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto input_to_forget_weights_alloc = _tensor_builder->at(input_to_forget_weights_index).get(); + auto input_to_cell_weights_alloc = _tensor_builder->at(input_to_cell_weights_index).get(); + auto input_to_output_weights_alloc = _tensor_builder->at(input_to_output_weights_index).get(); + auto recurrent_to_forget_weights_alloc = + _tensor_builder->at(recurrent_to_forget_weights_index).get(); + auto recurrent_to_cell_weights_alloc = _tensor_builder->at(recurrent_to_cell_weights_index).get(); + auto recurrent_to_output_weights_alloc = + _tensor_builder->at(recurrent_to_output_weights_index).get(); + + auto forget_gate_bias_alloc = _tensor_builder->at(forget_gate_bias_index).get(); + auto cell_bias_alloc = _tensor_builder->at(cell_bias_index).get(); + auto output_gate_bias_alloc = _tensor_builder->at(output_gate_bias_index).get(); + auto output_state_in_alloc = _tensor_builder->at(output_state_in_index).get(); + auto cell_state_in_alloc = _tensor_builder->at(cell_state_in_index).get(); + + auto act_info = ::onert::backend::acl_common::asActivationLayerInfo(activation); + + auto fn = std::make_unique<::arm_compute::NELSTMLayer>(); + + ::arm_compute::LSTMParams<::arm_compute::ITensor> lstm_params{}; + if (has_cifg_param) + { + auto input_to_input_weights_alloc = + _tensor_builder->at(input_to_input_weights_index).get(); // optional + auto recurrent_to_input_weights_alloc = + _tensor_builder->at(recurrent_to_input_weights_index).get(); // optional + auto cell_to_input_weights_handle = + has_peephole_param ? _tensor_builder->at(cell_to_input_weights_index).get()->handle() + : nullptr; // optional (non-cifg && peephole) + auto input_gate_bias_alloc = _tensor_builder->at(input_gate_bias_index).get(); // optional + lstm_params.set_cifg_params(input_to_input_weights_alloc->handle(), + recurrent_to_input_weights_alloc->handle(), + cell_to_input_weights_handle, input_gate_bias_alloc->handle()); + } + if (has_peephole_param) + { + auto cell_to_forget_weights_alloc = + _tensor_builder->at(cell_to_forget_weights_index).get(); // optional + auto cell_to_output_weights_alloc = + _tensor_builder->at(cell_to_output_weights_index).get(); // optional + lstm_params.set_peephole_params(cell_to_forget_weights_alloc->handle(), + cell_to_output_weights_alloc->handle()); + } + if (has_projection_param) + { + auto projection_weights_alloc = _tensor_builder->at(projection_weights_index).get(); // optional + auto projection_bias_handle = has_projection_bias + ? _tensor_builder->at(projection_bias_index).get()->handle() + : nullptr; // optional + lstm_params.set_projection_params(projection_weights_alloc->handle(), projection_bias_handle); + } + + fn->configure( + input_alloc->handle(), input_to_forget_weights_alloc->handle(), + input_to_cell_weights_alloc->handle(), input_to_output_weights_alloc->handle(), + recurrent_to_forget_weights_alloc->handle(), recurrent_to_cell_weights_alloc->handle(), + recurrent_to_output_weights_alloc->handle(), forget_gate_bias_alloc->handle(), + cell_bias_alloc->handle(), output_gate_bias_alloc->handle(), output_state_in_alloc->handle(), + cell_state_in_alloc->handle(), scratch_buffer_alloc->handle(), + output_state_out_alloc->handle(), cell_state_out_alloc->handle(), output_alloc->handle(), + lstm_params, act_info, cell_clip, projection_clip); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Mul &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Mul::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Mul::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::NEPixelWiseMultiplication>(); + + // RoundingPolicy for scale:1.0 is only allowed RoundingPolicy::TO_ZERO + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle(), 1.0, // scale + arm_compute::ConvertPolicy::SATURATE, arm_compute::RoundingPolicy::TO_ZERO); + + _return_fn = std::make_unique( + asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Neg &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Neg::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::NENegLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Pack &node) +{ + const auto output_index{node.getOutputs().at(0)}; + auto axis{node.param().axis}; + + const auto output_rank = node.param().rank; + + std::vector input_indexes; + for (const auto &input_index : node.getInputs()) + input_indexes.emplace_back(input_index); + + auto output = _tensor_builder->at(output_index).get()->handle(); + std::vector inputs; + for (const auto &input_index : input_indexes) + inputs.emplace_back(_tensor_builder->at(input_index)->handle()); + + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = _tensor_builder->at(output_index).get()->layout(); + + if (axis < 0) + axis += output_rank; + axis = acl_common::ToARMComputeAxis(output_rank, axis, frontend_layout, backend_layout).value(); + + auto fn = std::make_unique<::arm_compute::NEStackLayer>(); + + fn->configure(inputs, axis, output); + + _return_fn = asAclFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Pad &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)}; + const auto pad_index{node.getInputs().at(ir::operation::Pad::Input::PAD)}; + const auto output_index{node.getOutputs().at(0)}; + assert(_ctx.at(pad_index).data()); + + auto rank = node.param().rank; + auto pad_base = _ctx.at(pad_index).data()->base(); + + auto input = _tensor_builder->at(input_index).get()->handle(); + auto output = _tensor_builder->at(output_index).get()->handle(); + + ::arm_compute::PaddingList padding_list; + padding_list.resize(rank); + for (int32_t n = 0; n < rank; ++n) + { + const int32_t *from = reinterpret_cast(pad_base) + (n * 2); + + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = _tensor_builder->at(input_index).get()->layout(); + const auto axis = + acl_common::ToARMComputeAxis(rank, n, frontend_layout, backend_layout).value(); + padding_list[axis] = ::arm_compute::PaddingInfo{from[0], from[1]}; + } + + const auto input_type = _ctx.at(input_index).typeInfo(); + UNUSED_RELEASE(input_type); + assert(input->info()->data_type() == acl_common::asDataType(input_type.type())); + assert(input->info()->quantization_info() == + ::arm_compute::QuantizationInfo(input_type.scale(), input_type.offset())); + const auto pixel_value = + ::arm_compute::PixelValue(0, input->info()->data_type(), input->info()->quantization_info()); + + auto fn = std::make_unique<::arm_compute::NEPadLayer>(); + fn->configure(input, output, padding_list, pixel_value); + + _return_fn = asAclFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Permute &node) +{ + const auto ofm_idx{node.getOutputs().at(0)}; + const auto ifm_idx{node.getInputs().at(0)}; + const auto permute_type = node.getPermuteType(); + auto ofm_alloc = _tensor_builder->at(ofm_idx).get(); + auto ifm_alloc = _tensor_builder->at(ifm_idx).get(); + const auto rank = _ctx.at(ofm_idx).shape().rank(); + assert(_ctx.at(ifm_idx).shape().rank() == _ctx.at(ofm_idx).shape().rank()); + + std::unique_ptr<::arm_compute::IFunction> fn; + arm_compute::PermutationVector pv; + if (permute_type == ir::operation::Permute::Type::NCHW_TO_NHWC && rank == 4) + { + // WHCN -> CWHN + pv = arm_compute::PermutationVector{2, 0, 1}; + + auto l = std::make_unique<::arm_compute::NEPermute>(); + + l->configure(ifm_alloc->handle(), ofm_alloc->handle(), pv); + + fn = std::move(l); + } + else if (permute_type == ir::operation::Permute::Type::NHWC_TO_NCHW && rank == 4) + { + // CWHN -> WHCN + pv = arm_compute::PermutationVector{1, 2, 0}; + + auto l = std::make_unique<::arm_compute::NEPermute>(); + + l->configure(ifm_alloc->handle(), ofm_alloc->handle(), pv); + + fn = std::move(l); + } + else + { + auto l = std::make_unique<::arm_compute::NECopy>(); + + l->configure(ifm_alloc->handle(), ofm_alloc->handle()); + + fn = std::move(l); + } + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::PReLU &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::PReLU::Input::INPUT)}; + const auto alpha_index{node.getInputs().at(ir::operation::PReLU::Input::ALPHA)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto alpha_alloc = _tensor_builder->at(alpha_index).get(); + + std::unique_ptr<::arm_compute::IFunction> fn; + + auto l = std::make_unique<::arm_compute::NEPReLU>(); + + l->configure(ifm_alloc->handle(), alpha_alloc->handle(), ofm_alloc->handle()); + + fn = std::move(l); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReduceMax &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ReduceMax::Input::INPUT)}; + const auto &axes{node.param().axes}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + + // Convert to ACL axes taking into account negative values and possible duplicates. + std::set acl_axes; + const int ifm_rank = node.param().rank; + for (int axis : axes) + { + if (axis < 0) + axis += ifm_rank; + acl_axes.insert( + acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value()); + } + + arm_compute::Coordinates reduce_axes; + for (const auto axis : acl_axes) + { + reduce_axes.set(reduce_axes.num_dimensions(), axis); + } + + auto fn = std::make_unique<::arm_compute::NEReduceOperation>(); + + fn->configure(ifm_alloc->handle(), reduce_axes, false, ofm_alloc->handle(), + ::arm_compute::ReduceOperation::MAX); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReduceMin &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ReduceMin::Input::INPUT)}; + const auto &axes{node.param().axes}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + + // Convert to ACL axes taking into account negative values and possible duplicates. + std::set acl_axes; + const int ifm_rank = node.param().rank; + for (int axis : axes) + { + if (axis < 0) + axis += ifm_rank; + acl_axes.insert( + acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value()); + } + + arm_compute::Coordinates reduce_axes; + for (const auto axis : acl_axes) + { + reduce_axes.set(reduce_axes.num_dimensions(), axis); + } + + auto fn = std::make_unique<::arm_compute::NEReduceOperation>(); + + fn->configure(ifm_alloc->handle(), reduce_axes, false, ofm_alloc->handle(), + ::arm_compute::ReduceOperation::MIN); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReduceSum &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::ReduceSum::Input::INPUT)}; + const auto &axes{node.param().axes}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = input_alloc->layout(); + + // Convert to ACL axes taking into account negative values and possible duplicates. + std::set acl_axes; + const int input_rank = node.param().rank; + for (int axis : axes) + { + if (axis < 0) + axis += input_rank; + acl_axes.insert( + acl_common::ToARMComputeAxis(input_rank, axis, frontend_layout, backend_layout).value()); + } + + arm_compute::Coordinates fixed_axes; + for (const auto axis : acl_axes) + { + fixed_axes.set(fixed_axes.num_dimensions(), axis); + } + + auto fn = std::make_unique<::arm_compute::NEReduceSum>(); + + fn->configure(input_alloc->handle(), fixed_axes, false, output_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReLU &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::ReLU::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU}; + + fn->configure(input_alloc->handle(), output_alloc->handle(), act_info); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReLU1 &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ReLU1::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f}; + + auto fn = std::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), act_info); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ReLU6 &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ReLU6::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.0f}; + + auto fn = std::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), act_info); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Reshape &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Reshape::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + // NOTE This operation must not be changed the layout from frontend to backend + // So, PermutationOperationPass makes layouts of frontend and backend the same. + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = output_alloc->layout(); + assert((_ctx.at(input_index).shape().rank() < 4 && _ctx.at(output_index).shape().rank() < 4) || + frontend_layout == backend_layout); + UNUSED_RELEASE(frontend_layout); + UNUSED_RELEASE(backend_layout); + + auto fn = std::make_unique(); + + fn->configure(input_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::ResizeBilinear &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + + const auto ifm_index{node.getInputs().at(ir::operation::ResizeBilinear::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::NEScale>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), + ::arm_compute::InterpolationPolicy::BILINEAR, ::arm_compute::BorderMode::REPLICATE, + ::arm_compute::PixelValue(0.f), ::arm_compute::SamplingPolicy::TOP_LEFT); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::RNN &node) +{ + const auto output_index{node.getOutputs().at(ir::operation::RNN::Output::OUTPUT)}; + const auto hidden_state_out_index{ + node.getOutputs().at(ir::operation::RNN::Output::HIDDEN_STATE_OUT)}; + + const auto input_index{node.getInputs().at(ir::operation::RNN::Input::INPUT)}; + const auto weights_index{node.getInputs().at(ir::operation::RNN::Input::WEIGHTS)}; + const auto recurrent_weights_index{ + node.getInputs().at(ir::operation::RNN::Input::RECURRENT_WEIGHTS)}; + const auto bias_index{node.getInputs().at(ir::operation::RNN::Input::BIAS)}; + const auto hidden_state_in_index{node.getInputs().at(ir::operation::RNN::Input::HIDDEN_STATE_IN)}; + + const auto activation = node.param().activation; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto hidden_state_out_alloc = _tensor_builder->at(hidden_state_out_index).get(); + + auto input_alloc = _tensor_builder->at(input_index).get(); + auto weights_alloc = _tensor_builder->at(weights_index).get(); + auto recurrent_weights_alloc = _tensor_builder->at(recurrent_weights_index).get(); + auto bias_alloc = _tensor_builder->at(bias_index).get(); + auto hidden_state_in_alloc = _tensor_builder->at(hidden_state_in_index).get(); + auto act_info = ::onert::backend::acl_common::asActivationLayerInfo(activation); + + auto copy_layer = std::make_unique<::arm_compute::NECopy>(); + copy_layer->configure(hidden_state_in_alloc->handle(), hidden_state_out_alloc->handle()); + _return_fn = asAclFunction(std::move(copy_layer)); + + auto fn = std::make_unique<::arm_compute::NERNNLayerEx>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + fn->configure(input_alloc->handle(), weights_alloc->handle(), recurrent_weights_alloc->handle(), + bias_alloc->handle(), hidden_state_out_alloc->handle(), output_alloc->handle(), + act_info); + _return_fn = asAclFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::RSQRT &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::RSQRT::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::NERsqrtLayer>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle()); + + _return_fn = asAclFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Squeeze &node) +{ + // Squeeze is identical to reshape except that it has an optional dimensions input. + // In addition, optional dims_index is ignored since output tensor already has squeezed shape + // by freezer and toco + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Squeeze::Input::INPUT)}; + const auto dims{node.param().dims}; + const auto ndim{node.param().ndim}; + (void)dims; + (void)ndim; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + auto fn = std::make_unique(); + fn->configure(input_alloc->handle(), output_alloc->handle()); + auto acl_fn = asAclFunction(std::move(fn)); + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Tanh &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Tanh::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::TANH, 1.0f, 1.0f}; + + fn->configure(input_alloc->handle(), output_alloc->handle(), act_info); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Softmax &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Softmax::Input::INPUT)}; + const auto beta = node.param().beta; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::NESoftmaxLayer>( + _tensor_builder->acl_tensor_manager()->internal_buffer_manager()); + + fn->configure(input_alloc->handle(), output_alloc->handle(), beta); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::SpaceToBatchND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)}; + const auto block_size_index{ + node.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)}; + const auto paddings_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto block_size_alloc = _tensor_builder->at(block_size_index).get(); + auto paddings_alloc = _tensor_builder->at(paddings_index).get(); + + assert(_ctx.at(block_size_index).data()); + assert(_ctx.at(paddings_index).data()); + + // NESpaceToBatchLayer has a bug that padding's values are 0 even when zero point of QASYMM8 is + // not 0. + auto fn = std::make_unique<::arm_compute::NESpaceToBatchLayerEx>(); + + fn->configure(ifm_alloc->handle(), block_size_alloc->handle(), paddings_alloc->handle(), + ofm_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::SpaceToDepth &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::SpaceToDepth::Input::INPUT)}; + + auto block_size = node.param().block_size; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::arm_compute::NESpaceToDepthLayerEx>(); + + fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), block_size); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Split &node) +{ + // TODO Support this op by SubTensor + const auto ifm_index{node.getInputs().at(ir::operation::Split::Input::INPUT)}; + + assert(node.param().num_splits == static_cast(node.getOutputs().size())); + + const auto ifm_rank = node.param().rank; + std::vector output_indexes; + for (const auto &output : node.getOutputs()) + output_indexes.emplace_back(output); + + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + std::vector output_allocs; + for (const auto &ofm_ind : output_indexes) + output_allocs.emplace_back(_tensor_builder->at(ofm_ind).get()->handle()); + + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + auto axis = node.param().axis; + if (axis < 0) + axis += ifm_rank; + axis = acl_common::ToARMComputeAxis(ifm_rank, axis, frontend_layout, backend_layout).value(); + + auto fn = std::make_unique<::arm_compute::NESplit>(); + + fn->configure(ifm_alloc->handle(), output_allocs, axis); + + _return_fn = asAclFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::SQRT &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::SQRT::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::SQRT}; + + auto fn = std::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(input_alloc->handle(), output_alloc->handle(), act_info); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::SquaredDifference &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::RHS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::NEElementwiseSquaredDiff>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Sub &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Sub::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Sub::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::NEArithmeticSubtraction>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle(), + arm_compute::ConvertPolicy::SATURATE); + + _return_fn = std::make_unique( + asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Slice &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Slice::Input::INPUT)}; + const auto begins_index{node.getInputs().at(ir::operation::Slice::Input::BEGINS)}; + const auto sizes_index{node.getInputs().at(ir::operation::Slice::Input::SIZES)}; + + auto outputData_alloc = _tensor_builder->at(output_index).get(); + auto inputData_alloc = _tensor_builder->at(input_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = inputData_alloc->layout(); + + // Set initializers for indices data such as order of inputData + int input_rank = node.param().rank; + std::vector starts; + std::vector ends; + starts.resize(input_rank, 0); + ends.resize(input_rank, 0); + { + auto beginData_base = _ctx.at(begins_index).data()->base(); + auto sizeData_base = _ctx.at(sizes_index).data()->base(); + const int beginData_size = _ctx.at(begins_index).shape().num_elements(); + const int sizeData_size = _ctx.at(sizes_index).shape().num_elements(); + + using ir::DataType; + + UNUSED_RELEASE(beginData_size); + UNUSED_RELEASE(sizeData_size); + + assert(_ctx.at(begins_index).typeInfo().type() == DataType::INT32); + assert(_ctx.at(sizes_index).typeInfo().type() == DataType::INT32); + assert(beginData_size == input_rank); + assert(sizeData_size == input_rank); + + assert(beginData_base != nullptr); + for (int n = 0; n < input_rank; ++n) + { + auto axis = ::onert::backend::acl_common::ToARMComputeAxis(input_rank, n, frontend_layout, + backend_layout) + .value(); + + int32_t begin_value = *(reinterpret_cast(beginData_base) + n); + starts[axis] = begin_value; + + int32_t size_value = *(reinterpret_cast(sizeData_base) + n); + ends[axis] = begin_value + size_value; + } + } + + ::arm_compute::Coordinates starts_set; + ::arm_compute::Coordinates ends_set; + + for (size_t i = 0; i < starts.size(); ++i) + { + starts_set.set(i, starts[i]); + ends_set.set(i, ends[i]); + } + + auto fn = std::make_unique<::arm_compute::NESlice>(); + + fn->configure(inputData_alloc->handle(), outputData_alloc->handle(), starts_set, ends_set); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::StridedSlice &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)}; + const auto starts_index{node.getInputs().at(ir::operation::StridedSlice::Input::STARTS)}; + const auto ends_index{node.getInputs().at(ir::operation::StridedSlice::Input::ENDS)}; + const auto strides_index{node.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)}; + + auto outputData_alloc = _tensor_builder->at(output_index).get(); + auto inputData_alloc = _tensor_builder->at(input_index).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = inputData_alloc->layout(); + + // Set initializers for indices data such as order of inputData + int input_rank = node.param().rank; + std::vector starts; + std::vector ends; + std::vector strides; + starts.resize(input_rank, 0); + ends.resize(input_rank, 0); + strides.resize(input_rank, 0); + { + auto startData_base = _ctx.at(starts_index).data()->base(); + auto endData_base = _ctx.at(ends_index).data()->base(); + auto stridesData_base = _ctx.at(strides_index).data()->base(); + const int startData_size = _ctx.at(starts_index).shape().num_elements(); + const int endData_size = _ctx.at(ends_index).shape().num_elements(); + const int stridesData_size = _ctx.at(strides_index).shape().num_elements(); + + using ir::DataType; + + UNUSED_RELEASE(startData_size); + UNUSED_RELEASE(endData_size); + UNUSED_RELEASE(stridesData_size); + + assert(_ctx.at(starts_index).typeInfo().type() == DataType::INT32); + assert(_ctx.at(ends_index).typeInfo().type() == DataType::INT32); + assert(_ctx.at(strides_index).typeInfo().type() == DataType::INT32); + assert(startData_size == input_rank); + assert(endData_size == input_rank); + assert(stridesData_size == input_rank); + + assert(startData_base != nullptr); + for (int n = 0; n < input_rank; ++n) + { + auto axis = ::onert::backend::acl_common::ToARMComputeAxis(input_rank, n, frontend_layout, + backend_layout) + .value(); + + int32_t start_value = *(reinterpret_cast(startData_base) + n); + starts[axis] = start_value; + + int32_t end_value = *(reinterpret_cast(endData_base) + n); + ends[axis] = end_value; + + int32_t strides_value = *(reinterpret_cast(stridesData_base) + n); + strides[axis] = strides_value; + } + } + + // Set mask bits such as order of inputData + // FIXME Take the layouts into account. + const auto begin_mask = acl_common::ReorderBits(node.param().begin_mask, input_rank); + const auto end_mask = acl_common::ReorderBits(node.param().end_mask, input_rank); + const auto shrink_axis_mask = + acl_common::ReorderBits(node.param().shrink_axis_mask, input_rank); + + ::arm_compute::Coordinates starts_set; + ::arm_compute::Coordinates ends_set; + ::arm_compute::BiStrides strides_set; + + for (size_t i = 0; i < starts.size(); ++i) + { + starts_set.set(i, starts[i]); + ends_set.set(i, ends[i]); + strides_set.set(i, strides[i]); + } + + auto fn = std::make_unique<::arm_compute::NEStridedSlice>(); + + fn->configure(inputData_alloc->handle(), outputData_alloc->handle(), starts_set, ends_set, + strides_set, begin_mask, end_mask, shrink_axis_mask); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::TransposeConv &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ker_index{node.getInputs().at(ir::operation::TransposeConv::Input::KERNEL)}; + const auto ifm_index{node.getInputs().at(ir::operation::TransposeConv::Input::INPUT)}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ker_shape = _ctx.at(ker_index).shape().asFeature(_current_op_seq_layout); + + const auto stride = node.param().stride; + + assert((node.param().padding.type == ir::PaddingType::SAME) || + (node.param().padding.type == ir::PaddingType::VALID)); + auto padding = ir::calculatePadding(node.param().padding, ofm_shape, ifm_shape, stride, + ker_shape.W, ker_shape.H); + + uint32_t invalid_horizontal = 0; + uint32_t invalid_vertical = 0; + if (node.param().padding.type == ir::PaddingType::VALID) + { + invalid_horizontal = + ofm_shape.W - (1 + (ifm_shape.W - 1) * stride.horizontal) - (ker_shape.W - 1); + invalid_vertical = ofm_shape.H - (1 + (ifm_shape.H - 1) * stride.vertical) - (ker_shape.H - 1); + } + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto ker_alloc = _tensor_builder->at(ker_index).get(); + + const auto tconv_info = acl_common::asPadStrideInfo(padding, stride); + + auto fn = std::make_unique<::arm_compute::NETransposeConvLayer>(); + + fn->configure(ifm_alloc->handle(), ker_alloc->handle(), nullptr, ofm_alloc->handle(), tconv_info, + invalid_horizontal, invalid_vertical); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Transpose &node) +{ + const auto ofm_idx{node.getOutputs().at(0)}; + const auto ifm_idx{node.getInputs().at(ir::operation::Transpose::Input::INPUT)}; + const auto &perm{node.param().perm}; + + auto ofm_alloc = _tensor_builder->at(ofm_idx).get(); + const auto ifm_alloc = _tensor_builder->at(ifm_idx).get(); + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = ifm_alloc->layout(); + + const auto rank = node.param().rank; + std::vector pv(perm.cbegin(), perm.cend()); + auto backend_pv = ::onert::backend::acl_common::getARMComputePermutationVector( + rank, pv, frontend_layout, backend_layout); + + std::unique_ptr<::arm_compute::IFunction> fn; + + if (ifm_alloc->num_dimensions() <= 2 && ofm_alloc->num_dimensions() <= 2) + { + auto l = std::make_unique<::arm_compute::NETranspose>(); + + l->configure(ifm_alloc->handle(), ofm_alloc->handle()); + + fn = std::move(l); + } + else + { + auto l = std::make_unique<::arm_compute::NEPermute>(); + + l->configure(ifm_alloc->handle(), ofm_alloc->handle(), backend_pv); + + fn = std::move(l); + } + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Unpack &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Unpack::Input::INPUT)}; + auto axis{node.param().axis}; + + const auto input_rank = node.param().rank; + + std::vector output_indexes; + for (const auto &output_index : node.getOutputs()) + output_indexes.emplace_back(output_index); + + auto input = _tensor_builder->at(input_index).get()->handle(); + std::vector outputs; + for (const auto &output_index : output_indexes) + outputs.emplace_back(_tensor_builder->at(output_index)->handle()); + + const auto frontend_layout = _current_op_seq_layout; + const auto backend_layout = _tensor_builder->at(input_index).get()->layout(); + if (axis < 0) + axis += input_rank; + axis = acl_common::ToARMComputeAxis(input_rank, axis, frontend_layout, backend_layout).value(); + + auto fn = std::make_unique<::arm_compute::NEUnstack>(); + + fn->configure(input, outputs, axis); + + _return_fn = asAclFunction(std::move(fn)); +} + +void KernelGenerator::visit(const ir::operation::Add &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Add::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Add::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::NEArithmeticAddition>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle(), + arm_compute::ConvertPolicy::SATURATE); + + _return_fn = std::make_unique( + asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Div &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Div::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Div::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::NEElementwiseDivision>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle()); + + _return_fn = std::make_unique( + asAclFunction(std::move(fn)), ActivationBuilder::generate(activation, ofm_alloc->handle())); +} + +void KernelGenerator::visit(const ir::operation::Exp &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Exp::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::arm_compute::NEExpLayer>(); + + fn->configure(input_alloc->handle(), output_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Comparison &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input0_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)}; + + const auto comparison_type = node.param().comparison_type; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input0_alloc = _tensor_builder->at(input0_index).get(); + auto input1_alloc = _tensor_builder->at(input1_index).get(); + + auto fn = std::make_unique<::arm_compute::NEElementwiseComparison>(); + + fn->configure(input0_alloc->handle(), input1_alloc->handle(), output_alloc->handle(), + (arm_compute::ComparisonOperation)comparison_type); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Min &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Min::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Min::Input::RHS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::NEElementwiseMin>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::Max &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Max::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Max::Input::RHS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::arm_compute::NEElementwiseMax>(); + + fn->configure(lhs_alloc->handle(), rhs_alloc->handle(), ofm_alloc->handle()); + + auto acl_fn = asAclFunction(std::move(fn)); + + _return_fn = std::move(acl_fn); +} + +void KernelGenerator::visit(const ir::operation::OneHot &node) +{ + const auto out_idx{node.getOutputs().at(0)}; + const auto indices_idx{node.getInputs().at(ir::operation::OneHot::Input::INDICES)}; + const auto depth = node.param().depth; + const auto on_value = node.param().on_value; + const auto off_value = node.param().off_value; + const auto axis = node.param().axis; + + auto output_tensor = _tensor_builder->at(out_idx).get(); + auto indices_tensor = _tensor_builder->at(indices_idx).get(); + + auto fn = std::make_unique<::arm_compute::CPPOneHotEx>(); + fn->configure(indices_tensor->handle(), output_tensor->handle(), depth, on_value, off_value, + axis); + auto acl_fn = asAclFunction(std::move(fn)); + _return_fn = std::move(acl_fn); +} + +} // namespace acl_neon +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_neon/KernelGenerator.h b/runtime/onert/backend/acl_neon/KernelGenerator.h new file mode 100644 index 000000000..a29b07805 --- /dev/null +++ b/runtime/onert/backend/acl_neon/KernelGenerator.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_KERNEL_GENERATOR_H__ +#define __ONERT_BACKEND_ACL_NEON_KERNEL_GENERATOR_H__ + +#include + +#include "ir/Operands.h" +#include "TensorBuilder.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +class KernelGenerator : public IKernelGenerator +{ +public: + KernelGenerator(const ir::Operands &ctx, const std::shared_ptr &tensor_builder); + + void visit(const ir::OpSequence &) override; + void visit(const ir::operation::Abs &) override; + void visit(const ir::operation::ArgMax &) override; + void visit(const ir::operation::BatchToSpaceND &) override; + void visit(const ir::operation::Cast &) override; + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthToSpace &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::Dequantize &) override; + void visit(const ir::operation::MaxPool2D &) override; + void visit(const ir::operation::Mean &) override; + void visit(const ir::operation::AvgPool2D &) override; + void visit(const ir::operation::Concat &) override; + void visit(const ir::operation::EmbeddingLookup &) override; + void visit(const ir::operation::Floor &) override; + void visit(const ir::operation::FullyConnected &) override; + void visit(const ir::operation::Gather &) override; + void visit(const ir::operation::HashtableLookup &) override; + void visit(const ir::operation::InstanceNorm &) override; + void visit(const ir::operation::L2Normalization &) override; + void visit(const ir::operation::L2Pool2D &) override; + void visit(const ir::operation::LocalResponseNormalization &) override; + void visit(const ir::operation::LogicalAnd &) override; + void visit(const ir::operation::LogicalNot &) override; + void visit(const ir::operation::LogicalOr &) override; + void visit(const ir::operation::Logistic &) override; + void visit(const ir::operation::LSTM &) override; + void visit(const ir::operation::Mul &) override; + void visit(const ir::operation::Neg &) override; + void visit(const ir::operation::Pack &) override; + void visit(const ir::operation::Pad &) override; + void visit(const ir::operation::Permute &) override; + void visit(const ir::operation::PReLU &) override; + void visit(const ir::operation::ReduceMax &) override; + void visit(const ir::operation::ReduceMin &) override; + void visit(const ir::operation::ReduceSum &) override; + void visit(const ir::operation::ReLU &) override; + void visit(const ir::operation::ReLU1 &) override; + void visit(const ir::operation::ReLU6 &) override; + void visit(const ir::operation::Reshape &) override; + void visit(const ir::operation::ResizeBilinear &) override; + void visit(const ir::operation::RNN &) override; + void visit(const ir::operation::RSQRT &) override; + void visit(const ir::operation::Squeeze &) override; + void visit(const ir::operation::Tanh &) override; + void visit(const ir::operation::Softmax &) override; + void visit(const ir::operation::SpaceToBatchND &) override; + void visit(const ir::operation::SpaceToDepth &) override; + void visit(const ir::operation::Split &) override; + void visit(const ir::operation::SQRT &) override; + void visit(const ir::operation::SquaredDifference &) override; + void visit(const ir::operation::Sub &) override; + void visit(const ir::operation::Slice &) override; + void visit(const ir::operation::StridedSlice &) override; + void visit(const ir::operation::TransposeConv &) override; + void visit(const ir::operation::Transpose &) override; + void visit(const ir::operation::Unpack &) override; + void visit(const ir::operation::Add &) override; + void visit(const ir::operation::Div &) override; + void visit(const ir::operation::Exp &) override; + void visit(const ir::operation::Comparison &) override; + void visit(const ir::operation::Min &) override; + void visit(const ir::operation::Max &) override; + void visit(const ir::operation::OneHot &) override; + +private: + const ir::Operands &_ctx; + std::shared_ptr _tensor_builder; + ir::Layout _current_op_seq_layout; +}; + +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_KERNEL_GENERATOR_H__ diff --git a/runtime/onert/backend/acl_neon/Optimizer.cc b/runtime/onert/backend/acl_neon/Optimizer.cc new file mode 100644 index 000000000..2948cab09 --- /dev/null +++ b/runtime/onert/backend/acl_neon/Optimizer.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Optimizer.h" + +#include "ParentInfo.h" + +#include +#include +#include +#include "AclSubTensorAnalyzer.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +Optimizer::Optimizer(BackendContext *context) + : _context{context}, + _tensor_builder{std::dynamic_pointer_cast(context->tensor_builder)} +{ + assert(context); +} + +void Optimizer::optimize() +{ + // Concat elimination (build subtensor info) + { + acl_common::AclSubTensorAnalyzer sa{*_context->graph()}; + for (auto op_info : _context->operation_list()) + { + auto &op = _context->graph()->operations().at(op_info.index); + sa.setLayout(op_info.layout); + op.accept(sa); + } + + _tensor_builder->parent_map(sa.releaseParentMap()); + } +} + +} // namespace acl_neon +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_neon/Optimizer.h b/runtime/onert/backend/acl_neon/Optimizer.h new file mode 100644 index 000000000..5fe0d519c --- /dev/null +++ b/runtime/onert/backend/acl_neon/Optimizer.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_OPTIMIZER_H__ +#define __ONERT_BACKEND_ACL_NEON_OPTIMIZER_H__ + +#include +#include +#include "TensorBuilder.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +class Optimizer : public IOptimizer +{ +public: + Optimizer(BackendContext *context); + + void optimize() override; + +private: + BackendContext *_context; + std::shared_ptr _tensor_builder; +}; + +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_OPTIMIZER_H__ diff --git a/runtime/onert/backend/acl_neon/ShapeFixer.cc b/runtime/onert/backend/acl_neon/ShapeFixer.cc new file mode 100644 index 000000000..756222f4b --- /dev/null +++ b/runtime/onert/backend/acl_neon/ShapeFixer.cc @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ShapeFixer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ir/Index.h" +#include "exec/NopFunction.h" +#include "util/logging.h" +#include "util/Utils.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +using ::onert::backend::acl_common::asAclFunction; + +ShapeFixer::ShapeFixer(const ir::Operands &ctx, + const std::shared_ptr &tensor_builder) + : _ctx(ctx), _tensor_builder(tensor_builder) +{ + assert(tensor_builder); +} + +void ShapeFixer::visit(const ir::operation::Abs &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ArgMax &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::BatchToSpaceND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::BatchToSpaceND::Input::INPUT)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); +} + +void ShapeFixer::visit(const ir::operation::Cast &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Conv2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::DepthToSpace &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::DepthwiseConv2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Dequantize &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::MaxPool2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Mean &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::AvgPool2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Concat &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + _tensor_builder->dimCorrection(ofm_index, false); + for (const auto &inputs : node.getInputs()) + _tensor_builder->dimCorrection(inputs, false); +} + +void ShapeFixer::visit(const ir::operation::EmbeddingLookup &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto values_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::VALUES)}; + _tensor_builder->dimCorrection(values_index, false); + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::Exp &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Floor &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::FullyConnected &node) +{ + using ir::operation::FullyConnected; + const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)}; + const auto input_rank = _ctx.at(input_index).shape().rank(); + // Check for reshaping input's shape into rank-2 + if (input_rank == 3 || input_rank == 4) + _tensor_builder->dimCorrection(input_index, false); +} + +void ShapeFixer::visit(const ir::operation::HashtableLookup &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto values_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::VALUES)}; + _tensor_builder->dimCorrection(values_index, false); + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::Gather &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)}; + const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); + _tensor_builder->dimCorrection(indices_index, false); +} + +void ShapeFixer::visit(const ir::operation::InstanceNorm &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::L2Normalization &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::L2Pool2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::LocalResponseNormalization &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::LogicalAnd &node) +{ + const auto input0_index{node.getInputs().at(ir::operation::LogicalAnd::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::LogicalAnd::Input::INPUT1)}; + + if (!(_ctx.at(input0_index).shape() == _ctx.at(input1_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input0_index).shape().rank(), _ctx.at(input1_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(input0_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(input1_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::LogicalNot &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::LogicalOr &node) +{ + const auto input0_index{node.getInputs().at(ir::operation::LogicalOr::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::LogicalOr::Input::INPUT1)}; + + if (!(_ctx.at(input0_index).shape() == _ctx.at(input1_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input0_index).shape().rank(), _ctx.at(input1_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(input0_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(input1_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Logistic &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::LSTM &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Pack &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + _tensor_builder->dimCorrection(ofm_index, false); + for (const auto &inputs : node.getInputs()) + { + _tensor_builder->dimCorrection(inputs, false); + const auto ofm_rank = _ctx.at(ofm_index).shape().rank(); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(inputs).shape()).extendRank(ofm_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Pad &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)}; + const auto output_index{node.getOutputs().at(0)}; + _tensor_builder->dimCorrection(input_index, false); + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::Mul &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Mul::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Mul::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Neg &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Permute &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::PReLU &node) +{ + const auto ifm_index{node.getInputs().at(ir::operation::PReLU::Input::INPUT)}; + const auto alpha_index{node.getInputs().at(ir::operation::PReLU::Input::ALPHA)}; + + if (!(_ctx.at(ifm_index).shape() == _ctx.at(alpha_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(ifm_index).shape().rank(), _ctx.at(alpha_index).shape().rank()); + const_cast(_ctx.at(ifm_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(alpha_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::ReduceMax &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReduceMin &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReduceSum &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReLU &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReLU1 &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReLU6 &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Reshape &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Reshape::Input::INPUT)}; + + _tensor_builder->dimCorrection(input_index, false); + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::ResizeBilinear &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::RNN &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Comparison &node) +{ + const auto input0_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)}; + const auto input1_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)}; + + if (!(_ctx.at(input0_index).shape() == _ctx.at(input1_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input0_index).shape().rank(), _ctx.at(input1_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(input0_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(input1_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::RSQRT &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Squeeze &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Squeeze::Input::INPUT)}; + _tensor_builder->dimCorrection(input_index, false); + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::Tanh &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Slice &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::StridedSlice &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); +} + +void ShapeFixer::visit(const ir::operation::Softmax &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::SpaceToBatchND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)}; + _tensor_builder->dimCorrection(ofm_index, false); + _tensor_builder->dimCorrection(ifm_index, false); +} + +void ShapeFixer::visit(const ir::operation::SpaceToDepth &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Split &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Split::Input::INPUT)}; + _tensor_builder->dimCorrection(input_index, false); + for (const auto &output : node.getOutputs()) + _tensor_builder->dimCorrection(output, false); +} + +void ShapeFixer::visit(const ir::operation::SQRT &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::SquaredDifference &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::SquaredDifference::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Sub &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Sub::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Sub::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::TransposeConv &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Transpose &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Unpack &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Unpack::Input::INPUT)}; + _tensor_builder->dimCorrection(input_index, false); + for (const auto &output_index : node.getOutputs()) + _tensor_builder->dimCorrection(output_index, false); +} + +void ShapeFixer::visit(const ir::operation::Add &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Add::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Add::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Div &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Div::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Div::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Min &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Min::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Min::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::Max &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Max::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Max::Input::RHS)}; + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + + // TODO remove const_cast later. For example, _ctx may need to be a non const variable or + // a node to extend shape may be inserted in front of this operation + const_cast(_ctx.at(lhs_index).shape()).extendRank(broadcast_rank); + const_cast(_ctx.at(rhs_index).shape()).extendRank(broadcast_rank); + } +} + +void ShapeFixer::visit(const ir::operation::OneHot &) { /* Do NOTHING */} + +} // namespace acl_neon +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_neon/ShapeFixer.h b/runtime/onert/backend/acl_neon/ShapeFixer.h new file mode 100644 index 000000000..434cfd240 --- /dev/null +++ b/runtime/onert/backend/acl_neon/ShapeFixer.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_SHAPE_FIXER_H__ +#define __ONERT_BACKEND_ACL_NEON_SHAPE_FIXER_H__ + +#include + +#include "ir/Operands.h" +#include "TensorBuilder.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +class ShapeFixer : public IShapeFixer +{ +public: + ShapeFixer(const ir::Operands &ctx, const std::shared_ptr &tensor_builder); + + void visit(const ir::operation::Abs &) override; + void visit(const ir::operation::ArgMax &) override; + void visit(const ir::operation::BatchToSpaceND &) override; + void visit(const ir::operation::Cast &) override; + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthToSpace &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::Dequantize &) override; + void visit(const ir::operation::MaxPool2D &) override; + void visit(const ir::operation::Mean &) override; + void visit(const ir::operation::AvgPool2D &) override; + void visit(const ir::operation::Concat &) override; + void visit(const ir::operation::EmbeddingLookup &) override; + void visit(const ir::operation::Exp &) override; + void visit(const ir::operation::Floor &) override; + void visit(const ir::operation::FullyConnected &) override; + void visit(const ir::operation::Gather &) override; + void visit(const ir::operation::HashtableLookup &) override; + void visit(const ir::operation::InstanceNorm &) override; + void visit(const ir::operation::L2Normalization &) override; + void visit(const ir::operation::L2Pool2D &) override; + void visit(const ir::operation::LocalResponseNormalization &) override; + void visit(const ir::operation::LogicalAnd &) override; + void visit(const ir::operation::LogicalNot &) override; + void visit(const ir::operation::LogicalOr &) override; + void visit(const ir::operation::Logistic &) override; + void visit(const ir::operation::LSTM &) override; + void visit(const ir::operation::Mul &) override; + void visit(const ir::operation::Neg &) override; + void visit(const ir::operation::Pack &) override; + void visit(const ir::operation::Pad &) override; + void visit(const ir::operation::Permute &) override; + void visit(const ir::operation::PReLU &) override; + void visit(const ir::operation::ReduceMax &) override; + void visit(const ir::operation::ReduceMin &) override; + void visit(const ir::operation::ReduceSum &) override; + void visit(const ir::operation::ReLU &) override; + void visit(const ir::operation::ReLU1 &) override; + void visit(const ir::operation::ReLU6 &) override; + void visit(const ir::operation::Reshape &) override; + void visit(const ir::operation::ResizeBilinear &) override; + void visit(const ir::operation::RNN &) override; + void visit(const ir::operation::RSQRT &) override; + void visit(const ir::operation::Squeeze &) override; + void visit(const ir::operation::Tanh &) override; + void visit(const ir::operation::Softmax &) override; + void visit(const ir::operation::SpaceToBatchND &) override; + void visit(const ir::operation::SpaceToDepth &) override; + void visit(const ir::operation::Split &) override; + void visit(const ir::operation::SQRT &) override; + void visit(const ir::operation::SquaredDifference &) override; + void visit(const ir::operation::Sub &) override; + void visit(const ir::operation::Slice &) override; + void visit(const ir::operation::StridedSlice &) override; + void visit(const ir::operation::TransposeConv &) override; + void visit(const ir::operation::Transpose &) override; + void visit(const ir::operation::Unpack &) override; + void visit(const ir::operation::Add &) override; + void visit(const ir::operation::Div &) override; + void visit(const ir::operation::Comparison &) override; + void visit(const ir::operation::Min &) override; + void visit(const ir::operation::Max &) override; + void visit(const ir::operation::OneHot &) override; + +private: + const ir::Operands &_ctx; + std::shared_ptr _tensor_builder; +}; + +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_SHAPE_FIXER_H__ diff --git a/runtime/onert/backend/acl_neon/TensorBuilder.h b/runtime/onert/backend/acl_neon/TensorBuilder.h new file mode 100644 index 000000000..070dc20ac --- /dev/null +++ b/runtime/onert/backend/acl_neon/TensorBuilder.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_TENSOR_BUILDER_H__ +#define __ONERT_BACKEND_ACL_NEON_TENSOR_BUILDER_H__ + +#include + +#include "operand/NETensor.h" +#include "operand/NESubTensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +using TensorBuilder = + acl_common::AclTensorBuilder; + +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_TENSOR_BUILDER_H__ diff --git a/runtime/onert/backend/acl_neon/TensorManager.h b/runtime/onert/backend/acl_neon/TensorManager.h new file mode 100644 index 000000000..3ec9efa8f --- /dev/null +++ b/runtime/onert/backend/acl_neon/TensorManager.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_TENSOR_MANAGER_H__ +#define __ONERT_BACKEND_ACL_NEON_TENSOR_MANAGER_H__ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "operand/NETensor.h" +#include "operand/NESubTensor.h" + +#include "util/logging.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ + +using MemoryManager = + acl_common::AclMemoryManager; + +using LinearMemoryManager = acl_common::AclLinearMemoryManager< + operand::INETensor, operand::NETensor, operand::NESubTensor, + ::arm_compute::MemoryManagerOnDemand, ::arm_compute::PoolManager, + ::arm_compute::OffsetLifetimeManager, ::arm_compute::Allocator, ::arm_compute::MemoryGroup>; + +using InternalBufferManager = acl_common::AclInternalBufferManager< + ::arm_compute::MemoryManagerOnDemand, ::arm_compute::PoolManager, + ::arm_compute::OffsetLifetimeManager, ::arm_compute::Allocator>; + +using TensorManager = acl_common::AclTensorManager; + +TensorManager *createTensorManager(bool is_linear_executor) +{ + if (is_linear_executor) + { + VERBOSE(acl_neon_createTensorManager) << "AclTensorManager as Linear" << std::endl; + return new TensorManager(new MemoryManager(), new LinearMemoryManager(), + new InternalBufferManager()); + } + else + { + VERBOSE(acl_neon_createTensorManager) << "AclTensorManager" << std::endl; + return new TensorManager(new MemoryManager(), new MemoryManager(), new InternalBufferManager()); + } +} + +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_TENSOR_MANAGER_H__ diff --git a/runtime/onert/backend/acl_neon/acl_neon.cc b/runtime/onert/backend/acl_neon/acl_neon.cc new file mode 100644 index 000000000..f490d132d --- /dev/null +++ b/runtime/onert/backend/acl_neon/acl_neon.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Backend.h" + +extern "C" { +onert::backend::Backend *onert_backend_create() +{ + VERBOSE(onert_backend_create) << "'acl_neon' loaded\n"; + return new onert::backend::acl_neon::Backend; +} + +void onert_backend_destroy(onert::backend::Backend *backend) +{ + VERBOSE(onert_backend_create) << "'acl_neon' unloaded\n"; + delete backend; +} +} diff --git a/runtime/onert/backend/acl_neon/operand/INETensor.cc b/runtime/onert/backend/acl_neon/operand/INETensor.cc new file mode 100644 index 000000000..179ed691a --- /dev/null +++ b/runtime/onert/backend/acl_neon/operand/INETensor.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "INETensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ +namespace operand +{ + +void INETensor::access(const std::function &fn) { fn(*this); } + +} // namespace operand +} // namespace acl_neon +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_neon/operand/INETensor.h b/runtime/onert/backend/acl_neon/operand/INETensor.h new file mode 100644 index 000000000..db0ce6fdc --- /dev/null +++ b/runtime/onert/backend/acl_neon/operand/INETensor.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_OPERAND_I_NE_TENSOR_H__ +#define __ONERT_BACKEND_ACL_NEON_OPERAND_I_NE_TENSOR_H__ + +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ +namespace operand +{ + +class INETensor : public acl_common::IACLTensor +{ +public: + const arm_compute::ITensor *handle() const override = 0; + arm_compute::ITensor *handle() override = 0; + void access(const std::function &fn) final; +}; + +} // namespace operand +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_OPERAND_I_NE_TENSOR_H__ diff --git a/runtime/onert/backend/acl_neon/operand/NESubTensor.cc b/runtime/onert/backend/acl_neon/operand/NESubTensor.cc new file mode 100644 index 000000000..457addd55 --- /dev/null +++ b/runtime/onert/backend/acl_neon/operand/NESubTensor.cc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NESubTensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ +namespace operand +{ + +NESubTensor::NESubTensor(INETensor *parent, const arm_compute::TensorShape &tensor_shape, + const arm_compute::Coordinates &coords, size_t rank, bool extend_parent) + : _ne_sub_tensor(std::make_shared(parent->handle(), tensor_shape, + coords, extend_parent)), + _rank{rank} +{ + // DO NOTHING +} + +const arm_compute::SubTensor *NESubTensor::handle() const { return _ne_sub_tensor.get(); } + +arm_compute::SubTensor *NESubTensor::handle() { return _ne_sub_tensor.get(); } + +} // namespace operand +} // namespace acl_neon +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_neon/operand/NESubTensor.h b/runtime/onert/backend/acl_neon/operand/NESubTensor.h new file mode 100644 index 000000000..e7f77d7fc --- /dev/null +++ b/runtime/onert/backend/acl_neon/operand/NESubTensor.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_OPERAND_NE_SUB_TENSOR_H__ +#define __ONERT_BACKEND_ACL_NEON_OPERAND_NE_SUB_TENSOR_H__ + +#include +#include "INETensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ +namespace operand +{ + +class NESubTensor : public INETensor +{ +public: + NESubTensor() = delete; + +public: + NESubTensor(INETensor *parent, const arm_compute::TensorShape &tensor_shape, + const arm_compute::Coordinates &coords, size_t rank, bool extend_parent = false); + +public: + size_t num_dimensions() const final { return _rank; } + +public: + const arm_compute::SubTensor *handle() const override; + arm_compute::SubTensor *handle() override; + +public: + // This method is used to prevent the use of memcpy for SubTensor + bool has_padding() const override { return true; } + +private: + std::shared_ptr _ne_sub_tensor; + size_t _rank; +}; + +} // namespace operand +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_OPERAND_NE_SUB_TENSOR_H__ diff --git a/runtime/onert/backend/acl_neon/operand/NETensor.cc b/runtime/onert/backend/acl_neon/operand/NETensor.cc new file mode 100644 index 000000000..53dbb3021 --- /dev/null +++ b/runtime/onert/backend/acl_neon/operand/NETensor.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "NETensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ +namespace operand +{ + +NETensor::NETensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses) + : _ne_tensor(std::make_shared()), _rank{rank}, _num_uses{num_uses} +{ + allocator()->init(info); +} + +const arm_compute::Tensor *NETensor::handle() const { return _ne_tensor.get(); } + +arm_compute::Tensor *NETensor::handle() { return _ne_tensor.get(); } + +arm_compute::TensorAllocator *NETensor::allocator() { return _ne_tensor->allocator(); } + +} // namespace operand +} // namespace acl_neon +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/acl_neon/operand/NETensor.h b/runtime/onert/backend/acl_neon/operand/NETensor.h new file mode 100644 index 000000000..0dd81afec --- /dev/null +++ b/runtime/onert/backend/acl_neon/operand/NETensor.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ACL_NEON_OPERAND_NE_TENSOR_H__ +#define __ONERT_BACKEND_ACL_NEON_OPERAND_NE_TENSOR_H__ + +#include +#include +#include "arm_compute/runtime/TensorAllocator.h" +#include "INETensor.h" + +namespace onert +{ +namespace backend +{ +namespace acl_neon +{ +namespace operand +{ + +class NETensor : public INETensor +{ +public: + NETensor() = delete; + +public: + NETensor(const arm_compute::TensorInfo &info, size_t rank, size_t num_uses); + +public: + size_t num_dimensions() const final { return _rank; } + +public: + const arm_compute::Tensor *handle() const override; + arm_compute::Tensor *handle() override; + size_t num_uses() const { return _num_uses; } + +public: + arm_compute::TensorAllocator *allocator(); + +private: + std::shared_ptr _ne_tensor; + size_t _rank; + size_t _num_uses; +}; + +} // namespace operand +} // namespace acl_neon +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ACL_NEON_OPERAND_NE_TENSOR_H__ diff --git a/runtime/onert/backend/cpu/Backend.h b/runtime/onert/backend/cpu/Backend.h new file mode 100644 index 000000000..d12c809cd --- /dev/null +++ b/runtime/onert/backend/cpu/Backend.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_BACKEND_H__ +#define __ONERT_BACKEND_CPU_BACKEND_H__ + +#include "Config.h" +#include "ConstantInitializer.h" +#include "KernelGenerator.h" +#include "ShapeFixer.h" + +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +class Backend : public ::onert::backend::Backend +{ +public: + Backend() : _config{std::make_shared()} {} + + std::shared_ptr config() const override { return _config; } + + std::unique_ptr newContext(const ir::Graph &graph, + const std::shared_ptr &kb, + bool) const override + { + const auto &operands = graph.operands(); + auto context = std::make_unique(this, &graph); + auto tb = std::make_shared(); + context->tensor_builder = tb; + context->constant_initializer = std::make_shared(operands, tb); + context->kernel_gen = std::make_shared(operands, tb, kb); + context->shape_fixer = std::make_shared(operands); + context->tensor_register = nullptr; + context->optimizer = nullptr; + return context; + } + +private: + std::shared_ptr _config; +}; + +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_BACKEND_H__ diff --git a/runtime/onert/backend/cpu/CMakeLists.txt b/runtime/onert/backend/cpu/CMakeLists.txt new file mode 100644 index 000000000..ed2dcd110 --- /dev/null +++ b/runtime/onert/backend/cpu/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LIB_ONERT_BACKEND_CPU onert_backend_cpu) + +file(GLOB_RECURSE SOURCES "*.cc") + +add_library(${LIB_ONERT_BACKEND_CPU} SHARED ${SOURCES}) + +target_link_libraries(${LIB_ONERT_BACKEND_CPU} PRIVATE nnfw_lib_misc nnfw_lib_cker) +target_link_libraries(${LIB_ONERT_BACKEND_CPU} PRIVATE ${LIB_ONERT_BACKEND_CPU_COMMON}) +target_link_libraries(${LIB_ONERT_BACKEND_CPU} PRIVATE nnfw_common) +target_link_libraries(${LIB_ONERT_BACKEND_CPU} PRIVATE nnfw_coverage) + +set_target_properties(${LIB_ONERT_BACKEND_CPU} PROPERTIES OUTPUT_NAME backend_cpu) + +install(TARGETS ${LIB_ONERT_BACKEND_CPU} DESTINATION lib) diff --git a/runtime/onert/backend/cpu/Config.cc b/runtime/onert/backend/cpu/Config.cc new file mode 100644 index 000000000..cea8095b1 --- /dev/null +++ b/runtime/onert/backend/cpu/Config.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Config.h" + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +bool Config::initialize() { return true; } + +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/Config.h b/runtime/onert/backend/cpu/Config.h new file mode 100644 index 000000000..e7818fa04 --- /dev/null +++ b/runtime/onert/backend/cpu/Config.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_CONFIG_H__ +#define __ONERT_BACKEND_CPU_CONFIG_H__ + +#include +#include +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +class Config : public IConfig +{ +public: + std::string id() override { return "cpu"; } + bool initialize() override; + bool SupportPermutation() override { return true; } + + std::unique_ptr timer() override { return std::make_unique(); } +}; + +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_CONFIG_H__ diff --git a/runtime/onert/backend/cpu/ConstantInitializer.cc b/runtime/onert/backend/cpu/ConstantInitializer.cc new file mode 100644 index 000000000..a77a48b30 --- /dev/null +++ b/runtime/onert/backend/cpu/ConstantInitializer.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConstantInitializer.h" + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +ConstantInitializer::ConstantInitializer(const ir::Operands &operands, + const std::shared_ptr &tensor_builder) + : IConstantInitializer{operands}, _tensor_builder{tensor_builder} +{ + // DO NOTHING +} + +void ConstantInitializer::visit(const ir::operation::Conv2D &node) +{ + const auto &kernel_index = node.getInputs().at(ir::operation::Conv2D::KERNEL); + const auto &kernel_obj = _operands.at(kernel_index); + registerCopyInitializer(kernel_index, kernel_obj); + + const auto &bias_index = node.getInputs().at(ir::operation::Conv2D::BIAS); + const auto &bias_obj = _operands.at(bias_index); + registerCopyInitializer(bias_index, bias_obj); +} + +void ConstantInitializer::visit(const ir::operation::DepthwiseConv2D &node) +{ + const auto &kernel_index = node.getInputs().at(ir::operation::DepthwiseConv2D::KERNEL); + const auto &kernel_obj = _operands.at(kernel_index); + registerCopyInitializer(kernel_index, kernel_obj); + + const auto &bias_index = node.getInputs().at(ir::operation::DepthwiseConv2D::BIAS); + const auto &bias_obj = _operands.at(bias_index); + registerCopyInitializer(bias_index, bias_obj); +} + +void ConstantInitializer::visit(const ir::operation::FullyConnected &node) +{ + const auto &weight_index = node.getInputs().at(ir::operation::FullyConnected::WEIGHT); + const auto &weight_obj = _operands.at(weight_index); + registerCopyInitializer(weight_index, weight_obj); + + const auto &bias_index = node.getInputs().at(ir::operation::FullyConnected::BIAS); + const auto &bias_obj = _operands.at(bias_index); + registerCopyInitializer(bias_index, bias_obj); +} + +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/ConstantInitializer.h b/runtime/onert/backend/cpu/ConstantInitializer.h new file mode 100644 index 000000000..bd06c64d1 --- /dev/null +++ b/runtime/onert/backend/cpu/ConstantInitializer.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_CPU_CONSTANT_INITIALIZER_H__ +#define __ONERT_COMPILER_CPU_CONSTANT_INITIALIZER_H__ + +#include "TensorBuilder.h" + +#include +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +class ConstantInitializer : public IConstantInitializer +{ +public: + ConstantInitializer(const ir::Operands &operands, + const std::shared_ptr &tensor_builder); + +public: + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::FullyConnected &) override; + +private: + std::shared_ptr tensor_builder() const override { return _tensor_builder; } + +private: + std::shared_ptr _tensor_builder; +}; + +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_COMPILER_CPU_CONSTANT_INITIALIZER_H__ diff --git a/runtime/onert/backend/cpu/KernelGenerator.cc b/runtime/onert/backend/cpu/KernelGenerator.cc new file mode 100644 index 000000000..86764dd06 --- /dev/null +++ b/runtime/onert/backend/cpu/KernelGenerator.cc @@ -0,0 +1,932 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "KernelGenerator.h" + +#include "kernel/AbsLayer.h" +#include "kernel/AddLayer.h" +#include "kernel/AvgPoolLayer.h" +#include "kernel/CastLayer.h" +#include "kernel/CompareLayer.h" +#include "kernel/ConcatLayer.h" +#include "kernel/ConvolutionLayer.h" +#include "kernel/DepthwiseConvolutionLayer.h" +#include "kernel/DivLayer.h" +#include "kernel/ExpLayer.h" +#include "kernel/FullyConnectedLayer.h" +#include "kernel/GatherLayer.h" +#include "kernel/LogisticLayer.h" +#include "kernel/MaxLayer.h" +#include "kernel/MaxPoolLayer.h" +#include "kernel/MinLayer.h" +#include "kernel/MulLayer.h" +#include "kernel/OneHotLayer.h" +#include "kernel/OperationUtils.h" +#include "kernel/PackLayer.h" +#include "kernel/PadLayer.h" +#include "kernel/PermuteLayer.h" +#include "kernel/ReduceLayer.h" +#include "kernel/ReshapeLayer.h" +#include "kernel/RsqrtLayer.h" +#include "kernel/ShapeLayer.h" +#include "kernel/SinLayer.h" +#include "kernel/SliceLayer.h" +#include "kernel/SoftMaxLayer.h" +#include "kernel/StridedSliceLayer.h" +#include "kernel/SplitLayer.h" +#include "kernel/SubLayer.h" +#include "kernel/TanhLayer.h" +#include "kernel/TransposeLayer.h" +#include "kernel/UnpackLayer.h" + +#include +#include +#include +#include +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +KernelGenerator::KernelGenerator( + const ir::Operands &operand_ctx, const std::shared_ptr &tensor_builder, + const std::shared_ptr &kernel_builer) + : _ctx(operand_ctx), _tensor_builder(tensor_builder), _kernel_builder(kernel_builer), + _current_op_seq_layout(ir::Layout::UNKNOWN) +{ + // DO NOTHING +} + +void KernelGenerator::visit(const ir::OpSequence &op_seq) +{ + // TODO Move this to IKernelGenerator + // (all derivatives have the same implementation for this) + assert(!_return_fn_seq); + _return_fn_seq = std::make_unique(); + _current_op_seq_layout = op_seq.getLayout(); + for (const auto &e : op_seq.operations()) + { + const auto &node = *(e.node); + node.accept(*this); + _return_fn_seq->append(releaseFunction()); + + // NOTE Permute node has tensors of the other backends + if (node.opcode() != ir::OpCode::Permute) + { + for (const auto &ind : node.getInputs() + node.getOutputs()) + { + auto tensor = _tensor_builder->at(ind); + if (tensor) + { + tensor->increase_ref(); + } + } + } + } +} + +void KernelGenerator::visit(const ir::operation::Conv2D &node) +{ + using ir::operation::Conv2D; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(Conv2D::Input::INPUT)}; + const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)}; + + const auto stride = node.param().stride; + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in]. + const auto &ker_shape = _ctx.at(ker_index).shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + const auto padding_type = node.param().padding.type; + const auto padding = ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, + ker_width, ker_height); + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto ker_alloc = _tensor_builder->at(ker_index).get(); + auto bias_alloc = _tensor_builder->at(bias_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::ConvolutionLayer>(); + + fn->configure(ifm_alloc, ker_alloc, bias_alloc, padding_type, padding.left, padding.right, + padding.top, padding.bottom, stride.horizontal, stride.vertical, activation, + ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::DepthwiseConv2D &node) +{ + using ir::operation::DepthwiseConv2D; + + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(DepthwiseConv2D::Input::INPUT)}; + const auto ker_index{node.getInputs().at(DepthwiseConv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(DepthwiseConv2D::Input::BIAS)}; + + const auto stride = node.param().stride; + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + // Kernel format is [1, kernel_height, kernel_width, depth_out]. + const auto &ker_shape = _ctx.at(ker_index).shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + const auto padding = ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, + ker_width, ker_height); + const auto multiplier = node.param().multiplier; + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + auto ker_alloc = _tensor_builder->at(ker_index).get(); + auto bias_alloc = _tensor_builder->at(bias_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::DepthwiseConvolutionLayer>(); + + fn->configure(ifm_alloc, ker_alloc, bias_alloc, padding.left, padding.right, padding.top, + padding.bottom, stride.horizontal, stride.vertical, multiplier, activation, + ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::MaxPool2D &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::MaxPool2D::Input::INPUT)}; + + const auto kh = node.param().kh; + const auto kw = node.param().kw; + + const auto stride = node.param().stride; + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + const auto padding = + ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh); + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::MaxPoolLayer>(); + + fn->configure(ifm_alloc, padding.left, padding.right, padding.top, padding.bottom, + stride.horizontal, stride.vertical, kw, kh, activation, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::AvgPool2D &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::AvgPool2D::Input::INPUT)}; + + const auto kh = node.param().kh; + const auto kw = node.param().kw; + const auto stride = node.param().stride; + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_op_seq_layout); + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_op_seq_layout); + const auto padding = + ir::calculatePadding(node.param().padding, ifm_shape, ofm_shape, stride, kw, kh); + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::AvgPoolLayer>(); + + fn->configure(ifm_alloc, padding.left, padding.right, padding.top, padding.bottom, + stride.horizontal, stride.vertical, kw, kh, activation, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Concat &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + + const auto rank = _ctx.at(ofm_index).shape().rank(); + const auto axis = + ::onert::backend::cpu::kernel::getAxis(rank, node.param().axis, _current_op_seq_layout); + + auto output_alloc = _tensor_builder->at(ofm_index).get(); + + std::vector input_tensors; + for (auto &ifm_idx : node.getInputs()) + input_tensors.emplace_back(_tensor_builder->at(ifm_idx).get()); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::ConcatLayer>(); + + fn->configure(input_tensors, axis, output_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::FullyConnected &node) +{ + using ir::operation::FullyConnected; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)}; + const auto weight_index{node.getInputs().at(FullyConnected::Input::WEIGHT)}; + const auto bias_index{node.getInputs().at(FullyConnected::Input::BIAS)}; + const auto activation = node.param().activation; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + auto weight_alloc = _tensor_builder->at(weight_index).get(); + auto bias_alloc = _tensor_builder->at(bias_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::FullyConnectedLayer>(); + + fn->configure(input_alloc, weight_alloc, bias_alloc, activation, output_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Reshape &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Reshape::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + // optional 2nd input + operand::Tensor *shape_alloc = nullptr; + + if (node.getInputs().size() == 2) + { + const auto shape_index{node.getInputs().at(ir::operation::Reshape::Input::SHAPE)}; + shape_alloc = _tensor_builder->at(shape_index).get(); + } + + auto fn = std::make_unique<::onert::backend::cpu::kernel::ReshapeLayer>(); + + fn->configure(input_alloc, shape_alloc, output_alloc); + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Squeeze &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Squeeze::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + // Squeeze can share same kernel with reshape + auto fn = std::make_unique<::onert::backend::cpu::kernel::ReshapeLayer>(); + + fn->configure(input_alloc, nullptr, output_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Softmax &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Softmax::Input::INPUT)}; + + const auto beta = node.param().beta; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::SoftMaxLayer>(); + + fn->configure(input_alloc, beta, output_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Add &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Add::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Add::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::AddLayer>(); + + fn->configure(lhs_alloc, rhs_alloc, activation, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Comparison &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)}; + const auto rhs_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto comparison_type = node.param().comparison_type; + + auto fn = std::make_unique<::onert::backend::cpu::kernel::CompareLayer>(); + + fn->configure(lhs_alloc, rhs_alloc, comparison_type, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Gather &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)}; + const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + auto indices_alloc = _tensor_builder->at(indices_index).get(); + + const auto backend_layout = output_alloc->layout(); + UNUSED_RELEASE(backend_layout); + + // NOTE The frontend layout and backend layout must be the same for this operation. + // If not the same, we have to add a stage(?) to perform permutation of output tensor. It + // is not not efficient even if it works well. If so, it would be better to set the + // layout of these backend tensors to the same layout. + // There is also one thing we have to think about. This operation depends on the layout of + // a model. For example, if a model in NHWC has this operation as output rank == 4, indices + // rank == 2 and axis == 2, this operation should work as the axis W and C, but the axis W + // and C are not sequential in NCHW. So the backend in NCHW cannot handle this case. + assert(backend_layout == input_alloc->layout()); + assert(backend_layout == indices_alloc->layout()); + const auto &input_shape = _ctx.at(input_index).shape(); + UNUSED_RELEASE(input_shape); + assert(input_shape.rank() < 4 || _current_op_seq_layout == backend_layout); + + const auto axis_raw = node.param().axis; + const auto axis_value = (axis_raw < 0 ? (input_shape.rank() + axis_raw) : axis_raw); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::GatherLayer>(); + + fn->configure(input_alloc, indices_alloc, output_alloc, axis_value); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Sub &node) +{ + // The same as Add + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Sub::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Sub::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::SubLayer>(); + + fn->configure(lhs_alloc, rhs_alloc, activation, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Mul &node) +{ + // The same as Add + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Mul::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Mul::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::MulLayer>(); + + fn->configure(lhs_alloc, rhs_alloc, activation, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::OneHot &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto indices_index{node.getInputs().at(ir::operation::OneHot::INDICES)}; + + const auto depth = node.param().depth; + const auto on_value = node.param().on_value; + const auto off_value = node.param().off_value; + const auto axis = node.param().axis; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto indices_alloc = _tensor_builder->at(indices_index).get(); + + assert(indices_alloc->data_type() == OperandType::INT32); + assert(axis <= static_cast(indices_alloc->num_dimensions())); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::OneHotLayer>(); + + fn->configure(indices_alloc, output_alloc, depth, on_value, off_value, axis); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Div &node) +{ + // The same as Add + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Div::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Div::Input::RHS)}; + + const auto activation = node.param().activation; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::DivLayer>(); + + fn->configure(lhs_alloc, rhs_alloc, activation, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Permute &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + const auto &shape = _ctx.at(output_index).shape(); + const auto input_backend_ctx = node.param().input_backend_ctx; + const auto output_backend_ctx = node.param().output_backend_ctx; + const auto data_type = node.getDataType(); + + auto output_tensor = output_backend_ctx->tensor_builder->tensorAt(output_index); + auto input_tensor = input_backend_ctx->tensor_builder->tensorAt(input_index); + assert(output_tensor != nullptr); + assert(input_tensor != nullptr); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::PermuteLayer>(); + + // TODO Support NCHW frontend + auto out_shape = shape; + if (shape.rank() == 4 && output_tensor->layout() == ir::Layout::NCHW) + { + out_shape.dim(1) = shape.dim(3); + out_shape.dim(2) = shape.dim(1); + out_shape.dim(3) = shape.dim(2); + } + + const auto permute_type = node.getPermuteType(); + // Check Permutation Type + const auto inferPermuteType = [&]() { + if (input_tensor->layout() == ir::Layout::NHWC && output_tensor->layout() == ir::Layout::NCHW) + { + return ir::operation::Permute::Type::NHWC_TO_NCHW; + } + else if (input_tensor->layout() == ir::Layout::NCHW && + output_tensor->layout() == ir::Layout::NHWC) + { + return ir::operation::Permute::Type::NCHW_TO_NHWC; + } + else + { + return ir::operation::Permute::Type::COPY; + } + }(); + UNUSED_RELEASE(inferPermuteType); + assert(permute_type == inferPermuteType); + + fn->configure(input_tensor, output_tensor, out_shape, permute_type, data_type); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Custom &node) +{ + auto get_type_info = [](const ir::Operand &operand) -> custom::TypeInfo { + const auto &frontend_shape = operand.shape(); + custom::Shape shape(frontend_shape.rank()); + for (auto d = 0; d < frontend_shape.rank(); ++d) + { + shape.dim(d) = frontend_shape.dim(d); + } + + return {shape, operand.typeInfo().type()}; + }; + + auto fill_op_info = [&](const ir::OperandIndexSequence &opSeq, + std::vector &types, std::vector &allocs) { + for (auto &idx : opSeq) + { + const auto &operand = _ctx.at(idx); + // TODO make sure using `_current_op_seq_layout` is correct for custom operations + types.emplace_back(get_type_info(operand)); + auto in_alloc = _tensor_builder->at(idx)->buffer(); + allocs.emplace_back(in_alloc); + } + }; + + backend::custom::CustomKernelConfigParams params{}; + + fill_op_info(node.getInputs(), params.input_types, params.input_allocations); + fill_op_info(node.getOutputs(), params.output_types, params.output_allocations); + + params.userdata = node.userdata().data; + params.userdata_size = node.userdata().size; + + auto fn = _kernel_builder->buildKernel(node.id(), std::move(params)); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Exp &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Exp::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::ExpLayer>(); + + fn->configure(input_alloc, output_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Logistic &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Logistic::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::LogisticLayer>(); + + fn->configure(input_alloc, output_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Tanh &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Tanh::Input::INPUT)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::TanhLayer>(); + + fn->configure(input_alloc, output_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Pack &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + + const auto rank = node.param().rank; + const auto axis = + ::onert::backend::cpu::kernel::getAxis(rank, node.param().axis, _current_op_seq_layout); + + assert(-rank <= axis && axis < rank); + + auto output_alloc = _tensor_builder->at(ofm_index).get(); + + std::vector input_tensors; + for (auto &ifm_idx : node.getInputs()) + input_tensors.emplace_back(_tensor_builder->at(ifm_idx).get()); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::PackLayer>(); + + fn->configure(input_tensors, axis, output_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Unpack &node) +{ + const auto input_index{node.getInputs().at(0)}; + + const auto rank = node.param().rank; + const auto axis = + ::onert::backend::cpu::kernel::getAxis(rank, node.param().axis, _current_op_seq_layout); + + assert(-rank <= axis && axis < rank); + + auto input_alloc = _tensor_builder->at(input_index).get(); + + std::vector output_tensors; + for (auto &output_idx : node.getOutputs()) + output_tensors.emplace_back(_tensor_builder->at(output_idx).get()); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::UnpackLayer>(); + + uint32_t axis_resolved = (axis < 0 ? axis + rank : axis); + + fn->configure(input_alloc, axis_resolved, node.param().num, output_tensors); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Pad &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)}; + const auto pad_index{node.getInputs().at(ir::operation::Pad::Input::PAD)}; + const auto output_index{node.getOutputs().at(0)}; + assert(_ctx.at(pad_index).data()); + + auto input = _tensor_builder->at(input_index).get(); + auto output = _tensor_builder->at(output_index).get(); + auto pad_rank = _ctx.at(pad_index).shape().dim(0); + auto pad_base = reinterpret_cast(_ctx.at(pad_index).data()->base()); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::PadLayer>(); + + fn->configure(input, output, pad_base, pad_rank); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Max &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Max::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Max::Input::RHS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::MaxLayer>(); + + fn->configure(lhs_alloc, rhs_alloc, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Min &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Min::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Min::Input::RHS)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto lhs_alloc = _tensor_builder->at(lhs_index).get(); + auto rhs_alloc = _tensor_builder->at(rhs_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::MinLayer>(); + + fn->configure(lhs_alloc, rhs_alloc, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Cast &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Cast::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::CastLayer>(); + + fn->configure(ifm_alloc, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Transpose &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + auto rank = node.param().rank; + + auto fn = std::make_unique<::onert::backend::cpu::kernel::TransposeLayer>(); + + fn->configure(input_alloc, output_alloc, node.param().perm, rank); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::ReduceSum &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique(); + + fn->configure(input_alloc, output_alloc, kernel::ReduceType::kSum, node.param().axes, + node.param().keep_dims); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::ReduceMax &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique(); + + fn->configure(input_alloc, output_alloc, kernel::ReduceType::kMax, node.param().axes, + node.param().keep_dims); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::ReduceMin &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + + auto fn = std::make_unique(); + + fn->configure(input_alloc, output_alloc, kernel::ReduceType::kMin, node.param().axes, + node.param().keep_dims); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Slice &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Slice::Input::INPUT)}; + const auto begins_index{node.getInputs().at(ir::operation::Slice::Input::BEGINS)}; + const auto sizes_index{node.getInputs().at(ir::operation::Slice::Input::SIZES)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + auto begins_alloc = _tensor_builder->at(begins_index).get(); + auto sizes_alloc = _tensor_builder->at(sizes_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::SliceLayer>(); + + fn->configure(input_alloc, begins_alloc, sizes_alloc, output_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::StridedSlice &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)}; + const auto starts_index{node.getInputs().at(ir::operation::StridedSlice::Input::STARTS)}; + const auto ends_index{node.getInputs().at(ir::operation::StridedSlice::Input::ENDS)}; + const auto strides_index{node.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)}; + + auto output_alloc = _tensor_builder->at(output_index).get(); + auto input_alloc = _tensor_builder->at(input_index).get(); + auto starts_alloc = _tensor_builder->at(starts_index).get(); + auto ends_alloc = _tensor_builder->at(ends_index).get(); + auto strides_alloc = _tensor_builder->at(strides_index).get(); + + auto begin_mask = node.param().begin_mask; + auto end_mask = node.param().end_mask; + auto shrink_axis_mask = node.param().shrink_axis_mask; + auto rank = node.param().rank; + + auto fn = std::make_unique<::onert::backend::cpu::kernel::StridedSliceLayer>(); + + fn->configure(input_alloc, starts_alloc, ends_alloc, strides_alloc, output_alloc, begin_mask, + end_mask, shrink_axis_mask, rank); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Split &node) +{ + const auto num_splits = node.param().num_splits; + assert(num_splits == static_cast(node.getOutputs().size())); + + const auto rank = node.param().rank; + const auto axis = + ::onert::backend::cpu::kernel::getAxis(rank, node.param().axis, _current_op_seq_layout); + auto axis_resolved = axis < 0 ? axis + rank : axis; + assert(0 <= axis_resolved && axis_resolved < rank); + + const auto input_idx{node.getInputs().at(ir::operation::Split::Input::INPUT)}; + auto in_tensor = _tensor_builder->at(input_idx).get(); + + std::vector out_tensors; + for (auto &output_idx : node.getOutputs()) + out_tensors.emplace_back(_tensor_builder->at(output_idx).get()); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::SplitLayer>(); + + fn->configure(in_tensor, num_splits, axis_resolved, out_tensors); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Abs &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Abs::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::AbsLayer>(); + + fn->configure(ifm_alloc, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Sin &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Sin::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::SinLayer>(); + + fn->configure(ifm_alloc, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::RSQRT &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::RSQRT::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::RsqrtLayer>(); + + fn->configure(ifm_alloc, ofm_alloc); + + _return_fn = std::move(fn); +} + +void KernelGenerator::visit(const ir::operation::Shape &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Shape::Input::INPUT)}; + + auto ofm_alloc = _tensor_builder->at(ofm_index).get(); + auto ifm_alloc = _tensor_builder->at(ifm_index).get(); + + auto fn = std::make_unique<::onert::backend::cpu::kernel::ShapeLayer>(); + + fn->configure(ifm_alloc, ofm_alloc); + + _return_fn = std::move(fn); +} + +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/KernelGenerator.h b/runtime/onert/backend/cpu/KernelGenerator.h new file mode 100644 index 000000000..8291fa99d --- /dev/null +++ b/runtime/onert/backend/cpu/KernelGenerator.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_GENERATOR_H__ +#define __ONERT_BACKEND_CPU_KERNEL_GENERATOR_H__ + +#include "TensorBuilder.h" +#include "operand/Tensor.h" + +#include +#include +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +class KernelGenerator : public IKernelGenerator +{ +public: + KernelGenerator(const ir::Operands &ctx, const std::shared_ptr &tensor_builder, + const std::shared_ptr &kernel_builder); + + using IKernelGenerator::visit; + + void visit(const ir::OpSequence &) override; + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::MaxPool2D &) override; + void visit(const ir::operation::AvgPool2D &) override; + void visit(const ir::operation::Concat &) override; + void visit(const ir::operation::FullyConnected &) override; + void visit(const ir::operation::Reshape &) override; + void visit(const ir::operation::Squeeze &) override; + void visit(const ir::operation::Softmax &) override; + void visit(const ir::operation::Comparison &) override; + void visit(const ir::operation::Add &) override; + void visit(const ir::operation::Sub &) override; + void visit(const ir::operation::Mul &) override; + void visit(const ir::operation::Div &) override; + void visit(const ir::operation::Permute &) override; + void visit(const ir::operation::Gather &) override; + void visit(const ir::operation::Custom &node) override; + void visit(const ir::operation::Exp &) override; + void visit(const ir::operation::Logistic &) override; + void visit(const ir::operation::Pad &) override; + void visit(const ir::operation::Max &) override; + void visit(const ir::operation::Min &) override; + void visit(const ir::operation::Tanh &) override; + void visit(const ir::operation::Pack &) override; + void visit(const ir::operation::Unpack &) override; + void visit(const ir::operation::OneHot &) override; + void visit(const ir::operation::Cast &) override; + void visit(const ir::operation::Transpose &) override; + void visit(const ir::operation::ReduceSum &) override; + void visit(const ir::operation::ReduceMax &) override; + void visit(const ir::operation::ReduceMin &) override; + void visit(const ir::operation::Slice &) override; + void visit(const ir::operation::StridedSlice &) override; + void visit(const ir::operation::Split &) override; + void visit(const ir::operation::Abs &) override; + void visit(const ir::operation::Sin &) override; + void visit(const ir::operation::RSQRT &) override; + void visit(const ir::operation::Shape &) override; + +private: + const ir::Operands &_ctx; + std::shared_ptr _tensor_builder; + std::shared_ptr _kernel_builder; + ir::Layout _current_op_seq_layout; +}; + +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_GENERATOR_H__ diff --git a/runtime/onert/backend/cpu/ShapeFixer.cc b/runtime/onert/backend/cpu/ShapeFixer.cc new file mode 100644 index 000000000..4c2141128 --- /dev/null +++ b/runtime/onert/backend/cpu/ShapeFixer.cc @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ShapeFixer.h" + +#include "kernel/AddLayer.h" +#include "kernel/AvgPoolLayer.h" +#include "kernel/CastLayer.h" +#include "kernel/ConcatLayer.h" +#include "kernel/ConvolutionLayer.h" +#include "kernel/DepthwiseConvolutionLayer.h" +#include "kernel/DivLayer.h" +#include "kernel/ExpLayer.h" +#include "kernel/FullyConnectedLayer.h" +#include "kernel/GatherLayer.h" +#include "kernel/MaxPoolLayer.h" +#include "kernel/MulLayer.h" +#include "kernel/OperationUtils.h" +#include "kernel/PermuteLayer.h" +#include "kernel/ReshapeLayer.h" +#include "kernel/SoftMaxLayer.h" +#include "kernel/SubLayer.h" + +#include +#include +#include +#include +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +ShapeFixer::ShapeFixer(const ir::Operands &operand_ctx) : _ctx(operand_ctx) {} + +void ShapeFixer::visit(const ir::operation::Comparison &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Conv2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::DepthwiseConv2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::MaxPool2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::AvgPool2D &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Concat &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Exp &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::FullyConnected &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Reshape &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Squeeze &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Softmax &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Gather &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Add &node) +{ + const auto lhs_index{node.getInputs().at(ir::operation::Add::Input::LHS)}; + + // Quantization : not supported + if (_ctx.at(lhs_index).typeInfo().type() == ir::DataType::QUANT8_ASYMM) + { + throw std::runtime_error{"ShapeFixer: NYI for quantized Add"}; + } +} + +void ShapeFixer::visit(const ir::operation::Sub &node) +{ + // The same as Add + const auto lhs_index{node.getInputs().at(ir::operation::Sub::Input::LHS)}; + + // Quantization : not supported + if (_ctx.at(lhs_index).typeInfo().type() == ir::DataType::QUANT8_ASYMM) + { + throw std::runtime_error{"ShapeFixer: NYI for quantized Sub"}; + } +} + +void ShapeFixer::visit(const ir::operation::Mul &node) +{ + // The same as Add + const auto lhs_index{node.getInputs().at(ir::operation::Mul::Input::LHS)}; + + // Quantization : not supported + if (_ctx.at(lhs_index).typeInfo().type() == ir::DataType::QUANT8_ASYMM) + { + throw std::runtime_error{"ShapeFixer: NYI for quantized Mul"}; + } +} + +void ShapeFixer::visit(const ir::operation::Div &node) +{ + // The same as Add + const auto lhs_index{node.getInputs().at(ir::operation::Div::Input::LHS)}; + + // Quantization : not supported + if (_ctx.at(lhs_index).typeInfo().type() == ir::DataType::QUANT8_ASYMM) + { + throw std::runtime_error{"ShapeFixer: NYI for quantized Div"}; + } +} + +void ShapeFixer::visit(const ir::operation::Permute &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Custom &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Logistic &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Pad &node) +{ + // TODO: empty this method when quantization is supported + const auto lhs_index{node.getInputs().at(ir::operation::Sub::Input::LHS)}; + + // Quantization : not supported + if (_ctx.at(lhs_index).typeInfo().type() == ir::DataType::QUANT8_ASYMM) + { + throw std::runtime_error{"ShapeFixer: NYI for quantized Pad"}; + } +} + +void ShapeFixer::visit(const ir::operation::Max &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Min &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Tanh &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Pack &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Unpack &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::OneHot &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Cast &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Transpose &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReduceSum &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReduceMax &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::ReduceMin &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Slice &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::StridedSlice &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Split &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Abs &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Sin &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::RSQRT &) { /* DO NOTHING */} + +void ShapeFixer::visit(const ir::operation::Shape &) { /* DO NOTHING */} + +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/ShapeFixer.h b/runtime/onert/backend/cpu/ShapeFixer.h new file mode 100644 index 000000000..73bad4b15 --- /dev/null +++ b/runtime/onert/backend/cpu/ShapeFixer.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_SHAPE_FIXER_H__ +#define __ONERT_BACKEND_CPU_SHAPE_FIXER_H__ + +#include "TensorBuilder.h" +#include "operand/Tensor.h" + +#include +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +class ShapeFixer : public IShapeFixer +{ +public: + ShapeFixer(const ir::Operands &ctx); + + void visit(const ir::operation::Comparison &) override; + void visit(const ir::operation::Conv2D &) override; + void visit(const ir::operation::DepthwiseConv2D &) override; + void visit(const ir::operation::MaxPool2D &) override; + void visit(const ir::operation::AvgPool2D &) override; + void visit(const ir::operation::Concat &) override; + void visit(const ir::operation::FullyConnected &) override; + void visit(const ir::operation::Reshape &) override; + void visit(const ir::operation::Squeeze &) override; + void visit(const ir::operation::Softmax &) override; + void visit(const ir::operation::Add &) override; + void visit(const ir::operation::Gather &) override; + void visit(const ir::operation::Sub &) override; + void visit(const ir::operation::Mul &) override; + void visit(const ir::operation::Div &) override; + void visit(const ir::operation::Permute &) override; + void visit(const ir::operation::Custom &) override; + void visit(const ir::operation::Exp &) override; + void visit(const ir::operation::Logistic &) override; + void visit(const ir::operation::Pad &) override; + void visit(const ir::operation::Max &) override; + void visit(const ir::operation::Min &) override; + void visit(const ir::operation::Tanh &) override; + void visit(const ir::operation::Pack &) override; + void visit(const ir::operation::Unpack &) override; + void visit(const ir::operation::OneHot &) override; + void visit(const ir::operation::Cast &) override; + void visit(const ir::operation::Transpose &) override; + void visit(const ir::operation::ReduceSum &) override; + void visit(const ir::operation::ReduceMax &) override; + void visit(const ir::operation::ReduceMin &) override; + void visit(const ir::operation::Slice &) override; + void visit(const ir::operation::StridedSlice &) override; + void visit(const ir::operation::Split &) override; + void visit(const ir::operation::Abs &) override; + void visit(const ir::operation::Sin &) override; + void visit(const ir::operation::RSQRT &) override; + void visit(const ir::operation::Shape &) override; + +private: + const ir::Operands &_ctx; +}; + +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_SHAPE_FIXER_H__ diff --git a/runtime/onert/backend/cpu/TensorBuilder.cc b/runtime/onert/backend/cpu/TensorBuilder.cc new file mode 100644 index 000000000..cbf7c9e5c --- /dev/null +++ b/runtime/onert/backend/cpu/TensorBuilder.cc @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TensorBuilder.h" + +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +TensorBuilder::TensorBuilder() : _tensor_mgr{new TensorManager()} +{ + // DO NOTHING +} + +void TensorBuilder::registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info, + ir::Layout, bool as_const) +{ + _tensor_info_map.emplace(ind, info); + + if (as_const) + _constants.append(ind); +} + +void TensorBuilder::notifyFirstUse(const ir::OperandIndex &ind) +{ + assert(_tensor_info_map.find(ind) != _tensor_info_map.end()); + const auto tensor_info = _tensor_info_map.at(ind); + const auto size = tensor_info.total_size(); + _tensor_mgr->buildTensor(ind, tensor_info, _constants.contains(ind)); + _tensor_mgr->claimPlan(ind, size); +} + +void TensorBuilder::notifyLastUse(const ir::OperandIndex &ind) { _tensor_mgr->releasePlan(ind); } + +bool TensorBuilder::isRegistered(const ir::OperandIndex &ind) const +{ + return _tensor_info_map.find(ind) != _tensor_info_map.end(); +} + +void TensorBuilder::prepare(void) +{ + _tensor_mgr->allocateConsts(); + _tensor_mgr->allocateNonconsts(); +} + +void TensorBuilder::allocate() +{ + // NOTE For now nothing to do. Allocation is done in prepare stage, which is not appropriate + // This is because CPU kernels require `ITensor`s to be allocated before Kernel Generation. +} + +std::shared_ptr TensorBuilder::tensorAt(const ir::OperandIndex &ind) +{ + return _tensor_mgr->at(ind); +} + +void TensorBuilder::iterate(const IterateFunction &fn) { _tensor_mgr->iterate(fn); } + +std::shared_ptr TensorBuilder::at(const ir::OperandIndex &ind) +{ + auto ret = _tensor_mgr->at(ind); + assert(ret != nullptr); + return ret; +} + +std::unique_ptr TensorBuilder::releaseTensorManager(void) +{ + return std::move(_tensor_mgr); +} + +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/TensorBuilder.h b/runtime/onert/backend/cpu/TensorBuilder.h new file mode 100644 index 000000000..863eb77e2 --- /dev/null +++ b/runtime/onert/backend/cpu/TensorBuilder.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_TENSOR_BUILDER_H__ +#define __ONERT_BACKEND_CPU_TENSOR_BUILDER_H__ + +#include "TensorManager.h" +#include "operand/Tensor.h" + +#include +#include + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +class TensorBuilder : public ITensorBuilder +{ +public: + TensorBuilder(); + + /** + * @brief Register tensor information to allocate on CPU backend + * @param[in] ind Operand index + * @param[in] info Operand information + * @param[in] layout Operand data layout + */ + void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info, + ir::Layout backend_layout, bool as_const) override; + + void notifyFirstUse(const ir::OperandIndex &) override; + void notifyLastUse(const ir::OperandIndex &) override; + + bool isRegistered(const ir::OperandIndex &) const override; + + void prepare(void) override; + void allocate() override; + void postFunctionPrepare() override { /* DO NOTHING */} + + std::shared_ptr tensorAt(const ir::OperandIndex &ind) override; + + void iterate(const IterateFunction &fn) override; + + std::unique_ptr releaseTensorManager(void) override; + + std::shared_ptr at(const ir::OperandIndex &ind); + +private: + std::unique_ptr _tensor_mgr; + ir::OperandIndexMap _tensor_info_map; + ir::OperandIndexSequence _constants; +}; + +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_TENSOR_BUILDER_H__ diff --git a/runtime/onert/backend/cpu/TensorManager.cc b/runtime/onert/backend/cpu/TensorManager.cc new file mode 100644 index 000000000..96071bc51 --- /dev/null +++ b/runtime/onert/backend/cpu/TensorManager.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TensorManager.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +TensorManager::TensorManager() + : _const_mgr{new cpu_common::DynamicMemoryManager()}, + _nonconst_mgr{new cpu_common::MemoryManager()} +{ + // DO NOTHING +} + +void TensorManager::allocateConsts(void) +{ + for (auto &pair : _tensors) + { + const auto &ind = pair.first; + auto tensor = pair.second; + if (_as_constants[ind]) + { + auto mem_alloc = _const_mgr->allocate(ind, tensor->total_size()); + tensor->setBuffer(mem_alloc); + auto buffer = mem_alloc->base(); + VERBOSE(CPU_TENSORMANAGER) << "CONSTANT TENSOR(#" << ind.value() + << "): " << static_cast(buffer) + << "size : " << tensor->total_size() << std::endl; + } + } +} + +void TensorManager::allocateNonconsts(void) +{ + _nonconst_mgr->allocate(); + + for (auto &pair : _tensors) + { + const auto &ind = pair.first; + auto tensor = pair.second; + if (!_as_constants[ind]) + { + auto *buffer = _nonconst_mgr->getBuffer(ind); + tensor->setBuffer(buffer); + + VERBOSE(CPU_TENSORMANAGER) << "TENSOR(#" << ind.value() + << "): " << static_cast(buffer) << std::endl; + } + } +} + +void TensorManager::deallocateConsts(void) { _const_mgr->deallocate(); } + +void TensorManager::deallocateNonconsts(void) { _nonconst_mgr->deallocate(); } + +void TensorManager::buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &tensor_info, + bool as_const) +{ + assert(_tensors.find(ind) == _tensors.end()); + auto tensor = std::make_shared(tensor_info); + _tensors[ind] = tensor; + _as_constants[ind] = as_const; +} + +void TensorManager::claimPlan(const ir::OperandIndex &ind, uint32_t size) +{ + assert(_tensors.find(ind) != _tensors.end()); + if (!_as_constants[ind]) + _nonconst_mgr->claimPlan(ind, size); +} + +void TensorManager::releasePlan(const ir::OperandIndex &ind) +{ + assert(_tensors.find(ind) != _tensors.end()); + if (!_as_constants[ind]) + _nonconst_mgr->releasePlan(ind); +} + +std::shared_ptr TensorManager::at(const ir::OperandIndex &ind) +{ + if (_tensors.find(ind) == _tensors.end()) + return nullptr; + return _tensors.at(ind); +} + +void TensorManager::iterate(const std::function &fn) +{ + for (const auto &it : _tensors) + fn(it.first); +} + +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/TensorManager.h b/runtime/onert/backend/cpu/TensorManager.h new file mode 100644 index 000000000..ab1eec3fc --- /dev/null +++ b/runtime/onert/backend/cpu/TensorManager.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_TENSOR_MANAGER_H__ +#define __ONERT_BACKEND_CPU_TENSOR_MANAGER_H__ + +#include "MemoryManager.h" +#include "operand/Tensor.h" + +#include +#include +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ + +class TensorManager : public backend::ITensorManager +{ +public: + TensorManager(); + virtual ~TensorManager() = default; + + void allocateConsts(void); + void allocateNonconsts(void); + void deallocateConsts(void); + void deallocateNonconsts(void); + + void buildTensor(const ir::OperandIndex &ind, const ir::OperandInfo &tensor_info, bool as_const); + + void claimPlan(const ir::OperandIndex &ind, uint32_t size); + void releasePlan(const ir::OperandIndex &ind); + + std::shared_ptr at(const ir::OperandIndex &ind); + + void iterate(const std::function &fn); + +private: + std::unique_ptr _const_mgr; + std::unique_ptr _nonconst_mgr; + ir::OperandIndexMap> _tensors; + ir::OperandIndexMap _as_constants; +}; + +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_TENSOR_MANAGER_H__ diff --git a/runtime/onert/backend/cpu/cpu.cc b/runtime/onert/backend/cpu/cpu.cc new file mode 100644 index 000000000..5385bb2a3 --- /dev/null +++ b/runtime/onert/backend/cpu/cpu.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Backend.h" + +#include + +extern "C" { +onert::backend::Backend *onert_backend_create() +{ + VERBOSE(onert_backend_create) << "'cpu' loaded\n"; + return new onert::backend::cpu::Backend; +} + +void onert_backend_destroy(onert::backend::Backend *backend) +{ + VERBOSE(onert_backend_create) << "'cpu' unloaded\n"; + delete backend; +} +} diff --git a/runtime/onert/backend/cpu/kernel/AbsLayer.cc b/runtime/onert/backend/cpu/kernel/AbsLayer.cc new file mode 100644 index 000000000..770386826 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/AbsLayer.cc @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AbsLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +AbsLayer::AbsLayer() : _input(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +void AbsLayer::absFloat32() +{ + nnfw::cker::Abs(convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void AbsLayer::absQuant8() { throw std::runtime_error{"NYI"}; } + +void AbsLayer::configure(const operand::Tensor *input, operand::Tensor *output) +{ + _input = input; + _output = output; +} + +void AbsLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + absFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + absQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/AbsLayer.h b/runtime/onert/backend/cpu/kernel/AbsLayer.h new file mode 100644 index 000000000..551782a45 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/AbsLayer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in riting, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_ABSLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_ABSLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class AbsLayer : public ::onert::exec::IFunction +{ +public: + AbsLayer(); + +public: + void absFloat32(); + + void absQuant8(); + + void configure(const operand::Tensor *input, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_ABSLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/AddLayer.cc b/runtime/onert/backend/cpu/kernel/AddLayer.cc new file mode 100644 index 000000000..51320907d --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/AddLayer.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AddLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +void AddLayer::addFloat32() +{ + float output_activation_min, output_activation_max; + CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + nnfw::cker::BinaryArithmeticOpParam op_params; + op_params.type = nnfw::cker::BinaryArithmeticOpType::ADD; + op_params.float_activation_max = output_activation_max; + op_params.float_activation_min = output_activation_min; + + if (!HaveSameShapes(_lhs, _rhs)) + { + nnfw::cker::BroadcastBinaryArithmeticOpSlow( + op_params, convertToExtendedCkerShape(_lhs), + reinterpret_cast(_lhs->buffer()), convertToExtendedCkerShape(_rhs), + reinterpret_cast(_rhs->buffer()), convertToExtendedCkerShape(_output), + reinterpret_cast(_output->buffer())); + return; + } + + nnfw::cker::BinaryArithmeticOp( + op_params, convertTensorToCkerShape(_lhs), reinterpret_cast(_lhs->buffer()), + convertTensorToCkerShape(_rhs), reinterpret_cast(_rhs->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void AddLayer::addQuant8() +{ + int32_t output_activation_min, output_activation_max; + CalculateActivationRangeUint8(_activation, _output, &output_activation_min, + &output_activation_max); + // nnfw::cker::BinaryArithmeticOpParam op_params; + // op_params.quantized_activation_max = output_activation_max; + // op_params.quantized_activation_min = output_activation_min; + + // cker quant8 add is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void AddLayer::configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const ir::Activation activation, operand::Tensor *output) +{ + assert(lhs != nullptr); + assert(rhs != nullptr); + assert(output != nullptr); + + _lhs = lhs; + _rhs = rhs; + _activation = activation; + _output = output; +} + +void AddLayer::run() +{ + if (_lhs->data_type() == OperandType::FLOAT32) + { + addFloat32(); + } + else if (_lhs->data_type() == OperandType::QUANT8_ASYMM) + { + addQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/AddLayer.h b/runtime/onert/backend/cpu/kernel/AddLayer.h new file mode 100644 index 000000000..657decc72 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/AddLayer.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_ADDLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_ADDLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class AddLayer : public ::onert::exec::IFunction +{ +public: + AddLayer() : _lhs(nullptr), _rhs(nullptr), _output(nullptr) + { + // DO NOTHING + } + +public: + void addFloat32(); + + void addQuant8(); + + void configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const ir::Activation activation, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_lhs; + const operand::Tensor *_rhs; + operand::Tensor *_output; + + ir::Activation _activation{ir::Activation::NONE}; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_ADDLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/AvgPoolLayer.cc b/runtime/onert/backend/cpu/kernel/AvgPoolLayer.cc new file mode 100644 index 000000000..ba11b7cde --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/AvgPoolLayer.cc @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AvgPoolLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +#define AVGPOOLING_PARAMETERS \ + nnfw::cker::PoolParams op_params; \ + op_params.stride_height = _strideHeight; \ + op_params.stride_width = _strideWidth; \ + op_params.filter_height = _kernelHeight; \ + op_params.filter_width = _kernelWidth; \ + op_params.padding_values.height = (int8_t)_paddingTop; \ + op_params.padding_values.width = (int8_t)_paddingLeft; + +AvgPoolLayer::AvgPoolLayer() + : _input(nullptr), _output(nullptr), _paddingLeft(0), _paddingTop(0), _paddingRight(0), + _paddingBottom(0), _strideWidth(0), _strideHeight(0), _kernelWidth(0), _kernelHeight(0), + _activation(ir::Activation::NONE) +{ + // DO NOTHING +} + +void AvgPoolLayer::averagePoolFloat32() +{ + AVGPOOLING_PARAMETERS + float output_activation_min, output_activation_max; + CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; + + nnfw::cker::AveragePool(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} +void AvgPoolLayer::averagePoolQuant8() +{ + AVGPOOLING_PARAMETERS + int32_t output_activation_min = 0; + int32_t output_activation_max = 0; + CalculateActivationRangeUint8(_activation, _output, &output_activation_min, + &output_activation_max); + op_params.quantized_activation_min = output_activation_min; + op_params.quantized_activation_max = output_activation_max; + + nnfw::cker::AveragePool(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void AvgPoolLayer::configure(const operand::Tensor *input, const uint32_t paddingLeft, + const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideWidth, + const uint32_t strideHeight, const uint32_t kernelWidth, + const uint32_t kernelHeight, const ir::Activation activation, + operand::Tensor *output) +{ + assert(input != nullptr); + assert(output != nullptr); + + _input = input; + _paddingLeft = paddingLeft; + _paddingRight = paddingRight; + _paddingTop = paddingTop; + _paddingBottom = paddingBottom; + _strideWidth = strideWidth; + _strideHeight = strideHeight; + _kernelWidth = kernelWidth; + _kernelHeight = kernelHeight; + _activation = activation; + _output = output; +} + +void AvgPoolLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + averagePoolFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + averagePoolQuant8(); + } +} + +#undef AVGPOOLING_PARAMETERS + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/AvgPoolLayer.h b/runtime/onert/backend/cpu/kernel/AvgPoolLayer.h new file mode 100644 index 000000000..7d7ef980d --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/AvgPoolLayer.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_AVGPOOLLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_AVGPOOLLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class AvgPoolLayer : public ::onert::exec::IFunction +{ +public: + AvgPoolLayer(); + +public: + void averagePoolFloat32(); + + void averagePoolQuant8(); + + void configure(const operand::Tensor *input, const uint32_t paddingLeft, + const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideWidth, + const uint32_t strideHeight, const uint32_t kernelWidth, + const uint32_t kernelHeight, const ir::Activation activation, + operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; + + uint32_t _paddingLeft; + uint32_t _paddingTop; + uint32_t _paddingRight; + uint32_t _paddingBottom; + + uint32_t _strideWidth; + uint32_t _strideHeight; + uint32_t _kernelWidth; + uint32_t _kernelHeight; + + ir::Activation _activation; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_AVGPOOLLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/CastLayer.cc b/runtime/onert/backend/cpu/kernel/CastLayer.cc new file mode 100644 index 000000000..e485e04c7 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/CastLayer.cc @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CastLayer.h" + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +CastLayer::CastLayer() : _input(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +void CastLayer::configure(const operand::Tensor *input, operand::Tensor *output) +{ + _input = input; + _output = output; +} + +template void CastLayer::castTensor(const FromT *in, ToT *out) +{ + auto input_shape = convertTensorToCkerShape(_input); + auto output_shape = convertTensorToCkerShape(_output); + const auto num_elements = MatchingFlatSize(input_shape, output_shape); + + std::transform(in, in + num_elements, out, [](FromT a) { return static_cast(a); }); +} + +template void CastLayer::castPtr(const FromT *in, DataPtr out) +{ + switch (_output->data_type()) + { + case ir::DataType::FLOAT32: + castTensor(in, out.f); + return; + case ir::DataType::INT32: + castTensor(in, out.i32); + return; + case ir::DataType::UINT32: + castTensor(in, out.u32); + return; + case ir::DataType::UINT8: + castTensor(in, out.u8); + return; + case ir::DataType::BOOL8: + castTensor(in, out.b); + return; + case ir::DataType::QUANT8_ASYMM: + case ir::DataType::QUANT8_SYMM: + throw std::runtime_error("Not supported output type" + + std::to_string((int)_output->data_type())); + } +} + +void CastLayer::run() +{ + auto input_buf = _input->buffer(); + auto output_buf = _output->buffer(); + const auto in = *reinterpret_cast(&input_buf); + auto out = *reinterpret_cast(&output_buf); + + switch (_input->data_type()) + { + case ir::DataType::FLOAT32: + castPtr(in.f, out); + return; + case ir::DataType::INT32: + castPtr(in.i32, out); + return; + case ir::DataType::UINT32: + castPtr(in.u32, out); + return; + case ir::DataType::UINT8: + castPtr(in.u8, out); + return; + case ir::DataType::BOOL8: + castPtr(in.b, out); + return; + case ir::DataType::QUANT8_ASYMM: + case ir::DataType::QUANT8_SYMM: + throw std::runtime_error("Not supported input type" + + std::to_string((int)_input->data_type())); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/CastLayer.h b/runtime/onert/backend/cpu/kernel/CastLayer.h new file mode 100644 index 000000000..4690e1007 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/CastLayer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_CASTLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_CASTLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class CastLayer : public ::onert::exec::IFunction +{ +public: + CastLayer(); + +public: + template void castTensor(const FromT *in, ToT *out); + template void castPtr(const FromT *in, DataPtr out); + + void configure(const operand::Tensor *input, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_CASTLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/CompareLayer.cc b/runtime/onert/backend/cpu/kernel/CompareLayer.cc new file mode 100644 index 000000000..c8ee683b1 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/CompareLayer.cc @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "CompareLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +namespace +{ + +using OpType = onert::ir::operation::Comparison::ComparisonType; +using namespace onert::backend::cpu; + +template +void compareScalar(const operand::Tensor *lhs, const operand::Tensor *rhs, operand::Tensor *output, + OpType op_type) +{ + bool requires_broadcast = !HaveSameShapes(lhs, rhs); + + if (requires_broadcast) + { + switch (op_type) + { + case OpType::Equal: + Broadcast4DSlowEqual( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + case OpType::NotEqual: + Broadcast4DSlowNotEqual( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + case OpType::Greater: + Broadcast4DSlowGreater( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + case OpType::GreaterEqual: + Broadcast4DSlowGreaterEqual( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + case OpType::Less: + Broadcast4DSlowLess( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + case OpType::LessEqual: + Broadcast4DSlowLessEqual( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + default: + throw std::runtime_error{"Invalid OpType for CompareLayer"}; + } + } + else // if (requires_broadcast == false) + { + switch (op_type) + { + case OpType::Equal: + EqualNoScaling(convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), + reinterpret_cast(output->buffer())); + break; + case OpType::NotEqual: + NotEqualNoScaling( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + case OpType::Greater: + GreaterNoScaling( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + case OpType::GreaterEqual: + GreaterEqualNoScaling( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + case OpType::Less: + LessNoScaling(convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), + reinterpret_cast(output->buffer())); + break; + case OpType::LessEqual: + LessEqualNoScaling( + convertToExtendedCkerShape(lhs), reinterpret_cast(lhs->buffer()), + convertToExtendedCkerShape(rhs), reinterpret_cast(rhs->buffer()), + convertToExtendedCkerShape(output), reinterpret_cast(output->buffer())); + break; + default: + throw std::runtime_error{"Invalid OpType for CompareLayer"}; + } + } + return; +} +} // namespace + +CompareLayer::CompareLayer() + : _lhs(nullptr), _rhs(nullptr), _output(nullptr), + _op_type(ir::operation::Comparison::ComparisonType::Equal) +{ + // DO NOTHING +} + +void CompareLayer::compareQuant8() { throw std::runtime_error{"Compare NYI for quantized"}; } + +void CompareLayer::configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const OpType op_type, operand::Tensor *output) +{ + _lhs = lhs; + _rhs = rhs; + _op_type = op_type; + _output = output; +} + +void CompareLayer::run() +{ + if (_lhs->data_type() == OperandType::FLOAT32) + { + compareScalar(_lhs, _rhs, _output, _op_type); + } + else if (_lhs->data_type() == OperandType::INT32) + { + compareScalar(_lhs, _rhs, _output, _op_type); + } + else if (_lhs->data_type() == OperandType::BOOL8) + { + compareScalar(_lhs, _rhs, _output, _op_type); + } + else if (_lhs->data_type() == OperandType::QUANT8_ASYMM) + { + compareQuant8(); + } + else + { + throw std::runtime_error{"Compare: unsupported data type"}; + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/CompareLayer.h b/runtime/onert/backend/cpu/kernel/CompareLayer.h new file mode 100644 index 000000000..b62e5a2e4 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/CompareLayer.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_COMPARELAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_COMPARELAYER_H__ + +#include "../operand/Tensor.h" + +#include +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class CompareLayer : public ::onert::exec::IFunction +{ +public: + CompareLayer(); + +public: + void compareQuant8(); + + void configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const ir::operation::Comparison::ComparisonType op_type, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_lhs; + const operand::Tensor *_rhs; + operand::Tensor *_output; + ir::operation::Comparison::ComparisonType _op_type; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_COMPARELAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/ConcatLayer.cc b/runtime/onert/backend/cpu/kernel/ConcatLayer.cc new file mode 100644 index 000000000..80a29e8ce --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ConcatLayer.cc @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConcatLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +ConcatLayer::ConcatLayer() : _inputs(), _output(nullptr), _axis(0) +{ + // DO NOTHING +} + +void ConcatLayer::concatenationFloat32() +{ + uint32_t num_inputs = _inputs.size(); + + nnfw::cker::ConcatenationParams op_params; + op_params.axis = _axis; + op_params.inputs_count = num_inputs; + + std::vector inputDimsPtr; + std::vector inputDims; + inputDimsPtr.reserve(num_inputs); + inputDims.reserve(num_inputs); + + for (uint32_t i = 0; i < num_inputs; i++) + { + inputDims.push_back(convertTensorToCkerShape(_inputs[i])); + inputDimsPtr.push_back(&inputDims[i]); + } + + std::vector inputFloatPtrs; + + for (const auto input : _inputs) + { + inputFloatPtrs.emplace_back(reinterpret_cast(input->buffer())); + } + + nnfw::cker::Concatenation(op_params, inputDimsPtr.data(), inputFloatPtrs.data(), + convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} +void ConcatLayer::concatenationQuant8() +{ + uint32_t num_inputs = _inputs.size(); + + std::vector input_zeropoints(num_inputs); + std::vector input_scales(num_inputs); + for (uint32_t i = 0; i < num_inputs; i++) + { + input_zeropoints[i] = _inputs[i]->offset(); + input_scales[i] = _inputs[i]->scale(); + } + + nnfw::cker::ConcatenationParams op_params; + op_params.axis = _axis; + op_params.inputs_count = num_inputs; + op_params.input_zeropoint = input_zeropoints.data(); + op_params.input_scale = input_scales.data(); + op_params.output_zeropoint = _output->offset(); + op_params.output_scale = _output->scale(); + + std::vector inputDimsPtr; + std::vector inputDims; + inputDimsPtr.reserve(num_inputs); + inputDims.reserve(num_inputs); + for (uint32_t i = 0; i < num_inputs; i++) + { + inputDims.push_back(convertTensorToCkerShape(_inputs[i])); + inputDimsPtr.push_back(&inputDims[i]); + } + + std::vector inputDataPtrs; + for (const auto input : _inputs) + { + inputDataPtrs.emplace_back(reinterpret_cast(input->buffer())); + } + + nnfw::cker::ConcatenationWithScaling(op_params, inputDimsPtr.data(), inputDataPtrs.data(), + convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void ConcatLayer::configure(const std::vector &inputs, int32_t axis, + operand::Tensor *output) +{ + assert(inputs.size() > 0); + assert(output != nullptr); + + _inputs = inputs; + _axis = axis; + _output = output; +} + +void ConcatLayer::run() +{ + if (_output->data_type() == OperandType::FLOAT32) + { + concatenationFloat32(); + } + else if (_output->data_type() == OperandType::QUANT8_ASYMM) + { + concatenationQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/ConcatLayer.h b/runtime/onert/backend/cpu/kernel/ConcatLayer.h new file mode 100644 index 000000000..1ac1604cf --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ConcatLayer.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_CONCATLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_CONCATLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class ConcatLayer : public ::onert::exec::IFunction +{ +public: + ConcatLayer(); + +public: + void concatenationFloat32(); + + void concatenationQuant8(); + + void configure(const std::vector &inputs, int32_t axis, + operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + std::vector _inputs; + operand::Tensor *_output; + int32_t _axis; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_CONCATLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/ConvolutionLayer.cc b/runtime/onert/backend/cpu/kernel/ConvolutionLayer.cc new file mode 100644 index 000000000..398054527 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ConvolutionLayer.cc @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConvolutionLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ +ConvolutionLayer::ConvolutionLayer() + : _input(nullptr), _kernel(nullptr), _bias(nullptr), _output(nullptr), + _paddingType(ir::PaddingType::EXPLICIT), _paddingLeft(0), _paddingTop(0), _paddingRight(0), + _paddingBottom(0), _strideWidth(0), _strideHeight(0), _activation(ir::Activation::NONE), + _conv_kernel(new nnfw::cker::Conv()), _prepare(false) +{ + // DO NOTHING +} + +ConvolutionLayer::~ConvolutionLayer() = default; + +void ConvolutionLayer::convFloat32() +{ + float output_activation_min, output_activation_max; + CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + + nnfw::cker::ConvParams op_params; + op_params.padding_type = getPaddingType(_paddingType); + op_params.padding_values.width = _paddingLeft; + op_params.padding_values.height = _paddingTop; + op_params.stride_width = _strideWidth; + op_params.stride_height = _strideHeight; + op_params.dilation_width_factor = 1; + op_params.dilation_height_factor = 1; + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; + + nnfw::cker::Conv &kernel = *_conv_kernel; + if (!_prepare) + { + bool is_replaced_weights = false; + kernel.prepare(convertTensorToCkerShape(_kernel), + reinterpret_cast(_kernel->buffer()), op_params.padding_type, + is_replaced_weights); + + if (is_replaced_weights) + { + // TODO Remove const_cast + const_cast(_kernel)->decrease_ref(); + } + _prepare = true; + } + kernel(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_kernel), + reinterpret_cast(_kernel->buffer()), convertTensorToCkerShape(_bias), + reinterpret_cast(_bias->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void ConvolutionLayer::convQuant8() +{ + int32_t output_activation_min = 0; + int32_t output_activation_max = 0; + CalculateActivationRangeUint8(_activation, _output, &output_activation_min, + &output_activation_max); + + double real_multiplier = 0.0; + int32_t output_multiplier = 0; + int32_t output_shift = 0; + GetQuantizedConvolutionMultiplier(_input, _kernel, _bias, _output, &real_multiplier); + QuantizeMultiplier(real_multiplier, &output_multiplier, &output_shift); + + nnfw::cker::ConvParams op_params; + op_params.stride_width = _strideWidth; + op_params.stride_height = _strideHeight; + op_params.dilation_width_factor = 1; + op_params.dilation_height_factor = 1; + op_params.padding_type = getPaddingType(_paddingType); + op_params.padding_values.width = _paddingLeft; + op_params.padding_values.height = _paddingTop; + op_params.input_offset = -_input->offset(); + op_params.weights_offset = -_kernel->offset(); + op_params.output_offset = _output->offset(); + op_params.output_multiplier = output_multiplier; + op_params.output_shift = output_shift; + op_params.quantized_activation_min = output_activation_min; + op_params.quantized_activation_max = output_activation_max; + + nnfw::cker::Conv &kernel = *_conv_kernel; + if (!_prepare) + { + kernel.prepareQuant(convertTensorToCkerShape(_input), convertTensorToCkerShape(_kernel), + convertTensorToCkerShape(_output), _strideWidth, _strideHeight); + _prepare = true; + } + kernel(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_kernel), + reinterpret_cast(_kernel->buffer()), convertTensorToCkerShape(_bias), + reinterpret_cast(_bias->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void ConvolutionLayer::configure(const operand::Tensor *input, const operand::Tensor *kernel, + const operand::Tensor *bias, const ir::PaddingType paddingType, + const uint32_t paddingLeft, const uint32_t paddingRight, + const uint32_t paddingTop, const uint32_t paddingBottom, + const uint32_t strideWidth, const uint32_t strideHeight, + const ir::Activation activation, operand::Tensor *output) +{ + _input = input; + _kernel = kernel; + _bias = bias; + _paddingType = paddingType; + _paddingLeft = paddingLeft; + _paddingRight = paddingRight; + _paddingTop = paddingTop; + _paddingBottom = paddingBottom; + _strideWidth = strideWidth; + _strideHeight = strideHeight; + _activation = activation; + _output = output; +} + +void ConvolutionLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + convFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + convQuant8(); + } +} + +#undef ANDROID_NN_CONV_PARAMETERS + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/ConvolutionLayer.h b/runtime/onert/backend/cpu/kernel/ConvolutionLayer.h new file mode 100644 index 000000000..70af098c4 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ConvolutionLayer.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_CONVOLUTIONLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_CONVOLUTIONLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include +#include +#include + +namespace nnfw +{ +namespace cker +{ +class Conv; +} +} // namespace nnfw + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class ConvolutionLayer : public ::onert::exec::IFunction +{ +public: + ConvolutionLayer(); + ~ConvolutionLayer(); + +public: + void convFloat32(); + + void convQuant8(); + + void configure(const operand::Tensor *input, const operand::Tensor *kernel, + const operand::Tensor *bias, const ir::PaddingType paddingType, + const uint32_t paddingLeft, const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideW, const uint32_t strideH, + const ir::Activation activation, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + const operand::Tensor *_kernel; + const operand::Tensor *_bias; + operand::Tensor *_output; + + ir::PaddingType _paddingType; + uint32_t _paddingLeft; + uint32_t _paddingTop; + uint32_t _paddingRight; + uint32_t _paddingBottom; + + uint32_t _strideWidth; + uint32_t _strideHeight; + + ir::Activation _activation; + + std::unique_ptr _conv_kernel; + + bool _prepare; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_CONVOLUTIONLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/DepthwiseConvolutionLayer.cc b/runtime/onert/backend/cpu/kernel/DepthwiseConvolutionLayer.cc new file mode 100644 index 000000000..a1efe9fed --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/DepthwiseConvolutionLayer.cc @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DepthwiseConvolutionLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +DepthwiseConvolutionLayer::DepthwiseConvolutionLayer() + : _input(nullptr), _kernel(nullptr), _bias(nullptr), _output(nullptr), _paddingLeft(0), + _paddingTop(0), _paddingRight(0), _paddingBottom(0), _strideWidth(0), _strideHeight(0), + _multiplier(0), _activation(ir::Activation::NONE) +{ + // DO NOTHING +} + +void DepthwiseConvolutionLayer::convFloat32() +{ + float output_activation_min, output_activation_max; + CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + + nnfw::cker::DepthwiseConvParams op_params; + op_params.stride_width = _strideWidth; + op_params.stride_height = _strideHeight; + op_params.dilation_width_factor = 1; + op_params.dilation_height_factor = 1; + op_params.padding_values.width = _paddingLeft; + op_params.padding_values.height = _paddingTop; + op_params.depth_multiplier = _multiplier; + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; + + nnfw::cker::DepthwiseConv( + op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_kernel), + reinterpret_cast(_kernel->buffer()), convertTensorToCkerShape(_bias), + reinterpret_cast(_bias->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void DepthwiseConvolutionLayer::convQuant8() +{ + int32_t output_activation_min = 0; + int32_t output_activation_max = 0; + CalculateActivationRangeUint8(_activation, _output, &output_activation_min, + &output_activation_max); + + double real_multiplier = 0.0; + int32_t output_multiplier = 0; + int32_t output_shift = 0; + GetQuantizedConvolutionMultiplier(_input, _kernel, _bias, _output, &real_multiplier); + QuantizeMultiplier(real_multiplier, &output_multiplier, &output_shift); + + nnfw::cker::DepthwiseConvParams op_params; + op_params.stride_width = _strideWidth; + op_params.stride_height = _strideHeight; + op_params.dilation_width_factor = 1; + op_params.dilation_height_factor = 1; + op_params.padding_values.width = _paddingLeft; + op_params.padding_values.height = _paddingTop; + op_params.depth_multiplier = _multiplier; + op_params.input_offset = -_input->offset(); + op_params.weights_offset = -_kernel->offset(); + op_params.output_offset = _output->offset(); + op_params.output_multiplier = output_multiplier; + op_params.output_shift = output_shift; + op_params.quantized_activation_min = output_activation_min; + op_params.quantized_activation_max = output_activation_max; + + nnfw::cker::DepthwiseConv( + op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_kernel), + reinterpret_cast(_kernel->buffer()), convertTensorToCkerShape(_bias), + reinterpret_cast(_bias->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void DepthwiseConvolutionLayer::configure(const operand::Tensor *input, + const operand::Tensor *kernel, + const operand::Tensor *bias, const uint32_t paddingLeft, + const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideWidth, + const uint32_t strideHeight, const uint32_t multiplier, + const ir::Activation activation, operand::Tensor *output) +{ + _input = input; + _kernel = kernel; + _bias = bias; + _paddingLeft = paddingLeft; + _paddingRight = paddingRight; + _paddingTop = paddingTop; + _paddingBottom = paddingBottom; + _strideWidth = strideWidth; + _strideHeight = strideHeight; + _multiplier = multiplier; + _activation = activation; + _output = output; +} + +void DepthwiseConvolutionLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + convFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + convQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/DepthwiseConvolutionLayer.h b/runtime/onert/backend/cpu/kernel/DepthwiseConvolutionLayer.h new file mode 100644 index 000000000..dcc3762cc --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/DepthwiseConvolutionLayer.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_KERNEL_CPU_DEPTHWISECONVOLUTIONLAYER_H__ +#define __ONERT_KERNEL_CPU_DEPTHWISECONVOLUTIONLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class DepthwiseConvolutionLayer : public ::onert::exec::IFunction +{ +public: + DepthwiseConvolutionLayer(); + +public: + void convFloat32(); + + void convQuant8(); + + void configure(const operand::Tensor *input, const operand::Tensor *kernel, + const operand::Tensor *bias, const uint32_t paddingLeft, + const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideW, const uint32_t strideH, + const uint32_t multiplier, const ir::Activation activation, + operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + const operand::Tensor *_kernel; + const operand::Tensor *_bias; + operand::Tensor *_output; + + uint32_t _paddingLeft; + uint32_t _paddingTop; + uint32_t _paddingRight; + uint32_t _paddingBottom; + + uint32_t _strideWidth; + uint32_t _strideHeight; + + uint32_t _multiplier; + + ir::Activation _activation; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_KERNEL_CPU_DEPTHWISECONVOLUTIONLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/DivLayer.cc b/runtime/onert/backend/cpu/kernel/DivLayer.cc new file mode 100644 index 000000000..ec9daae9b --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/DivLayer.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DivLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +void DivLayer::divFloat32() +{ + float output_activation_min, output_activation_max; + CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + nnfw::cker::BinaryArithmeticOpParam op_params; + op_params.type = nnfw::cker::BinaryArithmeticOpType::DIV; + op_params.float_activation_max = output_activation_max; + op_params.float_activation_min = output_activation_min; + + if (!HaveSameShapes(_lhs, _rhs)) + { + nnfw::cker::BroadcastBinaryArithmeticOpSlow( + op_params, convertToExtendedCkerShape(_lhs), + reinterpret_cast(_lhs->buffer()), convertToExtendedCkerShape(_rhs), + reinterpret_cast(_rhs->buffer()), convertToExtendedCkerShape(_output), + reinterpret_cast(_output->buffer())); + return; + } + + nnfw::cker::BinaryArithmeticOp( + op_params, convertTensorToCkerShape(_lhs), reinterpret_cast(_lhs->buffer()), + convertTensorToCkerShape(_rhs), reinterpret_cast(_rhs->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void DivLayer::divQuant8() +{ + int32_t output_activation_min, output_activation_max; + CalculateActivationRangeUint8(_activation, _output, &output_activation_min, + &output_activation_max); + // nnfw::cker::BinaryArithmeticOpParam op_params; + // op_params.quantized_activation_max = output_activation_max; + // op_params.quantized_activation_min = output_activation_min; + + // cker quant8 div is not implemented yet + throw std::runtime_error{"Div NYI for quantized"}; +} + +void DivLayer::configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const ir::Activation activation, operand::Tensor *output) +{ + _lhs = lhs; + _rhs = rhs; + _activation = activation; + _output = output; +} + +void DivLayer::run() +{ + if (_output->data_type() == OperandType::FLOAT32) + { + divFloat32(); + } + else if (_output->data_type() == OperandType::QUANT8_ASYMM) + { + divQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/DivLayer.h b/runtime/onert/backend/cpu/kernel/DivLayer.h new file mode 100644 index 000000000..3e14d9c19 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/DivLayer.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_DIVLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_DIVLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class DivLayer : public ::onert::exec::IFunction +{ +public: + DivLayer() : _lhs(nullptr), _rhs(nullptr), _output(nullptr) + { + // DO NOTHING + } + +public: + void divFloat32(); + + void divQuant8(); + + void configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const ir::Activation activation, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_lhs; + const operand::Tensor *_rhs; + operand::Tensor *_output; + + ir::Activation _activation{ir::Activation::NONE}; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_DIVLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/ExpLayer.cc b/runtime/onert/backend/cpu/kernel/ExpLayer.cc new file mode 100644 index 000000000..335a789b2 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ExpLayer.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ExpLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +ExpLayer::ExpLayer() : _input(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +void ExpLayer::expFloat32() +{ + nnfw::cker::Exp(convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void ExpLayer::expQuant8() +{ + // cker quant8 exp is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void ExpLayer::configure(const operand::Tensor *input, operand::Tensor *output) +{ + _input = input; + _output = output; +} + +void ExpLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + expFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + expQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/ExpLayer.h b/runtime/onert/backend/cpu/kernel/ExpLayer.h new file mode 100644 index 000000000..5a7222fad --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ExpLayer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_EXPLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_EXPLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class ExpLayer : public ::onert::exec::IFunction +{ +public: + ExpLayer(); + +public: + void expFloat32(); + + void expQuant8(); + + void configure(const operand::Tensor *input, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_EXPLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/FullyConnectedLayer.cc b/runtime/onert/backend/cpu/kernel/FullyConnectedLayer.cc new file mode 100644 index 000000000..636df8941 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/FullyConnectedLayer.cc @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FullyConnectedLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +FullyConnectedLayer::FullyConnectedLayer() + : _input(nullptr), _weights(nullptr), _bias(nullptr), _output(nullptr), + _activation(ir::Activation::NONE), _temp_arena(new nnfw::cker::FCTempArena()) +{ + // DO NOTHING +} + +FullyConnectedLayer::~FullyConnectedLayer() = default; + +void FullyConnectedLayer::fullyConnectedFloat32() +{ + float output_activation_min, output_activation_max; + CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + + nnfw::cker::FullyConnectedParams op_params; + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; + op_params.activation = convertActivationType(_activation); + + nnfw::cker::FullyConnected( + op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_weights), + reinterpret_cast(_weights->buffer()), convertTensorToCkerShape(_bias), + reinterpret_cast(_bias->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +// executionMutex is used to protect concurrent access of non-threadsafe resources +// like gemmlowp::GemmContext. +void FullyConnectedLayer::fullyConnectedQuant8() +{ + double real_multiplier = 0.0; + int32_t output_multiplier = 0; + int32_t output_shift = 0; + int32_t output_activation_min = 0; + int32_t output_activation_max = 0; + GetQuantizedConvolutionMultiplier(_input, _weights, _bias, _output, &real_multiplier); + QuantizeMultiplier(real_multiplier, &output_multiplier, &output_shift); + CalculateActivationRangeUint8(_activation, _output, &output_activation_min, + &output_activation_max); + + nnfw::cker::FullyConnectedParams op_params; + op_params.input_offset = -_input->offset(); + op_params.weights_offset = -_weights->offset(); + op_params.output_offset = _output->offset(); + op_params.output_multiplier = output_multiplier; + op_params.output_shift = output_shift; + op_params.quantized_activation_min = output_activation_min; + op_params.quantized_activation_max = output_activation_max; + + nnfw::cker::FullyConnected( + op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_weights), + reinterpret_cast(_weights->buffer()), convertTensorToCkerShape(_bias), + reinterpret_cast(_bias->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void FullyConnectedLayer::fullyConnectedHybrid() +{ + nnfw::cker::FCTempArena &temp_arena = *_temp_arena; + if (!temp_arena.prepared) + { + temp_arena.prepare(convertTensorToCkerShape(_input), convertTensorToCkerShape(_weights)); + } + + nnfw::cker::FullyConnectedParams op_params; + op_params.activation = convertActivationType(_activation); + op_params.weights_scale = _weights->scale(); + + nnfw::cker::FullyConnectedHybrid( + op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_weights), + reinterpret_cast(_weights->buffer()), convertTensorToCkerShape(_bias), + reinterpret_cast(_bias->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer()), temp_arena); +} + +void FullyConnectedLayer::configure(const operand::Tensor *input, const operand::Tensor *weights, + const operand::Tensor *bias, ir::Activation activation, + operand::Tensor *output) +{ + _input = input; + _weights = weights; + _bias = bias; + _activation = activation; + _output = output; +} + +void FullyConnectedLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + if (_weights->data_type() == OperandType::QUANT8_SYMM) + { + fullyConnectedHybrid(); + } + else + { + fullyConnectedFloat32(); + } + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + fullyConnectedQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/FullyConnectedLayer.h b/runtime/onert/backend/cpu/kernel/FullyConnectedLayer.h new file mode 100644 index 000000000..616124bac --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/FullyConnectedLayer.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_FULLYCONNECTEDLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_FULLYCONNECTEDLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace nnfw +{ +namespace cker +{ +class FCTempArena; +} +} // namespace nnfw + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class FullyConnectedLayer : public ::onert::exec::IFunction +{ +public: + FullyConnectedLayer(); + ~FullyConnectedLayer(); + +public: + void fullyConnectedFloat32(); + + void fullyConnectedQuant8(); + + void fullyConnectedHybrid(); + + void configure(const operand::Tensor *input, const operand::Tensor *weights, + const operand::Tensor *bias, ir::Activation activation, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + const operand::Tensor *_weights; + const operand::Tensor *_bias; + operand::Tensor *_output; + + ir::Activation _activation; + std::unique_ptr _temp_arena; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_FULLYCONNECTEDLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/GatherLayer.cc b/runtime/onert/backend/cpu/kernel/GatherLayer.cc new file mode 100644 index 000000000..07f30136c --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/GatherLayer.cc @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "GatherLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +void GatherLayer::configure(const operand::Tensor *input, const operand::Tensor *indices, + operand::Tensor *output, int32_t axis) +{ + _input = input; + _indices = indices; + _axis = axis; + _output = output; +} + +void GatherLayer::run() +{ + nnfw::cker::GatherParams op_params; + op_params.axis = _axis; + + switch (_input->data_type()) + { + case OperandType::FLOAT32: + nnfw::cker::Gather( + op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_indices), + reinterpret_cast(_indices->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); + break; + case OperandType::QUANT8_ASYMM: + nnfw::cker::Gather( + op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_indices), + reinterpret_cast(_indices->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); + break; + case OperandType::INT32: + nnfw::cker::Gather( + op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), convertTensorToCkerShape(_indices), + reinterpret_cast(_indices->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); + break; + default: + throw std::runtime_error("Gather NYI for this operand type!"); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/GatherLayer.h b/runtime/onert/backend/cpu/kernel/GatherLayer.h new file mode 100644 index 000000000..2ff3605a2 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/GatherLayer.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_GATHERLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_GATHERLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class GatherLayer : public ::onert::exec::IFunction +{ +public: + GatherLayer() : _input{nullptr}, _indices{nullptr}, _output{nullptr}, _axis{-1} + { + // DO NOTHING + } + +public: + void configure(const operand::Tensor *input, const operand::Tensor *indices, + operand::Tensor *output, int32_t axis); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + const operand::Tensor *_indices; + operand::Tensor *_output; + + int32_t _axis; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_GATHERLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/LogisticLayer.cc b/runtime/onert/backend/cpu/kernel/LogisticLayer.cc new file mode 100644 index 000000000..07f434048 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/LogisticLayer.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LogisticLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +LogisticLayer::LogisticLayer() : _input(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +void LogisticLayer::logisticFloat32() +{ + nnfw::cker::Logistic( + convertTensorToCkerShape(_input), reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void LogisticLayer::logisticQuant8() +{ + // cker quant8 logistic is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void LogisticLayer::configure(const operand::Tensor *input, operand::Tensor *output) +{ + _input = input; + _output = output; +} + +void LogisticLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + logisticFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + logisticQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/LogisticLayer.h b/runtime/onert/backend/cpu/kernel/LogisticLayer.h new file mode 100644 index 000000000..76ee1600f --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/LogisticLayer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_LOGISTICLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_LOGISTICLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class LogisticLayer : public ::onert::exec::IFunction +{ +public: + LogisticLayer(); + +public: + void logisticFloat32(); + + void logisticQuant8(); + + void configure(const operand::Tensor *input, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_LOGISTICLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/MaxLayer.cc b/runtime/onert/backend/cpu/kernel/MaxLayer.cc new file mode 100644 index 000000000..701d73a35 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/MaxLayer.cc @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MaxLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +void MaxLayer::maxFloat32() +{ + nnfw::cker::Max( + convertTensorToCkerShape(_lhs), reinterpret_cast(_lhs->buffer()), + convertTensorToCkerShape(_rhs), reinterpret_cast(_rhs->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void MaxLayer::maxQuant8() +{ + // TODO Check whether cker for quant8 max produces correct results + // nnfw::cker::Max( + // convertTensorToCkerShape(_lhs), reinterpret_cast(_lhs->buffer()), + // convertTensorToCkerShape(_rhs), reinterpret_cast(_rhs->buffer()), + // convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); + + throw std::runtime_error("Max NYI for quantized"); +} + +void MaxLayer::configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + operand::Tensor *output) +{ + assert(lhs != nullptr); + assert(rhs != nullptr); + assert(output != nullptr); + + _lhs = lhs; + _rhs = rhs; + _output = output; +} + +void MaxLayer::run() +{ + if (_lhs->data_type() == OperandType::FLOAT32) + { + maxFloat32(); + } + else if (_lhs->data_type() == OperandType::QUANT8_ASYMM) + { + maxQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/MaxLayer.h b/runtime/onert/backend/cpu/kernel/MaxLayer.h new file mode 100644 index 000000000..2cccf26ae --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/MaxLayer.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_MAXLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_MAXLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class MaxLayer : public ::onert::exec::IFunction +{ +public: + MaxLayer() : _lhs(nullptr), _rhs(nullptr), _output(nullptr) + { + // DO NOTHING + } + +public: + void maxFloat32(); + + void maxQuant8(); + + void configure(const operand::Tensor *lhs, const operand::Tensor *rhs, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_lhs; + const operand::Tensor *_rhs; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_MAXLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/MaxPoolLayer.cc b/runtime/onert/backend/cpu/kernel/MaxPoolLayer.cc new file mode 100644 index 000000000..e35d5e92a --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/MaxPoolLayer.cc @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MaxPoolLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +#define MAXPOOLING_PARAMETERS \ + nnfw::cker::PoolParams op_params; \ + op_params.stride_height = _strideHeight; \ + op_params.stride_width = _strideWidth; \ + op_params.filter_height = _kernelHeight; \ + op_params.filter_width = _kernelWidth; \ + op_params.padding_values.height = (int8_t)_paddingTop; \ + op_params.padding_values.width = (int8_t)_paddingLeft; + +MaxPoolLayer::MaxPoolLayer() + : _input(nullptr), _output(nullptr), _paddingLeft(0), _paddingTop(0), _paddingRight(0), + _paddingBottom(0), _strideWidth(0), _strideHeight(0), _kernelWidth(0), _kernelHeight(0), + _activation(ir::Activation::NONE) +{ + // DO NOTHING +} + +void MaxPoolLayer::maxPoolFloat32() +{ + MAXPOOLING_PARAMETERS + float output_activation_min, output_activation_max; + CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; + + nnfw::cker::MaxPool(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} +void MaxPoolLayer::maxPoolQuant8() +{ + MAXPOOLING_PARAMETERS + int32_t output_activation_min = 0; + int32_t output_activation_max = 0; + CalculateActivationRangeUint8(_activation, _output, &output_activation_min, + &output_activation_max); + op_params.quantized_activation_min = output_activation_min; + op_params.quantized_activation_max = output_activation_max; + + nnfw::cker::MaxPool(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void MaxPoolLayer::configure(const operand::Tensor *input, const uint32_t paddingLeft, + const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideWidth, + const uint32_t strideHeight, const uint32_t kernelWidth, + const uint32_t kernelHeight, const ir::Activation activation, + operand::Tensor *output) +{ + _input = input; + _paddingLeft = paddingLeft; + _paddingRight = paddingRight; + _paddingTop = paddingTop; + _paddingBottom = paddingBottom; + _strideWidth = strideWidth; + _strideHeight = strideHeight; + _kernelWidth = kernelWidth; + _kernelHeight = kernelHeight; + _activation = activation; + _output = output; +} + +void MaxPoolLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + maxPoolFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + maxPoolQuant8(); + } +} + +#undef MAXPOOLING_PARAMETERS + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/MaxPoolLayer.h b/runtime/onert/backend/cpu/kernel/MaxPoolLayer.h new file mode 100644 index 000000000..a29e09e1b --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/MaxPoolLayer.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_MAXPOOLLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_MAXPOOLLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class MaxPoolLayer : public ::onert::exec::IFunction +{ +public: + MaxPoolLayer(); + +public: + void maxPoolFloat32(); + + void maxPoolQuant8(); + + void configure(const operand::Tensor *input, const uint32_t paddingLeft, + const uint32_t paddingRight, const uint32_t paddingTop, + const uint32_t paddingBottom, const uint32_t strideWidth, + const uint32_t strideHeight, const uint32_t kernelWidth, + const uint32_t kernelHeight, const ir::Activation activation, + operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; + + uint32_t _paddingLeft; + uint32_t _paddingTop; + uint32_t _paddingRight; + uint32_t _paddingBottom; + + uint32_t _strideWidth; + uint32_t _strideHeight; + uint32_t _kernelWidth; + uint32_t _kernelHeight; + + ir::Activation _activation; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_MAXPOOLLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/MinLayer.cc b/runtime/onert/backend/cpu/kernel/MinLayer.cc new file mode 100644 index 000000000..07cb8ab91 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/MinLayer.cc @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MinLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +void MinLayer::minFloat32() +{ + nnfw::cker::Min( + convertTensorToCkerShape(_lhs), reinterpret_cast(_lhs->buffer()), + convertTensorToCkerShape(_rhs), reinterpret_cast(_rhs->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void MinLayer::minQuant8() +{ + // TODO Check whether cker for quant8 min produces correct results + // nnfw::cker::Min( + // convertTensorToCkerShape(_lhs), reinterpret_cast(_lhs->buffer()), + // convertTensorToCkerShape(_rhs), reinterpret_cast(_rhs->buffer()), + // convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); + + throw std::runtime_error("Min NYI for quantized"); +} + +void MinLayer::configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + operand::Tensor *output) +{ + assert(lhs != nullptr); + assert(rhs != nullptr); + assert(output != nullptr); + + _lhs = lhs; + _rhs = rhs; + _output = output; +} + +void MinLayer::run() +{ + if (_lhs->data_type() == OperandType::FLOAT32) + { + minFloat32(); + } + else if (_lhs->data_type() == OperandType::QUANT8_ASYMM) + { + minQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/MinLayer.h b/runtime/onert/backend/cpu/kernel/MinLayer.h new file mode 100644 index 000000000..5beb6444a --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/MinLayer.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_MINLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_MINLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class MinLayer : public ::onert::exec::IFunction +{ +public: + MinLayer() : _lhs(nullptr), _rhs(nullptr), _output(nullptr) + { + // DO NOTHING + } + +public: + void minFloat32(); + + void minQuant8(); + + void configure(const operand::Tensor *lhs, const operand::Tensor *rhs, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_lhs; + const operand::Tensor *_rhs; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_MINLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/MulLayer.cc b/runtime/onert/backend/cpu/kernel/MulLayer.cc new file mode 100644 index 000000000..df7d71eec --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/MulLayer.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MulLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +void MulLayer::mulFloat32() +{ + float output_activation_min, output_activation_max; + CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + nnfw::cker::BinaryArithmeticOpParam op_params; + op_params.type = nnfw::cker::BinaryArithmeticOpType::MUL; + op_params.float_activation_max = output_activation_max; + op_params.float_activation_min = output_activation_min; + + if (!HaveSameShapes(_lhs, _rhs)) + { + nnfw::cker::BroadcastBinaryArithmeticOpSlow( + op_params, convertToExtendedCkerShape(_lhs), + reinterpret_cast(_lhs->buffer()), convertToExtendedCkerShape(_rhs), + reinterpret_cast(_rhs->buffer()), convertToExtendedCkerShape(_output), + reinterpret_cast(_output->buffer())); + return; + } + + nnfw::cker::BinaryArithmeticOp( + op_params, convertTensorToCkerShape(_lhs), reinterpret_cast(_lhs->buffer()), + convertTensorToCkerShape(_rhs), reinterpret_cast(_rhs->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void MulLayer::mulQuant8() +{ + int32_t output_activation_min, output_activation_max; + CalculateActivationRangeUint8(_activation, _output, &output_activation_min, + &output_activation_max); + // nnfw::cker::BinaryArithmeticOpParam op_params; + // op_params.quantized_activation_max = output_activation_max; + // op_params.quantized_activation_min = output_activation_min; + + // cker quant8 mul is not implemented yet + throw std::runtime_error{"Mull NYI for quantized"}; +} + +void MulLayer::configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const ir::Activation activation, operand::Tensor *output) +{ + _lhs = lhs; + _rhs = rhs; + _activation = activation; + _output = output; +} + +void MulLayer::run() +{ + if (_output->data_type() == OperandType::FLOAT32) + { + mulFloat32(); + } + else if (_output->data_type() == OperandType::QUANT8_ASYMM) + { + mulQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/MulLayer.h b/runtime/onert/backend/cpu/kernel/MulLayer.h new file mode 100644 index 000000000..a5cf25f0f --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/MulLayer.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_MULLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_MULLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class MulLayer : public ::onert::exec::IFunction +{ +public: + MulLayer() : _lhs(nullptr), _rhs(nullptr), _output(nullptr) + { + // DO NOTHING + } + +public: + void mulFloat32(); + + void mulQuant8(); + + void configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const ir::Activation activation, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_lhs; + const operand::Tensor *_rhs; + operand::Tensor *_output; + + ir::Activation _activation{ir::Activation::NONE}; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_MULLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/OneHotLayer.cc b/runtime/onert/backend/cpu/kernel/OneHotLayer.cc new file mode 100644 index 000000000..fd2c1b795 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/OneHotLayer.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OneHotLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +void OneHotLayer::oneHotFloat32() +{ + nnfw::cker::OneHot( + _depth, _on_value, _off_value, _axis, convertTensorToCkerShape(_indices), + reinterpret_cast(_indices->buffer()), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void OneHotLayer::oneHotQuant8() { throw std::runtime_error{"OneHot NYI for quantized"}; } + +void OneHotLayer::configure(const operand::Tensor *indices, operand::Tensor *output, int32_t depth, + float on_value, float off_value, int32_t axis) +{ + _indices = indices; + _output = output; + _depth = depth; + _on_value = on_value; + _off_value = off_value; + _axis = axis; + if (_axis == -1) + _axis = _indices->num_dimensions(); +} + +void OneHotLayer::run() +{ + if (_output->data_type() == OperandType::FLOAT32) + { + oneHotFloat32(); + } + else if (_output->data_type() == OperandType::QUANT8_ASYMM) + { + oneHotQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/OneHotLayer.h b/runtime/onert/backend/cpu/kernel/OneHotLayer.h new file mode 100644 index 000000000..5f23481ba --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/OneHotLayer.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_ONEHOTLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_ONEHOTLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class OneHotLayer : public ::onert::exec::IFunction +{ +public: + OneHotLayer() + : _indices(nullptr), _output(nullptr), _depth(0), _on_value(1), _off_value(0), _axis(-1) + { + // DO NOTHING + } + +public: + void oneHotFloat32(); + + void oneHotQuant8(); + + void configure(const operand::Tensor *indices, operand::Tensor *output, int32_t depth, + float on_value, float off_value, int32_t axis); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_indices; + operand::Tensor *_output; + + int32_t _depth; + float _on_value; + float _off_value; + int32_t _axis; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_ONEHOTLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/OperationUtils.cc b/runtime/onert/backend/cpu/kernel/OperationUtils.cc new file mode 100644 index 000000000..178aac833 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/OperationUtils.cc @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperationUtils.h" + +#include +#include +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +uint32_t getNumberOfDimensions(const operand::Tensor *tensor) +{ + assert(tensor); + return tensor->num_dimensions(); +} + +uint32_t getNumberOfElements(const operand::Tensor *tensor) +{ + assert(tensor); + uint32_t count = 1; + for (size_t i = 0; i < tensor->num_dimensions(); i++) + { + count *= tensor->dimension(i); + } + return count; +} + +uint32_t getSizeOfDimension(const operand::Tensor *tensor, uint32_t dimensionIdx) +{ + assert(tensor); + if (dimensionIdx >= tensor->num_dimensions()) + { + // TODO, log the error + return 0; + } + return tensor->dimension(dimensionIdx); +} + +void QuantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift) +{ + if (double_multiplier == 0.) + { + *quantized_multiplier = 0; + *shift = 0; + return; + } + const double q = std::frexp(double_multiplier, shift); + auto q_fixed = static_cast(std::round(q * (1ll << 31))); + + assert(q_fixed <= (1ll << 31)); + if (q_fixed == (1ll << 31)) + { + q_fixed /= 2; + ++*shift; + } + assert(q_fixed <= std::numeric_limits::max()); + *quantized_multiplier = static_cast(q_fixed); +} + +void GetQuantizedConvolutionMultiplier(const operand::Tensor *input, const operand::Tensor *filter, + const operand::Tensor *bias, const operand::Tensor *output, + double *multiplier) +{ + const double input_product_scale = input->scale() * filter->scale(); + const double bias_scale = bias->scale(); + const double output_scale = output->scale(); + // The following conditions must be guaranteed by the training pipeline. + UNUSED_RELEASE(bias_scale); + assert(std::abs(input_product_scale - bias_scale) <= + 1e-6 * std::min(input_product_scale, bias_scale)); + assert(input_product_scale >= 0); + assert(input_product_scale < output_scale); + *multiplier = input_product_scale / output_scale; +} + +void QuantizeMultiplierGreaterThanOne(double double_multiplier, int32_t *quantized_multiplier, + int *left_shift) +{ + assert(double_multiplier > 1.); + const double q = std::frexp(double_multiplier, left_shift); + int64_t q_fixed = static_cast(std::round(q * (1ll << 31))); + assert(q_fixed <= (1ll << 31)); + if (q_fixed == (1ll << 31)) + { + q_fixed /= 2; + ++*left_shift; + } + assert(*left_shift >= 0); + assert(q_fixed <= std::numeric_limits::max()); + *quantized_multiplier = static_cast(q_fixed); +} + +void CalculateActivationRangeFloat(ir::Activation activation, float *activation_min, + float *activation_max) +{ + if (activation == ir::Activation::RELU) + { + *activation_min = 0.f; + *activation_max = std::numeric_limits::max(); + } + else if (activation == ir::Activation::RELU6) + { + *activation_min = 0.f; + *activation_max = 6.f; + } + else if (activation == ir::Activation::RELU1) + { + *activation_min = -1.f; + *activation_max = 1.f; + } + else if (activation == ir::Activation::SIGMOID) + { + *activation_min = 0.f; + *activation_max = 1.f; + } + else if (activation == ir::Activation::NONE) + { + *activation_min = std::numeric_limits::lowest(); + *activation_max = std::numeric_limits::max(); + } + else + { + std::cout << "Unsupported fused activation function." << std::endl; + } +} + +void CalculateActivationRangeUint8(ir::Activation activation, const operand::Tensor *output, + int32_t *act_min, int32_t *act_max) +{ + const int32_t qmin = std::numeric_limits::min(); + const int32_t qmax = std::numeric_limits::max(); + const auto scale = output->scale(); + const auto zero_point = output->offset(); + auto quantize = [scale, zero_point](float f) { + return zero_point + static_cast(std::round(f / scale)); + }; + if (activation == ir::Activation::RELU) + { + *act_min = std::max(qmin, quantize(0.0)); + *act_max = qmax; + } + else if (activation == ir::Activation::RELU6) + { + *act_min = std::max(qmin, quantize(0.0)); + *act_max = std::min(qmax, quantize(6.0)); + } + else if (activation == ir::Activation::RELU1) + { + *act_min = std::max(qmin, quantize(-1.0)); + *act_max = std::min(qmax, quantize(1.0)); + } + else if (activation == ir::Activation::SIGMOID) + { + *act_min = std::max(qmin, quantize(0.0)); + *act_max = std::min(qmax, quantize(1.0)); + } + else if (activation == ir::Activation::NONE) + { + *act_min = qmin; + *act_max = qmax; + } + else + { + std::cout << "Unsupported fused activation function." << std::endl; + } +} + +bool HaveSameShapes(const operand::Tensor *input1, const operand::Tensor *input2) +{ + if (input1 == input2) + return true; + if (input2 == NULL || input2 == NULL) + return false; + + if (input1 == NULL) + { + return (getNumberOfDimensions(input2) == 0); + } + + if (getNumberOfDimensions(input1) != getNumberOfDimensions(input2)) + return false; + + for (uint32_t i = 0; i < getNumberOfDimensions(input1); i++) + if (input1->dimension(i) != input2->dimension(i)) + return false; + + return true; +} + +int32_t CalculateInputRadius(int input_integer_bits, int input_left_shift) +{ + const double max_input_rescaled = 1.0 * ((1 << input_integer_bits) - 1) * + (1ll << (31 - input_integer_bits)) / (1ll << input_left_shift); + // Tighten bound using floor. Suppose that we could use the exact value. + // After scaling the difference, the result would be at the maximum. Thus we + // must ensure that our value has lower magnitude. + return static_cast(std::floor(max_input_rescaled)); +} + +uint32_t sizeOfData(OperandType type, const std::vector &dimensions) +{ + uint32_t size = 4; + + switch (type) + { + case OperandType::FLOAT32: + case OperandType::INT32: + case OperandType::UINT32: + size = 4; + break; + case OperandType::BOOL8: + case OperandType::QUANT8_ASYMM: + case OperandType::QUANT8_SYMM: + size = 1; + break; + default: + throw std::runtime_error("Not supported operand type."); + break; + } + + for (auto d : dimensions) + { + size *= d; + } + + return size; +} + +nnfw::cker::PaddingType getPaddingType(ir::PaddingType ir_padding_type) +{ + switch (ir_padding_type) + { + case ir::PaddingType::EXPLICIT: + return nnfw::cker::PaddingType::kNone; + case ir::PaddingType::SAME: + return nnfw::cker::PaddingType::kSame; + case ir::PaddingType::VALID: + return nnfw::cker::PaddingType::kValid; + default: + throw std::runtime_error("Wrong padding type."); + break; + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/OperationUtils.h b/runtime/onert/backend/cpu/kernel/OperationUtils.h new file mode 100644 index 000000000..be9b24f36 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/OperationUtils.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NNFW_SUPPORT_NNAPI_OPERATION_UTILS_H__ +#define __NNFW_SUPPORT_NNAPI_OPERATION_UTILS_H__ + +#include "../operand/Tensor.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using OperandType = onert::ir::DataType; + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +union DataPtr { + uint8_t *u8; + int8_t *i8; + uint32_t *u32; + int32_t *i32; + bool *b; + float *f; + void *v; +}; + +uint32_t getNumberOfDimensions(const operand::Tensor *tensor); + +uint32_t getNumberOfElements(const operand::Tensor *tensor); + +uint32_t getSizeOfDimension(const operand::Tensor *tensor, uint32_t dimensionIdx); + +inline nnfw::cker::Shape convertToExtendedCkerShape(const operand::Tensor *tensor) +{ + assert(tensor); + std::vector raw_shape; + raw_shape.resize(4); + + uint32_t src = 4 - tensor->num_dimensions(); + for (uint32_t i = 0; i < 4; ++i) + { + if (i < src) + { + raw_shape[i] = 1; + } + else + { + raw_shape[i] = tensor->dimension(i - src); + } + } + + return nnfw::cker::GetShape(raw_shape); +} + +inline nnfw::cker::Shape convertTensorToCkerShape(const operand::Tensor *tensor) +{ + assert(tensor); + assert(tensor->layout() == ir::Layout::NHWC); + std::vector raw_shape; + raw_shape.resize(tensor->num_dimensions()); + for (uint32_t i = 0; i < tensor->num_dimensions(); ++i) + { + raw_shape[i] = tensor->dimension(i); + } + + return nnfw::cker::GetShape(raw_shape); +} + +inline nnfw::cker::FusedActivationFunctionType +convertActivationType(const ir::Activation activation) +{ + switch (activation) + { + case ir::Activation::NONE: + return nnfw::cker::FusedActivationFunctionType::kNone; + case ir::Activation::RELU: + return nnfw::cker::FusedActivationFunctionType::kRelu; + case ir::Activation::RELU1: + return nnfw::cker::FusedActivationFunctionType::kRelu1; + case ir::Activation::RELU6: + return nnfw::cker::FusedActivationFunctionType::kRelu6; + default: + throw std::runtime_error{"CPU backend: Cannot convert activation type"}; + } +} + +inline int32_t getAxis(uint32_t rank, int32_t axis, ir::Layout frontend_layout) +{ + auto ret = axis; + + if (axis < 0) + { + ret += rank; + } + + // NCHW -> NHWC + if (frontend_layout == ir::Layout::NCHW) + { + int32_t permutation[4] = {0, 3, 1, 2}; + ret = permutation[ret]; + } + + return ret; +} + +void QuantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift); + +void GetQuantizedConvolutionMultiplier(const operand::Tensor *inputDescr, + const operand::Tensor *filterDescr, + const operand::Tensor *biasDescr, + const operand::Tensor *outputDescr, double *multiplier); + +void QuantizeMultiplierGreaterThanOne(double double_multiplier, int32_t *quantized_multiplier, + int *left_shift); + +void CalculateActivationRangeFloat(ir::Activation activation, float *activation_min, + float *activation_max); + +void CalculateActivationRangeUint8(ir::Activation activation, const operand::Tensor *output, + int32_t *act_min, int32_t *act_max); + +bool HaveSameShapes(const operand::Tensor *input1, const operand::Tensor *input2); + +int32_t CalculateInputRadius(int input_integer_bits, int input_left_shift); + +uint32_t sizeOfData(OperandType type, const std::vector &dimensions); + +nnfw::cker::PaddingType getPaddingType(ir::PaddingType ir_padding_type); + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __NNFW_SUPPORT_NNAPI_OPERATION_UTILS_H__ diff --git a/runtime/onert/backend/cpu/kernel/PackLayer.cc b/runtime/onert/backend/cpu/kernel/PackLayer.cc new file mode 100644 index 000000000..01e69ff1d --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/PackLayer.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PackLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +PackLayer::PackLayer() : _inputs(), _output(nullptr), _axis(0) +{ + // DO NOTHING +} + +void PackLayer::packFloat32() +{ + uint32_t num_inputs = _inputs.size(); + nnfw::cker::PackParams op_params; + op_params.axis = _axis; + op_params.inputs_count = num_inputs; + + std::vector inputDimsPtr; + std::vector inputDims; + inputDimsPtr.reserve(num_inputs); + inputDims.reserve(num_inputs); + + for (uint32_t i = 0; i < num_inputs; i++) + { + inputDims.push_back(convertTensorToCkerShape(_inputs[i])); + inputDimsPtr.push_back(&inputDims[i]); + } + + std::vector inputFloatPtrs; + + for (const auto input : _inputs) + { + inputFloatPtrs.emplace_back(reinterpret_cast(input->buffer())); + } + + nnfw::cker::Pack(op_params, inputFloatPtrs.data(), convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void PackLayer::packQuant8() +{ + // cker quant8 pack is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void PackLayer::configure(const std::vector &inputs, int32_t axis, + operand::Tensor *output) +{ + assert(inputs.size() > 0); + assert(output != nullptr); + + _inputs = inputs; + _axis = axis; + _output = output; +} + +void PackLayer::run() +{ + if (_output->data_type() == OperandType::FLOAT32) + { + packFloat32(); + } + else if (_output->data_type() == OperandType::QUANT8_ASYMM) + { + packQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/PackLayer.h b/runtime/onert/backend/cpu/kernel/PackLayer.h new file mode 100644 index 000000000..5c87382be --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/PackLayer.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_PACKLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_PACKLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class PackLayer : public ::onert::exec::IFunction +{ +public: + PackLayer(); + +public: + void packFloat32(); + + void packQuant8(); + + void configure(const std::vector &inputs, int32_t axis, + operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + std::vector _inputs; + operand::Tensor *_output; + int32_t _axis; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_PACKLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/PadLayer.cc b/runtime/onert/backend/cpu/kernel/PadLayer.cc new file mode 100644 index 000000000..393856178 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/PadLayer.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PadLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +PadLayer::PadLayer() + : _input(nullptr), _output(nullptr), _padData(), _padRank(), _constantValueData() +{ + // DO NOTHING +} + +void PadLayer::padFloat32() +{ + nnfw::cker::Pad(_padData, _padRank, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer()), + _constantValueData.f); +} +void PadLayer::padQuant8() { throw std::runtime_error("Quantized Pad isn't supported NYI"); } + +void PadLayer::configure(const operand::Tensor *input, operand::Tensor *output, + const int32_t *padData, int32_t padRank, uint8_t *constantValueData) +{ + _input = input; + _output = output; + _padData = padData; + _padRank = padRank; + _constantValueData.u8 = constantValueData; +} + +void PadLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + padFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + padQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/PadLayer.h b/runtime/onert/backend/cpu/kernel/PadLayer.h new file mode 100644 index 000000000..fc14ae033 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/PadLayer.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_PADLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_PADLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +// Note, this is pad with mode=`CONSTANT`: it doesn't support `REFLECT` and +// `SYMMETRIC` +class PadLayer : public ::onert::exec::IFunction +{ +public: + PadLayer(); + +public: + void padFloat32(); + + void padQuant8(); + + void configure(const operand::Tensor *input, operand::Tensor *output, const int32_t *padData, + int32_t padRank, uint8_t *constantValueData = nullptr); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; + + const int32_t *_padData; + int32_t _padRank; + DataPtr _constantValueData; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_PADLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/PermuteLayer.cc b/runtime/onert/backend/cpu/kernel/PermuteLayer.cc new file mode 100644 index 000000000..a3e828255 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/PermuteLayer.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PermuteLayer.h" + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +using Type = ir::operation::Permute::Type; + +void PermuteLayer::configure(std::shared_ptr input, + std::shared_ptr output, + const ir::Shape &output_shape, Type type, ir::DataType dataType) +{ + _input = input; + _output = output; + _output_shape = output_shape; + _type = type; + _dataType = dataType; +} + +void PermuteLayer::run() +{ + using ir::DataType; + switch (_dataType) + { + case DataType::FLOAT32: + runTempl(); + break; + case DataType::INT32: + runTempl(); + break; + case DataType::UINT32: + runTempl(); + break; + case DataType::BOOL8: + case DataType::QUANT8_ASYMM: + runTempl(); + break; + case DataType::QUANT8_SYMM: + runTempl(); + break; + default: + throw std::runtime_error("NYI"); + break; + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/PermuteLayer.h b/runtime/onert/backend/cpu/kernel/PermuteLayer.h new file mode 100644 index 000000000..52b96caba --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/PermuteLayer.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_PERMUTE_LAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_PERMUTE_LAYER_H__ + +#include "OperationUtils.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class PermuteLayer : public ::onert::exec::IFunction +{ +public: + PermuteLayer() = default; + +public: + void configure(std::shared_ptr input, std::shared_ptr output, + const ir::Shape &output_shape, ir::operation::Permute::Type type, + ir::DataType dataType); + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + template void runTempl() + { + auto rank = _output_shape.rank(); + auto fn = [&](ITensor &in_tensor) { + _output->access([&](ITensor &out_tensor) { + auto input_buffer = in_tensor.buffer(); + auto input_size = in_tensor.total_size(); + auto output_buffer = out_tensor.buffer(); + if (_type == ir::operation::Permute::Type::COPY) + { + assert(in_tensor.layout() == out_tensor.layout()); + if (!in_tensor.has_padding() && !out_tensor.has_padding()) + { + assert(input_size == out_tensor.total_size()); + memcpy(output_buffer, input_buffer, input_size); + return; + } + } + switch (rank) + { + case 0: + case 1: + { + const int32_t copy_len = _output_shape.dim(0); + + memcpy(output_buffer, input_buffer, copy_len); + break; + } + case 2: + { + const int32_t copy_len = _output_shape.dim(1); + + for (auto i = 0; i < _output_shape.dim(0); ++i) + { + ir::Coordinates coords{i, 0}; + memcpy(output_buffer + out_tensor.calcOffset(coords), + input_buffer + in_tensor.calcOffset(coords), copy_len * sizeof(T)); + } + break; + } + case 3: + { + const int32_t copy_len = _output_shape.dim(2); + + for (auto i = 0; i < _output_shape.dim(0); ++i) + { + for (auto j = 0; j < _output_shape.dim(1); ++j) + { + ir::Coordinates coords{i, j, 0}; + memcpy(output_buffer + out_tensor.calcOffset(coords), + input_buffer + in_tensor.calcOffset(coords), copy_len * sizeof(T)); + } + } + break; + } + case 4: + { + // TODO Unify permute type and remove switch case + switch (_type) + { + case ir::operation::Permute::Type::NHWC_TO_NCHW: + { + for (auto n = 0; n < _output_shape.dim(0); ++n) + { + for (auto c = 0; c < _output_shape.dim(1); ++c) + { + for (auto h = 0; h < _output_shape.dim(2); ++h) + { + for (auto w = 0; w < _output_shape.dim(3); ++w) + { + const ir::Coordinates in_coords{n, h, w, c}; + const auto out_coords = + convertCoordinates(in_coords, in_tensor.layout(), out_tensor.layout()); + const auto value = + *reinterpret_cast(input_buffer + in_tensor.calcOffset(in_coords)); + *reinterpret_cast(output_buffer + out_tensor.calcOffset(out_coords)) = + value; + } + } + } + } + break; + } + case ir::operation::Permute::Type::NCHW_TO_NHWC: + { + for (auto n = 0; n < _output_shape.dim(0); ++n) + { + for (auto h = 0; h < _output_shape.dim(1); ++h) + { + for (auto w = 0; w < _output_shape.dim(2); ++w) + { + for (auto c = 0; c < _output_shape.dim(3); ++c) + { + const ir::Coordinates in_coords{n, c, h, w}; + const auto out_coords = + convertCoordinates(in_coords, in_tensor.layout(), out_tensor.layout()); + const auto value = + *reinterpret_cast(input_buffer + in_tensor.calcOffset(in_coords)); + *reinterpret_cast(output_buffer + out_tensor.calcOffset(out_coords)) = + value; + } + } + } + } + break; + } + case ir::operation::Permute::Type::COPY: + { + const int32_t copy_len = _output_shape.dim(3); + + for (auto i = 0; i < _output_shape.dim(0); ++i) + { + for (auto j = 0; j < _output_shape.dim(1); ++j) + { + for (auto k = 0; k < _output_shape.dim(2); ++k) + { + ir::Coordinates coords{i, j, k, 0}; + memcpy(output_buffer + out_tensor.calcOffset(coords), + input_buffer + in_tensor.calcOffset(coords), copy_len * sizeof(T)); + } + } + } + break; + } + default: + throw std::runtime_error("NYI"); + break; + } + break; + } + default: + throw std::runtime_error("NYI"); + break; + } + }); + }; + _input->access(fn); + } + +private: + std::shared_ptr _input{nullptr}; + std::shared_ptr _output{nullptr}; + ir::Shape _output_shape{}; + ir::operation::Permute::Type _type{ir::operation::Permute::Type::COPY}; + ir::DataType _dataType{ir::DataType::FLOAT32}; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_PERMUTE_LAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/ReduceLayer.cc b/runtime/onert/backend/cpu/kernel/ReduceLayer.cc new file mode 100644 index 000000000..78c82f1cc --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ReduceLayer.cc @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ReduceLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +namespace +{ + +template +void evalLogic(const operand::Tensor *input, operand::Tensor *output, const std::vector &axes, + bool keep_dims, T init_value, nnfw::cker::Reduce &reduce_kernel, + T reducer(const T current, const T in)) +{ + reduce_kernel.prepare(input->num_dimensions(), axes.size()); + bool result = reduce_kernel.ReduceGeneric( + convertTensorToCkerShape(input), reinterpret_cast(input->buffer()), + convertTensorToCkerShape(output), reinterpret_cast(output->buffer()), axes, keep_dims, + init_value, reducer); + + if (!result) + { + throw std::runtime_error{"Reduce: Fail to run"}; + } +} + +template +void evalType(const operand::Tensor *input, operand::Tensor *output, const std::vector &axes, + bool keep_dims, nnfw::cker::Reduce &reduce_kernel, ReduceType reduce_type) +{ + switch (reduce_type) + { + case ReduceType::kSum: + return evalLogic(input, output, axes, keep_dims, static_cast(0), reduce_kernel, + [](const T current, const T in) -> T { return in + current; }); + break; + case ReduceType::kProd: + return evalLogic(input, output, axes, keep_dims, static_cast(1), reduce_kernel, + [](const T current, const T in) -> T { return in * current; }); + break; + case ReduceType::kMax: + return evalLogic( + input, output, axes, keep_dims, std::numeric_limits::lowest(), reduce_kernel, + [](const T current, const T in) -> T { return (in > current) ? in : current; }); + break; + case ReduceType::kMin: + return evalLogic( + input, output, axes, keep_dims, std::numeric_limits::max(), reduce_kernel, + [](const T current, const T in) -> T { return (in < current) ? in : current; }); + break; + default: + throw std::runtime_error{"Reduce: Unsupported reduce type"}; + } +} + +template +void evalGeneric(const operand::Tensor *input, operand::Tensor *output, + const std::vector &axes, bool keep_dims, nnfw::cker::Reduce &reduce_kernel) +{ + switch (input->data_type()) + { + case OperandType::FLOAT32: + return evalType(input, output, axes, keep_dims, reduce_kernel, reduce_type); + case OperandType::INT32: + return evalType(input, output, axes, keep_dims, reduce_kernel, reduce_type); + default: + throw std::runtime_error{"Reduce(generic): Unsupported input type"}; + } +} +} // namespace + +ReduceLayer::ReduceLayer() + : _input(nullptr), _output(nullptr), _reduceType(ReduceType::kAny), _axes(), _keep_dims(false), + _reduce_kernel(new nnfw::cker::Reduce()) +{ + // DO NOTHING +} + +ReduceLayer::~ReduceLayer() = default; + +void ReduceLayer::configure(const operand::Tensor *input, operand::Tensor *output, + ReduceType reduceType, const std::vector &axes, bool keep_dims) +{ + _input = input; + _output = output; + _reduceType = reduceType; + _axes = axes; + _keep_dims = keep_dims; +} + +void ReduceLayer::run() +{ + switch (_reduceType) + { + case ReduceType::kSum: + evalGeneric(_input, _output, _axes, _keep_dims, *_reduce_kernel); + break; + case ReduceType::kMax: + evalGeneric(_input, _output, _axes, _keep_dims, *_reduce_kernel); + break; + case ReduceType::kMin: + evalGeneric(_input, _output, _axes, _keep_dims, *_reduce_kernel); + break; + default: + throw std::runtime_error{"ReduceSum: Unsupported reduce type"}; + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/ReduceLayer.h b/runtime/onert/backend/cpu/kernel/ReduceLayer.h new file mode 100644 index 000000000..9310882c9 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ReduceLayer.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_REDUCESUMLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_REDUCESUMLAYER_H__ + +#include "../operand/Tensor.h" + +#include +#include + +namespace nnfw +{ +namespace cker +{ +class Reduce; +} +} // namespace nnfw + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +enum class ReduceType +{ + kSum, + kProd, + kMax, + kMin, + kAny, +}; + +class ReduceLayer : public ::onert::exec::IFunction +{ +public: + ReduceLayer(); + ~ReduceLayer(); + +public: + void configure(const operand::Tensor *input, operand::Tensor *output, ReduceType reduceType, + const std::vector &axes, bool keep_dims); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; + ReduceType _reduceType; + std::vector _axes; + bool _keep_dims; + + std::unique_ptr _reduce_kernel; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_REDUCESUMLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/ReshapeLayer.cc b/runtime/onert/backend/cpu/kernel/ReshapeLayer.cc new file mode 100644 index 000000000..b8bd5a45c --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ReshapeLayer.cc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ReshapeLayer.h" + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +ReshapeLayer::ReshapeLayer() : _input(nullptr), _shape(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +void ReshapeLayer::reshapeGeneric() +{ + // TODO use _shape to calculate shape of output when _shape is not nullptr && not constant + + size_t count = _input->total_size(); + memcpy(_output->buffer(), _input->buffer(), count); +} + +void ReshapeLayer::configure(const operand::Tensor *input, const operand::Tensor *shape, + operand::Tensor *output) +{ + _input = input; + /* note : shape is optional. If not provided from model, _shape is nullptr. */ + _shape = shape; + _output = output; +} + +void ReshapeLayer::run() { reshapeGeneric(); } + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/ReshapeLayer.h b/runtime/onert/backend/cpu/kernel/ReshapeLayer.h new file mode 100644 index 000000000..7a95b6d35 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ReshapeLayer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_RESHAPELAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_RESHAPELAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class ReshapeLayer : public ::onert::exec::IFunction +{ +public: + ReshapeLayer(); + +public: + void reshapeGeneric(); + + void configure(const operand::Tensor *input, const operand::Tensor *shape, + operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + const operand::Tensor *_shape; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_RESHAPELAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/RsqrtLayer.cc b/runtime/onert/backend/cpu/kernel/RsqrtLayer.cc new file mode 100644 index 000000000..d94ff8751 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/RsqrtLayer.cc @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "RsqrtLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ +RsqrtLayer::RsqrtLayer() : _input(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +void RsqrtLayer::rsqrtFloat32() +{ + nnfw::cker::Rsqrt( + convertTensorToCkerShape(_input), reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void RsqrtLayer::rsqrtQuant8() { throw std::runtime_error{"NYI : QASYMM8 not supported"}; } + +void RsqrtLayer::configure(const operand::Tensor *input, operand::Tensor *output) +{ + _input = input; + _output = output; +} + +void RsqrtLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + rsqrtFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + rsqrtQuant8(); + } + else + { + throw std::runtime_error{"Rsqrt: unsupported data type"}; + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/RsqrtLayer.h b/runtime/onert/backend/cpu/kernel/RsqrtLayer.h new file mode 100644 index 000000000..188d53160 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/RsqrtLayer.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in riting, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_RSQRTLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_RSQRTLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ +class RsqrtLayer : public ::onert::exec::IFunction +{ +public: + RsqrtLayer(); + + void configure(const operand::Tensor *input, operand::Tensor *output); + + void run(); + void runSync() + { + // this rsqrttract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + void rsqrtFloat32(); + void rsqrtQuant8(); + const operand::Tensor *_input; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_RSQRTLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/ShapeLayer.cc b/runtime/onert/backend/cpu/kernel/ShapeLayer.cc new file mode 100644 index 000000000..1cd183331 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ShapeLayer.cc @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ShapeLayer.h" + +#include "OperationUtils.h" + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +ShapeLayer::ShapeLayer() : _input(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +template void GetRawShape(const operand::Tensor *input, T *output_data) +{ + for (uint32_t i = 0; i < input->num_dimensions(); ++i) + { + output_data[i] = static_cast(input->dimension(i)); + } +} + +void ShapeLayer::shape() +{ + if (_output->data_type() == OperandType::UINT32) + { + GetRawShape(_input, reinterpret_cast(_output->buffer())); + } + else if (_output->data_type() == OperandType::INT32) + { + GetRawShape(_input, reinterpret_cast(_output->buffer())); + } + else + { + throw std::runtime_error{"NYI : not supported output type for ShapeLayer"}; + } +} + +void ShapeLayer::configure(const operand::Tensor *input, operand::Tensor *output) +{ + _input = input; + _output = output; +} + +void ShapeLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32 || + _input->data_type() == OperandType::QUANT8_ASYMM) + { + shape(); + } + else + { + throw std::runtime_error{"NYI : not supported input type for ShapeLayer"}; + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/ShapeLayer.h b/runtime/onert/backend/cpu/kernel/ShapeLayer.h new file mode 100644 index 000000000..cb4acedb8 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/ShapeLayer.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in riting, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_SHAPELAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_SHAPELAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class ShapeLayer : public ::onert::exec::IFunction +{ +public: + ShapeLayer(); + +public: + void shape(); + + void configure(const operand::Tensor *input, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_SHAPELAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/SinLayer.cc b/runtime/onert/backend/cpu/kernel/SinLayer.cc new file mode 100644 index 000000000..db8186ac6 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SinLayer.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SinLayer.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ +SinLayer::SinLayer() : _input(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +void SinLayer::sinFloat32() +{ + nnfw::cker::Sin(convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void SinLayer::sinQuant8() { throw std::runtime_error{"NYI"}; } + +void SinLayer::configure(const operand::Tensor *input, operand::Tensor *output) +{ + _input = input; + _output = output; +} + +void SinLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + sinFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + sinQuant8(); + } + else + { + throw std::runtime_error{"Sin: unsupported data type"}; + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/SinLayer.h b/runtime/onert/backend/cpu/kernel/SinLayer.h new file mode 100644 index 000000000..7898cf050 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SinLayer.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in riting, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_SINLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_SINLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ +class SinLayer : public ::onert::exec::IFunction +{ +public: + SinLayer(); + + void configure(const operand::Tensor *input, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + void sinFloat32(); + void sinQuant8(); + + const operand::Tensor *_input; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_SINLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/SliceLayer.cc b/runtime/onert/backend/cpu/kernel/SliceLayer.cc new file mode 100644 index 000000000..1ade5fb44 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SliceLayer.cc @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SliceLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +SliceLayer::SliceLayer() : _input(nullptr), _begin(nullptr), _size(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +template +void SliceLayer::GetBeginAndSizeVectors(int dimensions, const operand::Tensor *begin, + const operand::Tensor *size, std::vector *begins, + std::vector *sizes) +{ + for (int idx = dimensions - 1; idx >= 0; --idx) + { + begins->push_back(reinterpret_cast(begin->buffer())[idx]); + sizes->push_back(reinterpret_cast(size->buffer())[idx]); + } +} + +void SliceLayer::sliceFloat32() +{ + const int kMaxDim = nnfw::cker::Shape::kMaxSmallSize; + + std::vector begins; + std::vector sizes; + begins.reserve(kMaxDim); + sizes.reserve(kMaxDim); + + GetBeginAndSizeVectors(_input->num_dimensions(), _begin, _size, &begins, &sizes); + + // begins : 0-based, sizes : 1-based + for (int i = _input->num_dimensions(); i < kMaxDim; ++i) + { + begins.push_back(0); + sizes.push_back(1); + } + + nnfw::cker::SliceParams op_params; + op_params.begin_count = 4; + op_params.size_count = 4; + for (int i = 0; i < 4; ++i) + { + op_params.begin[i] = begins[3 - i]; + op_params.size[i] = sizes[3 - i]; + } + + nnfw::cker::Slice(op_params, convertToExtendedCkerShape(_input), + reinterpret_cast(_input->buffer()), + reinterpret_cast(_output->buffer())); +} + +void SliceLayer::sliceQuant8() +{ + // cker quant8 slice is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void SliceLayer::configure(const operand::Tensor *input, const operand::Tensor *begin, + const operand::Tensor *size, operand::Tensor *output) +{ + _input = input; + _output = output; + _begin = begin; + _size = size; +} + +void SliceLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + sliceFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + sliceQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/SliceLayer.h b/runtime/onert/backend/cpu/kernel/SliceLayer.h new file mode 100644 index 000000000..bb18c890c --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SliceLayer.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_SLICELAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_SLICELAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class SliceLayer : public ::onert::exec::IFunction +{ +public: + SliceLayer(); + +public: + void configure(const operand::Tensor *input, const operand::Tensor *begin, + const operand::Tensor *size, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + void sliceFloat32(); + void sliceQuant8(); + + template + void GetBeginAndSizeVectors(int dimensions, const operand::Tensor *begin, + const operand::Tensor *size, std::vector *begins, + std::vector *sizes); + +private: + const operand::Tensor *_input; + const operand::Tensor *_begin; + const operand::Tensor *_size; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_SLICELAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/SoftMaxLayer.cc b/runtime/onert/backend/cpu/kernel/SoftMaxLayer.cc new file mode 100644 index 000000000..7a1ba48aa --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SoftMaxLayer.cc @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SoftMaxLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +SoftMaxLayer::SoftMaxLayer() : _input(nullptr), _output(nullptr), _beta(0.0) +{ + // DO NOTHING +} + +// Performs softmax along the input of size (input_size * batch_size). +void Softmax(const float *in, const int input_size, const int batch_size, const float beta, + float *out) +{ + assert(input_size > 0); + + // For each batch + for (int b = 0; b < batch_size; b++) + { + // Find the max coeff. + float max_coeff = in[0]; + for (int i = 1; i < input_size; i++) + { + if (in[i] > max_coeff) + max_coeff = in[i]; + } + + // Compute the normalized sum of exps. + float exp_sum = 0.0; + for (int i = 0; i < input_size; i++) + { + out[i] = std::exp((in[i] - max_coeff) * beta); + exp_sum += out[i]; + } + + // Divide by the sum of exps. + float reciprocal_sum_exp = 1.f / exp_sum; + for (int i = 0; i < input_size; i++) + { + out[i] *= reciprocal_sum_exp; + } + + // Advance in and out pointers for the next batch. + in += input_size; + out += input_size; + } +} + +void SoftMaxLayer::softmaxFloat32() +{ + if (getNumberOfDimensions(_input) == 2) + { + uint32_t batch_size = getSizeOfDimension(_input, 0); + if (batch_size == 0) + throw std::runtime_error("batch_size should not be 0"); + + uint32_t input_size = getNumberOfElements(_input) / batch_size; + Softmax(reinterpret_cast(_input->buffer()), input_size, batch_size, _beta, + reinterpret_cast(_output->buffer())); + } + else if (getNumberOfDimensions(_input) == 4) + { + nnfw::cker::SoftmaxParams op_params; + op_params.beta = _beta; + nnfw::cker::Softmax(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); + } + else + { + throw std::runtime_error{"only 2D and 4D tensors supported"}; + } +} + +void SoftMaxLayer::softmaxQuant8() +{ + nnfw::cker::Shape descrIn4D(4); + + if (getNumberOfDimensions(_input) == 2) + { + auto batch_size = getSizeOfDimension(_input, 0); + if (batch_size == 0) + throw std::runtime_error("batch_size should not be 0"); + + auto input_size = getNumberOfElements(_input) / batch_size; + descrIn4D.SetDim(0, batch_size); + descrIn4D.SetDim(1, 1); + descrIn4D.SetDim(2, 1); + descrIn4D.SetDim(3, input_size); + } + else if (getNumberOfDimensions(_input) == 4) + { + descrIn4D.SetDim(0, _input->dimension(0)); + descrIn4D.SetDim(1, _input->dimension(1)); + descrIn4D.SetDim(2, _input->dimension(2)); + descrIn4D.SetDim(3, _input->dimension(3)); + } + else + { + throw std::runtime_error{"only 2D and 4D tensors supported"}; + } + if (_output->offset() != 0 || _output->scale() != 1.f / 256) + { + throw std::runtime_error{"incorrect scale / offset for output"}; + } + static const int32_t kScaledDiffIntegerBits = 5; + const double input_beta_real_multiplier = std::min( + 1.0 * _beta * _input->scale() * (1 << (31 - kScaledDiffIntegerBits)), (1ll << 31) - 1.0); + int32_t input_multiplier = 0; + int32_t input_left_shift = 0; + QuantizeMultiplierGreaterThanOne(input_beta_real_multiplier, &input_multiplier, + &input_left_shift); + float diff_min = -1.0f * CalculateInputRadius(kScaledDiffIntegerBits, input_left_shift); + + nnfw::cker::SoftmaxParams op_params; + op_params.input_multiplier = input_multiplier; + op_params.input_left_shift = input_left_shift; + op_params.diff_min = diff_min; + nnfw::cker::Softmax(op_params, descrIn4D, reinterpret_cast(_input->buffer()), + descrIn4D, reinterpret_cast(_output->buffer())); +} + +void SoftMaxLayer::configure(const operand::Tensor *input, const float beta, + operand::Tensor *output) +{ + _input = input; + _output = output; + _beta = beta; +} + +void SoftMaxLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + softmaxFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + softmaxQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/SoftMaxLayer.h b/runtime/onert/backend/cpu/kernel/SoftMaxLayer.h new file mode 100644 index 000000000..bb29b4fda --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SoftMaxLayer.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_SOFTMAXLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_SOFTMAXLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class SoftMaxLayer : public ::onert::exec::IFunction +{ +public: + SoftMaxLayer(); + +public: + void softmaxFloat32(); + + void softmaxQuant8(); + + void configure(const operand::Tensor *input, const float beta, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; + + float _beta; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_SOFTMAXLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/SplitLayer.cc b/runtime/onert/backend/cpu/kernel/SplitLayer.cc new file mode 100644 index 000000000..e4c5ef3a0 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SplitLayer.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SplitLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +SplitLayer::SplitLayer() : _input(nullptr), _num_splits(0), _axis(0), _outputs() +{ + // DO NOTHING +} + +void SplitLayer::splitFloat32() +{ + nnfw::cker::SplitParams op_params; + op_params.axis = _axis; + op_params.num_split = _num_splits; + + std::vector outputDimsPtr; + std::vector outputDims; + outputDimsPtr.reserve(_num_splits); + outputDims.reserve(_num_splits); + + for (uint32_t i = 0; i < _num_splits; i++) + { + outputDims.push_back(convertTensorToCkerShape(_outputs[i])); + outputDimsPtr.push_back(&outputDims[i]); + } + + std::vector outputFloatPtrs; + + for (const auto output : _outputs) + { + outputFloatPtrs.emplace_back(reinterpret_cast(output->buffer())); + } + + nnfw::cker::Split(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_outputs[0]), outputFloatPtrs.data()); +} + +void SplitLayer::splitQuant8() { throw std::runtime_error{"Split: NYI quant8 type"}; } + +void SplitLayer::configure(const operand::Tensor *input, uint16_t num_splits, int16_t axis, + std::vector &outputs) +{ + assert(input != nullptr); + + _num_splits = num_splits; + _input = input; + _axis = axis; + _outputs = outputs; +} + +void SplitLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + splitFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + splitQuant8(); + } + else + { + throw std::runtime_error{"Split: Unsupported input type"}; + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/SplitLayer.h b/runtime/onert/backend/cpu/kernel/SplitLayer.h new file mode 100644 index 000000000..9f236f0af --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SplitLayer.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_SPLITLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_SPLITLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class SplitLayer : public ::onert::exec::IFunction +{ +public: + SplitLayer(); + +public: + void splitFloat32(); + + void splitQuant8(); + + void configure(const operand::Tensor *input, uint16_t num_splits, int16_t axis, + std::vector &outputs); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + uint16_t _num_splits; + int16_t _axis; + std::vector _outputs; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_SPLITLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/StridedSliceLayer.cc b/runtime/onert/backend/cpu/kernel/StridedSliceLayer.cc new file mode 100644 index 000000000..22315c7c6 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/StridedSliceLayer.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "StridedSliceLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +StridedSliceLayer::StridedSliceLayer() + : _input(nullptr), _begin(nullptr), _end(nullptr), _strides(nullptr), _output(nullptr), + _begin_mask(0), _ellipsis_mask(0), _end_mask(0), _new_axis_mask(0), _shrink_axis_mask(0), + _rank(0) +{ +} + +void StridedSliceLayer::stridedSliceFloat32() +{ + auto op_params = nnfw::cker::buildStridedSliceParams( + reinterpret_cast(_begin->buffer()), reinterpret_cast(_end->buffer()), + reinterpret_cast(_strides->buffer()), _begin_mask, _end_mask, _shrink_axis_mask, + _rank); + + nnfw::cker::checkOutputSize(op_params, convertTensorToCkerShape(_input), + convertTensorToCkerShape(_output), _rank); + + nnfw::cker::StridedSlice(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), + reinterpret_cast(_output->buffer())); +} + +void StridedSliceLayer::stridedSliceQuant8() +{ + // cker quant8 stridedSlice is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void StridedSliceLayer::configure(const operand::Tensor *input, const operand::Tensor *begin, + const operand::Tensor *end, const operand::Tensor *strides, + operand::Tensor *output, const int32_t begin_mask, + const int32_t end_mask, const int32_t shrink_axis_mask, + const int32_t rank) +{ + _input = input; + _begin = begin; + _end = end; + _strides = strides; + _output = output; + + _rank = rank; + _begin_mask = begin_mask; + _ellipsis_mask = 0; + _end_mask = end_mask; + _new_axis_mask = 0; + _shrink_axis_mask = shrink_axis_mask; +} + +void StridedSliceLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + stridedSliceFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + stridedSliceQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/StridedSliceLayer.h b/runtime/onert/backend/cpu/kernel/StridedSliceLayer.h new file mode 100644 index 000000000..7888eff3c --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/StridedSliceLayer.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_STRIDEDSLICELAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_STRIDEDSLICELAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class StridedSliceLayer : public ::onert::exec::IFunction +{ +public: + StridedSliceLayer(); + +public: + void configure(const operand::Tensor *input, const operand::Tensor *begin, + const operand::Tensor *end, const operand::Tensor *strides, + operand::Tensor *output, const int32_t begin_mask, const int32_t end_mask, + const int32_t shrink_axis_mask, const int32_t rank); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + void stridedSliceFloat32(); + void stridedSliceQuant8(); + +private: + const operand::Tensor *_input; + const operand::Tensor *_begin; + const operand::Tensor *_end; + const operand::Tensor *_strides; + operand::Tensor *_output; + + int32_t _begin_mask; + int32_t _ellipsis_mask; + int32_t _end_mask; + int32_t _new_axis_mask; + int32_t _shrink_axis_mask; + + int32_t _rank; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_STRIDEDSLICELAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/SubLayer.cc b/runtime/onert/backend/cpu/kernel/SubLayer.cc new file mode 100644 index 000000000..15aa43835 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SubLayer.cc @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SubLayer.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +void SubLayer::subFloat32() +{ + float output_activation_min, output_activation_max; + CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max); + nnfw::cker::BinaryArithmeticOpParam op_params; + op_params.type = nnfw::cker::BinaryArithmeticOpType::SUB; + op_params.float_activation_max = output_activation_max; + op_params.float_activation_min = output_activation_min; + + if (!HaveSameShapes(_lhs, _rhs)) + { + nnfw::cker::BroadcastBinaryArithmeticOpSlow( + op_params, convertToExtendedCkerShape(_lhs), + reinterpret_cast(_lhs->buffer()), convertToExtendedCkerShape(_rhs), + reinterpret_cast(_rhs->buffer()), convertToExtendedCkerShape(_output), + reinterpret_cast(_output->buffer())); + return; + } + + nnfw::cker::BinaryArithmeticOp( + op_params, convertTensorToCkerShape(_lhs), reinterpret_cast(_lhs->buffer()), + convertTensorToCkerShape(_rhs), reinterpret_cast(_rhs->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void SubLayer::subQuant8() +{ + int32_t output_activation_min, output_activation_max; + CalculateActivationRangeUint8(_activation, _output, &output_activation_min, + &output_activation_max); + // nnfw::cker::SubParam op_params; + // op_params.quantized_activation_max = output_activation_max; + // op_params.quantized_activation_min = output_activation_min; + + // cker quant8 sub is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void SubLayer::configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const ir::Activation activation, operand::Tensor *output) +{ + _lhs = lhs; + _rhs = rhs; + _activation = activation; + _output = output; +} + +void SubLayer::run() +{ + if (_output->data_type() == OperandType::FLOAT32) + { + subFloat32(); + } + else if (_output->data_type() == OperandType::QUANT8_ASYMM) + { + subQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/SubLayer.h b/runtime/onert/backend/cpu/kernel/SubLayer.h new file mode 100644 index 000000000..48fa97669 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/SubLayer.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_SUBLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_SUBLAYER_H__ + +#include "../operand/Tensor.h" +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class SubLayer : public ::onert::exec::IFunction +{ +public: + SubLayer() : _lhs(nullptr), _rhs(nullptr), _output(nullptr) + { + // DO NOTHING + } + +public: + void subFloat32(); + + void subQuant8(); + + void configure(const operand::Tensor *lhs, const operand::Tensor *rhs, + const ir::Activation activation, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_lhs; + const operand::Tensor *_rhs; + operand::Tensor *_output; + + ir::Activation _activation{ir::Activation::NONE}; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_SUBLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/TanhLayer.cc b/runtime/onert/backend/cpu/kernel/TanhLayer.cc new file mode 100644 index 000000000..6a9274f7a --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/TanhLayer.cc @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TanhLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +TanhLayer::TanhLayer() : _input(nullptr), _output(nullptr) +{ + // DO NOTHING +} + +void TanhLayer::tanhFloat32() +{ + nnfw::cker::Tanh(convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void TanhLayer::tanhQuant8() +{ + // cker quant8 tanh is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void TanhLayer::configure(const operand::Tensor *input, operand::Tensor *output) +{ + _input = input; + _output = output; +} + +void TanhLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + tanhFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + tanhQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/TanhLayer.h b/runtime/onert/backend/cpu/kernel/TanhLayer.h new file mode 100644 index 000000000..8fb621cdb --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/TanhLayer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_TANHLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_TANHLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class TanhLayer : public ::onert::exec::IFunction +{ +public: + TanhLayer(); + +public: + void tanhFloat32(); + + void tanhQuant8(); + + void configure(const operand::Tensor *input, operand::Tensor *output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_TANHLAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/TransposeLayer.cc b/runtime/onert/backend/cpu/kernel/TransposeLayer.cc new file mode 100644 index 000000000..31b1dd12d --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/TransposeLayer.cc @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TransposeLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +TransposeLayer::TransposeLayer() : _input(nullptr), _output(nullptr), _perm(), _rank(0) +{ + // DO NOTHING +} + +void TransposeLayer::transposeFloat32() +{ + nnfw::cker::TransposeParams param; + param.perm_count = _rank; + for (int32_t i = 0; i < _rank; i++) + { + param.perm[i] = _perm[i]; + } + + nnfw::cker::Transpose( + param, convertTensorToCkerShape(_input), reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_output), reinterpret_cast(_output->buffer())); +} + +void TransposeLayer::transposeQuant8() +{ + // cker quant8 tanh is not implemented yet + throw std::runtime_error{"NYI"}; +} + +void TransposeLayer::configure(const operand::Tensor *input, operand::Tensor *output, + const std::vector &perm, int32_t rank) +{ + _input = input; + _rank = rank; + _perm = perm; + _output = output; +} + +void TransposeLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + transposeFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + transposeQuant8(); + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/TransposeLayer.h b/runtime/onert/backend/cpu/kernel/TransposeLayer.h new file mode 100644 index 000000000..ffe7c2ae5 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/TransposeLayer.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_TRANSPOSELAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_TRANSPOSELAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class TransposeLayer : public ::onert::exec::IFunction +{ +public: + TransposeLayer(); + +public: + void transposeFloat32(); + + void transposeQuant8(); + + void configure(const operand::Tensor *input, operand::Tensor *output, + const std::vector &perm, int32_t rank); + + void run(); + void runSync() { run(); } + +private: + const operand::Tensor *_input; + operand::Tensor *_output; + std::vector _perm; + int32_t _rank; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_TRANSPOSELAYER_H__ diff --git a/runtime/onert/backend/cpu/kernel/UnpackLayer.cc b/runtime/onert/backend/cpu/kernel/UnpackLayer.cc new file mode 100644 index 000000000..fe07e3e19 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/UnpackLayer.cc @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "UnpackLayer.h" + +#include "OperationUtils.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +UnpackLayer::UnpackLayer() : _input(nullptr), _outputs(), _axis(0), _num_output(0) +{ + // DO NOTHING +} + +void UnpackLayer::unpackFloat32() +{ + nnfw::cker::UnpackParams op_params; + op_params.axis = _axis; + op_params.num_split = _num_output; + + std::vector outputDimsPtr; + std::vector outputDims; + outputDimsPtr.reserve(_num_output); + outputDims.reserve(_num_output); + + for (int32_t i = 0; i < _num_output; i++) + { + outputDims.push_back(convertTensorToCkerShape(_outputs[i])); + outputDimsPtr.push_back(&outputDims[i]); + } + + std::vector outputFloatPtrs; + + for (const auto output : _outputs) + { + outputFloatPtrs.emplace_back(reinterpret_cast(output->buffer())); + } + + nnfw::cker::Unpack(op_params, convertTensorToCkerShape(_input), + reinterpret_cast(_input->buffer()), + convertTensorToCkerShape(_outputs[0]), outputFloatPtrs.data()); +} + +void UnpackLayer::unpackQuant8() +{ + // cker quant8 pack is not implemented yet + throw std::runtime_error{"Unpack: NYI quant8 type"}; +} + +void UnpackLayer::configure(const operand::Tensor *input, uint32_t axis, int32_t num, + std::vector &outputs) +{ + assert(input != nullptr); + assert(outputs.size() > 0); + assert(outputs.size() == (size_t)num); + + _input = input; + _axis = axis; + _num_output = num; + _outputs = outputs; +} + +void UnpackLayer::run() +{ + if (_input->data_type() == OperandType::FLOAT32) + { + unpackFloat32(); + } + else if (_input->data_type() == OperandType::QUANT8_ASYMM) + { + unpackQuant8(); + } + else + { + throw std::runtime_error{"Unpack: Unsupported input type"}; + } +} + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/kernel/UnpackLayer.h b/runtime/onert/backend/cpu/kernel/UnpackLayer.h new file mode 100644 index 000000000..23d064db2 --- /dev/null +++ b/runtime/onert/backend/cpu/kernel/UnpackLayer.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_KERNEL_UNPACKLAYER_H__ +#define __ONERT_BACKEND_CPU_KERNEL_UNPACKLAYER_H__ + +#include "../operand/Tensor.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace kernel +{ + +class UnpackLayer : public ::onert::exec::IFunction +{ +public: + UnpackLayer(); + +public: + void unpackFloat32(); + + void unpackQuant8(); + + void configure(const operand::Tensor *input, uint32_t axis, int32_t num_output, + std::vector &output); + + void run(); + void runSync() + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } + +private: + const operand::Tensor *_input; + std::vector _outputs; + uint32_t _axis; + int32_t _num_output; +}; + +} // namespace kernel +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_KERNEL_UNPACKLAYER_H__ diff --git a/runtime/onert/backend/cpu/operand/Tensor.cc b/runtime/onert/backend/cpu/operand/Tensor.cc new file mode 100644 index 000000000..96ee93023 --- /dev/null +++ b/runtime/onert/backend/cpu/operand/Tensor.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Tensor.h" + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace operand +{ + +size_t Tensor::calcOffset(const ir::Coordinates &coords) const +{ + size_t rank = num_dimensions(); + size_t offset = 0; + for (size_t i = 0; i < rank; ++i) + { + offset = offset * dimension(i) + coords[i]; + } + offset *= sizeOfDataType(data_type()); + return offset; +} + +void Tensor::access(const std::function &fn) { fn(*this); } + +} // namespace operand +} // namespace cpu +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu/operand/Tensor.h b/runtime/onert/backend/cpu/operand/Tensor.h new file mode 100644 index 000000000..f9e7b34d1 --- /dev/null +++ b/runtime/onert/backend/cpu/operand/Tensor.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_OPERAND_TENSOR_H__ +#define __ONERT_BACKEND_CPU_OPERAND_TENSOR_H__ + +#include "Allocator.h" + +#include +#include + +namespace onert +{ +namespace backend +{ +namespace cpu +{ +namespace operand +{ + +class Tensor : public ITensor +{ +public: + Tensor() = delete; + +public: + Tensor(const ir::OperandInfo &info) + : _info(info), _buffer(nullptr), _num_references(0), _allocator(nullptr) + { + // DO NOTHING + } + +public: + // Only one of two method 'setBuffer' must be called once + void setBuffer(uint8_t *buffer) + { + assert(_buffer == nullptr && _allocator == nullptr); + _buffer = buffer; + } + void setBuffer(const std::shared_ptr &alloc) + { + assert(_buffer == nullptr && _allocator == nullptr); + _allocator = alloc; + } + ir::DataType data_type() const { return _info.typeInfo().type(); } + float scale() const { return _info.typeInfo().scale(); } + int32_t offset() const { return _info.typeInfo().offset(); } + +public: + uint8_t *buffer() const override + { + if (_allocator != nullptr) + return _allocator->base(); + else + return _buffer; + } + /** + * @brief Get dimension by index + * + * @param index Index to get diemension + * @return size_t Dimension at index + * @note N : dimension(0) + * H : dimension(1) + * W : dimension(2) + * C : dimension(3) + */ + size_t dimension(size_t index) const override { return _info.shape().dim(index); } + size_t num_dimensions() const override { return _info.shape().rank(); } + size_t total_size() const override { return _info.total_size(); } + size_t calcOffset(const ir::Coordinates &coords) const override; + ir::Layout layout() const override { return ir::Layout::NHWC; } + bool has_padding() const override { return false; } + void access(const std::function &fn) final; + bool is_dynamic() const override { return _info.memAllocType() == ir::MemAllocType::DYNAMIC; } + + void increase_ref() + { + assert(_buffer != nullptr || _allocator != nullptr); + ++_num_references; + } + void decrease_ref() + { + assert(_buffer != nullptr || _allocator != nullptr); + assert(_num_references > 0); + --_num_references; + // Only constant tensor has allocator pointer + if (_num_references == 0) + { + if (_buffer != nullptr) + _buffer = nullptr; + else + { + _allocator->release(); + _allocator = nullptr; + } + } + } + +private: + ir::OperandInfo _info; + uint8_t *_buffer; + int32_t _num_references; + std::shared_ptr _allocator; +}; + +} // namespace operand +} // namespace cpu +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_OPERAND_TENSOR_H__ diff --git a/runtime/onert/backend/cpu_common/Allocator.cc b/runtime/onert/backend/cpu_common/Allocator.cc new file mode 100644 index 000000000..253fc4753 --- /dev/null +++ b/runtime/onert/backend/cpu_common/Allocator.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Allocator.h" + +#include "util/logging.h" + +namespace onert +{ +namespace backend +{ +namespace cpu_common +{ + +Allocator::Allocator(uint32_t capacity) +{ + _base = std::make_unique(capacity); + + VERBOSE(ALLOC) << "allocation capacity: " << capacity << std::endl; + VERBOSE(ALLOC) << "base pointer: " << static_cast(_base.get()) << std::endl; +} + +} // namespace cpu_common +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu_common/Allocator.h b/runtime/onert/backend/cpu_common/Allocator.h new file mode 100644 index 000000000..fa67fc7c4 --- /dev/null +++ b/runtime/onert/backend/cpu_common/Allocator.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file        Allocator.h + * @brief       This file contains Allocator related classes + */ + +#ifndef __ONERT_BACKEND_CPU_COMMON_ALLOCATOR_H__ +#define __ONERT_BACKEND_CPU_COMMON_ALLOCATOR_H__ + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu_common +{ + +/** + * @brief Class to allocate memory + */ +class Allocator +{ +public: + Allocator(uint32_t capacity); + /** + * @brief Get memory base pointer + * @return base pointer + */ + uint8_t *base() const { return _base.get(); } + void release() { _base.reset(); } + +private: + std::unique_ptr _base; +}; + +} // namespace cpu_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_COMMON_ALLOCATOR_H__ diff --git a/runtime/onert/backend/cpu_common/CMakeLists.txt b/runtime/onert/backend/cpu_common/CMakeLists.txt new file mode 100644 index 000000000..bc9e014e7 --- /dev/null +++ b/runtime/onert/backend/cpu_common/CMakeLists.txt @@ -0,0 +1,35 @@ +file(GLOB SOURCES "*.cc") +file(GLOB_RECURSE TESTS "*.test.cc") +list(REMOVE_ITEM SOURCES ${TESTS}) + +add_library(${LIB_ONERT_BACKEND_CPU_COMMON} STATIC ${SOURCES}) + +target_include_directories(${LIB_ONERT_BACKEND_CPU_COMMON} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(${LIB_ONERT_BACKEND_CPU_COMMON} PUBLIC onert_core) +target_link_libraries(${LIB_ONERT_BACKEND_CPU_COMMON} PRIVATE nnfw_lib_misc) +target_link_libraries(${LIB_ONERT_BACKEND_CPU_COMMON} PRIVATE nnfw_common) +target_link_libraries(${LIB_ONERT_BACKEND_CPU_COMMON} PRIVATE nnfw_coverage) + +set_target_properties(${LIB_ONERT_BACKEND_CPU_COMMON} PROPERTIES POSITION_INDEPENDENT_CODE ON) +set_target_properties(${LIB_ONERT_BACKEND_CPU_COMMON} PROPERTIES OUTPUT_NAME backend_cpu_common) + +install(TARGETS ${LIB_ONERT_BACKEND_CPU_COMMON} ARCHIVE DESTINATION lib) +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + DESTINATION "include/onert" + FILES_MATCHING PATTERN "*.h" + ) + +if(NOT ENABLE_TEST) + return() +endif(NOT ENABLE_TEST) + +# Unit Tests +set(TEST_ONERT_BACKEND_CPU_COMMON test_onert_backend_cpu_common) + +add_executable(${TEST_ONERT_BACKEND_CPU_COMMON} ${TESTS}) + +target_link_libraries(${TEST_ONERT_BACKEND_CPU_COMMON} ${LIB_ONERT_BACKEND_CPU_COMMON}) +target_link_libraries(${TEST_ONERT_BACKEND_CPU_COMMON} gtest gtest_main dl ${LIB_PTHREAD}) + +add_test(${TEST_ONERT_BACKEND_CPU_COMMON} ${TEST_ONERT_BACKEND_CPU_COMMON}) +install(TARGETS ${TEST_ONERT_BACKEND_CPU_COMMON} DESTINATION unittest) diff --git a/runtime/onert/backend/cpu_common/MemoryManager.cc b/runtime/onert/backend/cpu_common/MemoryManager.cc new file mode 100644 index 000000000..df6aa12f8 --- /dev/null +++ b/runtime/onert/backend/cpu_common/MemoryManager.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MemoryManager.h" + +#include + +#include +#include "util/ConfigSource.h" + +namespace onert +{ +namespace backend +{ +namespace cpu_common +{ + +MemoryManager::MemoryManager() : _mem_planner{createMemoryPlanner()} +{ + // DO NOTHING +} + +MemoryManager::MemoryManager(const std::string planner_id) + : _mem_planner{createMemoryPlanner(planner_id)} +{ + // DO NOTHING +} + +cpu_common::IMemoryPlanner *MemoryManager::createMemoryPlanner() +{ + auto planner_id = util::getConfigString(util::config::CPU_MEMORY_PLANNER); + return cpu_common::MemoryPlannerFactory::get().create(planner_id); +} + +cpu_common::IMemoryPlanner *MemoryManager::createMemoryPlanner(const std::string planner_id) +{ + return cpu_common::MemoryPlannerFactory::get().create(planner_id); +} + +void MemoryManager::claimPlan(const ir::OperandIndex &ind, uint32_t size) +{ + _mem_planner->claim(ind, size); +} + +void MemoryManager::releasePlan(const ir::OperandIndex &ind) { _mem_planner->release(ind); } + +void MemoryManager::allocate(void) +{ + _mem_alloc = std::make_shared(_mem_planner->capacity()); + assert(_mem_alloc->base()); +} + +uint8_t *MemoryManager::getBuffer(const ir::OperandIndex &ind) const +{ + assert(_mem_planner->memory_plans().find(ind) != _mem_planner->memory_plans().end()); + const auto &mem_blk = _mem_planner->memory_plans().at(ind); + return _mem_alloc->base() + mem_blk.offset; +} + +std::shared_ptr DynamicMemoryManager::allocate(const ir::OperandIndex &ind, + uint32_t capacity) +{ + auto mem_alloc = std::make_shared(capacity); + _mem_alloc_map[ind] = mem_alloc; + return mem_alloc; +} + +void DynamicMemoryManager::deallocate(void) +{ + for (auto &mem_alloc : _mem_alloc_map) + { + mem_alloc.second->release(); + } +} + +} // namespace cpu_common +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu_common/MemoryManager.h b/runtime/onert/backend/cpu_common/MemoryManager.h new file mode 100644 index 000000000..b6d2d5192 --- /dev/null +++ b/runtime/onert/backend/cpu_common/MemoryManager.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_MEMORY_MANAGER_H__ +#define __ONERT_BACKEND_CPU_MEMORY_MANAGER_H__ + +#include "backend/IMemoryManager.h" +#include "MemoryPlanner.h" +#include "ir/OperandIndexMap.h" + +namespace onert +{ +namespace backend +{ +namespace cpu_common +{ + +class MemoryManager : public backend::IMemoryManager +{ +public: + MemoryManager(); + MemoryManager(const std::string); + virtual ~MemoryManager() = default; + + void allocate(void) override; + uint8_t *getBuffer(const ir::OperandIndex &ind) const; + void deallocate(void) override { _mem_alloc->release(); } + + void claimPlan(const ir::OperandIndex &ind, uint32_t size); + void releasePlan(const ir::OperandIndex &ind); + +private: + cpu_common::IMemoryPlanner *createMemoryPlanner(); + cpu_common::IMemoryPlanner *createMemoryPlanner(const std::string); + +private: + ir::OperandIndexMap _tensor_mem_map; + std::shared_ptr _mem_planner; + std::shared_ptr _mem_alloc; +}; + +class DynamicMemoryManager +{ +public: + DynamicMemoryManager() = default; + virtual ~DynamicMemoryManager() = default; + + std::shared_ptr allocate(const ir::OperandIndex &ind, uint32_t capacity); + void deallocate(void); + +private: + ir::OperandIndexMap> _mem_alloc_map; +}; + +} // namespace cpu_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_MEMORY_MANAGER_H__ diff --git a/runtime/onert/backend/cpu_common/MemoryPlanner.cc b/runtime/onert/backend/cpu_common/MemoryPlanner.cc new file mode 100644 index 000000000..4b7f12cfd --- /dev/null +++ b/runtime/onert/backend/cpu_common/MemoryPlanner.cc @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MemoryPlanner.h" +#include "util/logging.h" +#include + +namespace onert +{ +namespace backend +{ +namespace cpu_common +{ + +void BumpPlanner::claim(const ir::OperandIndex &ind, size_t size) +{ + assert(size != 0); + + Block blk{_capacity, size}; + _mem_plans[ind] = blk; + _capacity += size; + + VERBOSE(BP_PLANNER) << "CLAIM(#" << ind.value() << "): " << blk.offset << ", " << blk.size + << std::endl; +} + +void BumpPlanner::release(const ir::OperandIndex &ind) +{ + VERBOSE(BP_PLANNER) << "RELEASE(#" << ind.value() << "): " + << "NOTHING does" << std::endl; +} + +// There are some assumptions for claiming memory(== making a reservation for memory). +// 1. About _claim_table(std::map). +// - The table's data structure is std::map so that it always sorts +// value(OperandIndex) by key(base_offset). +// - This claim() inserts key/value into _claim_table and the release() removes the key/value from +// _claim_table. +// - _claim_table shows the memory status at a certain point in time. Therefore, +// - If _claim_table has an offset and a certain size at a certain point in time, +// it means the place at the offset has been already claimed(== can't claim now. need to find +// someplace new). +// - If _claim_table doesn't have any element for an offset and a certain size at a certain +// point in time, it means the place at the offset can be claimed. +// 2. In the loop for _claim_table, we can assume the current claim_base_offset value is bigger than +// the previous claim_base_offset. +void FirstFitPlanner::claim(const ir::OperandIndex &ind, size_t size) +{ + assert(size != 0); + + // Find the right position for claiming + uint32_t next_offset = 0; + for (auto &mem_claim : _claim_table) + { + auto claimed_base_offset = mem_claim.first; + auto claimed_size = _mem_plans[mem_claim.second].size; + if (next_offset + size <= claimed_base_offset) + { + break; + } + else + { + next_offset = claimed_base_offset + claimed_size; + } + } + + // Now next_offset is set to the proper offset + _claim_table[next_offset] = ind; + _mem_plans[ind] = {next_offset, size}; + + VERBOSE(FF_PLANNER) << "claim(#" << ind.value() << "): [+" << next_offset << ", " << size << "sz]" + << std::endl; + + if (_capacity < next_offset + size) + { + _capacity = next_offset + size; + } +} + +void FirstFitPlanner::release(const ir::OperandIndex &ind) +{ + for (auto it = _claim_table.cbegin(); it != _claim_table.cend(); ++it) + { + if (it->second == ind) + { + uint32_t offset = it->first; + uint32_t index = ind.value(); + uint32_t size = _mem_plans[ind].size; + + _claim_table.erase(it); + + VERBOSE(FF_PLANNER) << "release(#" << index << "): [+" << offset << ", " << size << "sz]" + << std::endl; + return; + } + } + assert(!"Cannot release for given index. It has been not claimed or released already."); +} + +WICPlanner::WICPlanner() + : _initialized(false), _capacity(0), _mem_plans(), _live_operands(), _interference_graph(), + _map_size_to_operands(), _claim_table() +{ + // DO NOTHING +} + +void WICPlanner::claim(const ir::OperandIndex &ind, size_t size) +{ + assert(size != 0); + + _map_size_to_operands.insert({size, ind}); + for (auto &live_operand : _live_operands) + { + _interference_graph[live_operand].insert(ind); + _interference_graph[ind].insert(live_operand); + } + _live_operands.insert(ind); + + VERBOSE(WIC_PLANNER) << "claim(#" << ind.value() << "): [" << size << "sz]" << std::endl; +} + +void WICPlanner::release(const ir::OperandIndex &ind) +{ + _live_operands.erase(ind); + VERBOSE(WIC_PLANNER) << "release(#" << ind.value() << ")" << std::endl; +} + +/* + * Build memory plans using liveness and size of operands + * 1. Build inference graph at claim + * - Two operands interfere if they have overlapped live range + * 2. Sort operands descending order of size + * - Use std::multimap to sort operands + * 3. Allocate memory block for sorted operands + * - Find free memory block which does not overlap with interfered operands + */ +void WICPlanner::buildMemoryPlans() +{ + for (auto &size_to_operand : _map_size_to_operands) + { + uint32_t size = size_to_operand.first; + ir::OperandIndex ind = size_to_operand.second; + VERBOSE(WIC_PLANNER) << "build_plan(#" << ind.value() << "): [" << size << "sz]" << std::endl; + + // Find firstfit which does not interfere with live operands + uint32_t next_offset = 0; + if (_interference_graph.find(ind) != _interference_graph.end()) + { + std::unordered_set &interferences = _interference_graph.find(ind)->second; + for (auto &mem_claim : _claim_table) + { + if (interferences.find(mem_claim.second) != interferences.end()) + { + auto claimed_base_offset = mem_claim.first; + auto claimed_size = _mem_plans[mem_claim.second].size; + VERBOSE(WIC_PLANNER) << "interfere (#" << mem_claim.second.value() << "): [+" + << claimed_base_offset << ", " << claimed_size << "sz]" << std::endl; + if (next_offset + size <= claimed_base_offset) + { + break; + } + else if (next_offset < claimed_base_offset + claimed_size) + { + next_offset = claimed_base_offset + claimed_size; + } + } + } + } + else + { + VERBOSE(WIC_PLANNER) << "No interference" << std::endl; + } + + _claim_table.insert({next_offset, ind}); + _mem_plans[ind] = {next_offset, size}; + VERBOSE(WIC_PLANNER) << "alloc(#" << ind.value() << "): [+" << next_offset << ", " << size + << "sz]" << std::endl; + + if (_capacity < next_offset + size) + { + _capacity = next_offset + size; + } + } + _initialized = true; + _interference_graph.clear(); + _map_size_to_operands.clear(); + _claim_table.clear(); +} + +WICPlanner::MemoryPlans &WICPlanner::memory_plans() +{ + if (!_initialized) + buildMemoryPlans(); + return _mem_plans; +} + +} // namespace cpu_common +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu_common/MemoryPlanner.h b/runtime/onert/backend/cpu_common/MemoryPlanner.h new file mode 100644 index 000000000..4f9724328 --- /dev/null +++ b/runtime/onert/backend/cpu_common/MemoryPlanner.h @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file        MemoryPlanner.h + * @brief       This file contains Memory Planning related classes + */ + +#ifndef __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_H__ +#define __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_H__ + +#include +#include +#include + +#include "Allocator.h" +#include "ir/OperandIndexMap.h" + +namespace onert +{ +namespace backend +{ +namespace cpu_common +{ + +/** + * @brief Structure to have memory offset and size + */ +struct Block +{ + uint32_t offset; + size_t size; +}; + +/** + * @brief Interface to plan memory + */ +struct IMemoryPlanner +{ + using MemoryPlans = ir::OperandIndexMap; + + /** + * @brief Claim memory for operand + * @param[in] index The operand index + * @param[in] size The size of the memory + */ + virtual void claim(const ir::OperandIndex &, size_t) = 0; + /** + * @brief Release memory for operand + * @param[in] index The operand index + */ + virtual void release(const ir::OperandIndex &) = 0; + /** + * @brief Get capacity for memory planning + * @return The value of capacity + */ + virtual uint32_t capacity() = 0; + /** + * @brief Get MemoryPlans + * @return MemoryPlans + */ + virtual MemoryPlans &memory_plans() = 0; + + virtual ~IMemoryPlanner() = default; +}; + +/** + * @brief Class to plan memory by bump way + */ +class BumpPlanner : public IMemoryPlanner +{ +public: + /** + * @brief Claim memory for operand by bump way + * @param[in] index The operand index + * @param[in] size The size of the memory + */ + void claim(const ir::OperandIndex &, size_t) override; + /** + * @brief Release memory for operand by bump way + * @param[in] index The operand index + */ + void release(const ir::OperandIndex &) override; + /** + * @brief Get capacity for memory planning + * @return The value of capacity + */ + uint32_t capacity() override { return _capacity; } + /** + * @brief Get MemoryPlans + * @return MemoryPlans + */ + MemoryPlans &memory_plans() override { return _mem_plans; } + +private: + uint32_t _capacity = 0; + MemoryPlans _mem_plans; +}; + +/** + * @brief Class to plan memory by firstfit way + */ +class FirstFitPlanner : public IMemoryPlanner +{ +public: + /** + * @brief Claim memory for operand by firstfit way + * @param[in] index The operand index + * @param[in] size The size of the memory + */ + void claim(const ir::OperandIndex &, size_t) override; + /** + * @brief Release memory for operand by firstfit way + * @param[in] index The operand index + */ + void release(const ir::OperandIndex &) override; + /** + * @brief Get capacity for memory planning + * @return The value of capacity + */ + uint32_t capacity() override { return _capacity; } + /** + * @brief Get MemoryPlans + * @return MemoryPlans + */ + MemoryPlans &memory_plans() override { return _mem_plans; } + +private: + uint32_t _capacity = 0; + MemoryPlans _mem_plans; + // Use std::map because claim() assumes that _claim_table is sorted by uint32_t(base_offset) + std::map _claim_table; +}; + +/** + * @brief Class to plan memory by Weighted Interval Color algorithm + */ +class WICPlanner : public IMemoryPlanner +{ +public: + WICPlanner(); + + /** + * @brief Claim memory for operand by WIC algorithm + * @param[in] index The operand index + * @param[in] size The size of the memory + */ + void claim(const ir::OperandIndex &, size_t) override; + /** + * @brief Release memory for operand by WIC algorithm + * @param[in] index The operand index + */ + void release(const ir::OperandIndex &) override; + /** + * @brief Get capacity for memory planning + * @return The value of capacity + */ + uint32_t capacity() override + { + if (!_initialized) + buildMemoryPlans(); + return _capacity; + } + /** + * @brief Get MemoryPlans + * @return MemoryPlans + */ + MemoryPlans &memory_plans() override; + +private: + void buildMemoryPlans(); + + bool _initialized; + uint32_t _capacity; + MemoryPlans _mem_plans; + std::unordered_set _live_operands; + ir::OperandIndexMap> _interference_graph; + // Sort operands by descending order of size + std::multimap> _map_size_to_operands; + std::multimap _claim_table; +}; + +} // namespace cpu_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_H__ diff --git a/runtime/onert/backend/cpu_common/MemoryPlanner.test.cc b/runtime/onert/backend/cpu_common/MemoryPlanner.test.cc new file mode 100644 index 000000000..5208a94d4 --- /dev/null +++ b/runtime/onert/backend/cpu_common/MemoryPlanner.test.cc @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "MemoryPlanner.h" +#include "ir/Index.h" + +TEST(Allocator, allocate_test) +{ + ::onert::backend::cpu_common::Allocator allocator(1024); + ASSERT_NE(allocator.base(), nullptr); +} + +TEST(BumpPlanner, claim_test) +{ + ::onert::backend::cpu_common::BumpPlanner planner; + + auto claim = [&planner](uint32_t index, size_t size, uint32_t expected_offset) { + onert::ir::OperandIndex mem_idx(index); + planner.claim(mem_idx, size); + auto mem_blk = planner.memory_plans()[mem_idx]; + ASSERT_EQ(mem_blk.offset, expected_offset); + ASSERT_EQ(mem_blk.size, size); + }; + + claim(0, 10, 0); + claim(1, 20, 10); + claim(2, 30, 30); +} + +TEST(FirstFitPlanner, claim_release_test) +{ + ::onert::backend::cpu_common::FirstFitPlanner planner; + + auto claim = [&planner](uint32_t index, size_t size, uint32_t expected_offset) { + onert::ir::OperandIndex mem_idx(index); + planner.claim(mem_idx, size); + auto mem_blk = planner.memory_plans()[mem_idx]; + ASSERT_EQ(mem_blk.offset, expected_offset); + ASSERT_EQ(mem_blk.size, size); + }; + + auto release = [&planner](uint32_t index) { + onert::ir::OperandIndex mem_idx(index); + planner.release(mem_idx); + }; + + // 0 CLAIM - 10 + claim(0, 10, 0); + + // 1 CLAIM - 20 + claim(1, 20, 10); + + // 2 CLAIM - 30 + claim(2, 30, 30); + + // 0 RELEASE - 10 + release(0); + + // 3 CLAIM - 20 + claim(3, 20, 60); + + // 4 CLAIM - 5 + claim(4, 5, 0); + + // 5 CLAIM - 10 + claim(5, 10, 80); + + // 6 CLAIM - 5 + claim(6, 5, 5); + + // 2 RELEASE - 30 + release(2); + + // 7 CLAIM - 35 + claim(7, 35, 90); + + // 8 CLAIM - 10 + claim(8, 10, 30); + + // 4 RELEASE - 5 + release(4); + + // 9 CLAIM - 10 + claim(9, 10, 40); + + // 10 CLAIM - 10 + claim(10, 10, 50); + + // 6 RELEASE + release(6); + + // 1 RELEASE + release(1); + + // 8 RELEASE + release(8); + + // 9 RELEASE + release(9); + + // 10 RELEASE + release(10); + + // 3 RELEASE + release(3); + + // 5 RELEASE + release(5); + + // 7 RELEASE + release(7); +} + +TEST(WICPlanner, claim_release_test) +{ + ::onert::backend::cpu_common::WICPlanner planner; + + auto claim = [&planner](uint32_t index, size_t size) { + onert::ir::OperandIndex mem_idx(index); + planner.claim(mem_idx, size); + }; + + auto release = [&planner](uint32_t index) { + onert::ir::OperandIndex mem_idx(index); + planner.release(mem_idx); + }; + + auto verify = [&planner](uint32_t index, uint32_t size, uint32_t expected_offset) { + onert::ir::OperandIndex mem_idx(index); + auto mem_blk = planner.memory_plans()[mem_idx]; + ASSERT_EQ(mem_blk.offset, expected_offset); + ASSERT_EQ(mem_blk.size, size); + }; + + auto capacity = [&planner](uint32_t expected_capacity) { + auto actual_capacity = planner.capacity(); + ASSERT_EQ(actual_capacity, expected_capacity); + }; + + claim(0, 20); + claim(1, 5); + release(0); + claim(2, 10); + release(1); + claim(3, 10); + release(2); + claim(4, 10); + release(3); + claim(5, 20); + release(4); + claim(6, 20); + release(5); + release(7); + + // VERIFY 0 - 0 + verify(0, 20, 0); + + // VERIFY 1 - 20 + verify(1, 5, 20); + + // VERIFY 2 - 0 + verify(2, 10, 0); + + // VERIFY 3 - 10 + verify(3, 10, 10); + + // VERIFY 4 - 20 + verify(4, 10, 20); + + // VERIFY 5 - 0 + verify(5, 20, 0); + + // VERIFY 6 - 20 + verify(6, 20, 20); + + // CAPACITY - 40 + capacity(40); +} diff --git a/runtime/onert/backend/cpu_common/MemoryPlannerFactory.cc b/runtime/onert/backend/cpu_common/MemoryPlannerFactory.cc new file mode 100644 index 000000000..322d0de8c --- /dev/null +++ b/runtime/onert/backend/cpu_common/MemoryPlannerFactory.cc @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MemoryPlannerFactory.h" + +namespace onert +{ +namespace backend +{ +namespace cpu_common +{ + +MemoryPlannerFactory &MemoryPlannerFactory::get() +{ + static MemoryPlannerFactory instance; + return instance; +} + +IMemoryPlanner *MemoryPlannerFactory::create(const std::string &key) +{ + if (key == "FirstFit") + { + return new FirstFitPlanner; + } + else if (key == "Bump") + { + return new BumpPlanner; + } + else if (key == "WIC") + { + return new WICPlanner; + } + return new FirstFitPlanner; // Default Planner +} + +} // namespace cpu_common +} // namespace backend +} // namespace onert diff --git a/runtime/onert/backend/cpu_common/MemoryPlannerFactory.h b/runtime/onert/backend/cpu_common/MemoryPlannerFactory.h new file mode 100644 index 000000000..a85b67ca8 --- /dev/null +++ b/runtime/onert/backend/cpu_common/MemoryPlannerFactory.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_FACTORY_H__ +#define __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_FACTORY_H__ + +#include "MemoryPlanner.h" + +#include + +namespace onert +{ +namespace backend +{ +namespace cpu_common +{ + +class MemoryPlannerFactory +{ +public: + static MemoryPlannerFactory &get(); + +private: + MemoryPlannerFactory() = default; + +public: + IMemoryPlanner *create(const std::string &key); +}; + +} // namespace cpu_common +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_CPU_COMMON_MEMORY_PLANNER_FACTORY_H__ diff --git a/runtime/onert/core/CMakeLists.txt b/runtime/onert/core/CMakeLists.txt new file mode 100644 index 000000000..46e57427c --- /dev/null +++ b/runtime/onert/core/CMakeLists.txt @@ -0,0 +1,21 @@ +file(GLOB_RECURSE SOURCES "src/*.cc") + +add_library(onert_core SHARED ${SOURCES}) +set_target_properties(onert_core PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_include_directories(onert_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(onert_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) +target_link_libraries(onert_core PUBLIC nnfw_lib_misc) +target_link_libraries(onert_core PRIVATE nnfw_lib_cker) +target_link_libraries(onert_core PRIVATE nnfw_common) +target_link_libraries(onert_core PRIVATE nnfw_coverage) +target_link_libraries(onert_core PRIVATE dl ${LIB_PTHREAD}) + +if(ENVVAR_ONERT_CONFIG) + target_compile_definitions(onert_core PRIVATE ENVVAR_FOR_DEFAULT_CONFIG) +endif(ENVVAR_ONERT_CONFIG) + +install(TARGETS onert_core LIBRARY DESTINATION lib) +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" + DESTINATION "include/onert" + FILES_MATCHING PATTERN "*.h" PATTERN "*.lst" + ) diff --git a/runtime/onert/core/include/backend/Backend.h b/runtime/onert/core/include/backend/Backend.h new file mode 100644 index 000000000..4f6ebbba7 --- /dev/null +++ b/runtime/onert/core/include/backend/Backend.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_BACKEND_H__ +#define __ONERT_BACKEND_BACKEND_H__ + +#include + +#include "ir/Graph.h" +#include "backend/IConfig.h" +#include "backend/BackendContext.h" + +namespace onert +{ +namespace backend +{ + +namespace custom +{ +class IKernelBuilder; +} + +class Backend +{ +public: + virtual ~Backend() = default; + virtual std::shared_ptr config() const = 0; + + virtual std::unique_ptr + newContext(const ir::Graph &graph, const std::shared_ptr &kb, + bool is_linear_executor) const = 0; +}; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_BACKEND_H__ diff --git a/runtime/onert/core/include/backend/BackendContext.h b/runtime/onert/core/include/backend/BackendContext.h new file mode 100644 index 000000000..3c88b5418 --- /dev/null +++ b/runtime/onert/core/include/backend/BackendContext.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_BACKEND_CONTEXT_H__ +#define __ONERT_BACKEND_BACKEND_CONTEXT_H__ + +#include +#include "ir/Graph.h" + +namespace onert +{ +namespace backend +{ + +class Backend; +class IConstantInitializer; +class IKernelGenerator; +class IShapeFixer; +class ITensorRegister; +struct ITensorBuilder; +struct IOptimizer; + +class BackendContext +{ +public: + struct OperationInfo + { + ir::OperationIndex index; + ir::Layout layout; + + OperationInfo(ir::OperationIndex index, ir::Layout layout) : index{index}, layout{layout} {} + }; + +public: + BackendContext(const Backend *backend, const ir::Graph *graph, + std::shared_ptr tensor_builder = nullptr, + std::shared_ptr constant_initializer = nullptr, + std::shared_ptr kernel_gen = nullptr, + std::shared_ptr shape_fixer = nullptr, + std::shared_ptr tensor_register = nullptr, + std::shared_ptr optimizer = nullptr) + : _backend{backend}, _graph{graph}, tensor_builder{tensor_builder}, + constant_initializer{constant_initializer}, kernel_gen{kernel_gen}, + shape_fixer{shape_fixer}, tensor_register{tensor_register}, optimizer{optimizer} + { + } + + void initialize(const std::vector &operation_list, + const std::vector &operand_list); + void fixShapes(); + void initConsts(); + + const Backend *backend() const { return _backend; } + const ir::Graph *graph() const { return _graph; } + const std::vector &operation_list() { return _operation_list; } + const std::vector &operand_list() { return _operand_list; } + +private: + const Backend *_backend{nullptr}; + const ir::Graph *_graph{nullptr}; + std::vector _operation_list; + std::vector _operand_list; + +public: + std::shared_ptr tensor_builder; + std::shared_ptr constant_initializer; + std::shared_ptr kernel_gen; + std::shared_ptr shape_fixer; + std::shared_ptr tensor_register; + std::shared_ptr optimizer; +}; + +using BackendContexts = std::unordered_map>; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_BACKEND_CONTEXT_H__ diff --git a/runtime/onert/core/include/backend/CustomKernelBuilder.h b/runtime/onert/core/include/backend/CustomKernelBuilder.h new file mode 100644 index 000000000..2d35406dd --- /dev/null +++ b/runtime/onert/core/include/backend/CustomKernelBuilder.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_CUSTOM_KERNEL_BUILDER_H__ +#define __ONERT_BACKEND_CUSTOM_KERNEL_BUILDER_H__ + +#include "misc/tensor/Shape.h" +#include "ir/DataType.h" + +#include +#include + +namespace onert +{ +namespace exec +{ + +class IFunction; + +} // namespace exec +} // namespace onert + +namespace onert +{ +namespace backend +{ +namespace custom +{ + +using Shape = nnfw::misc::tensor::Shape; + +struct TypeInfo +{ + Shape shape; + ir::DataType dtype; +}; + +struct CustomKernelConfigParams +{ + std::vector input_allocations; + std::vector input_types; + + std::vector output_allocations; + std::vector output_types; + + char *userdata; + size_t userdata_size; +}; + +class IKernelBuilder +{ +public: + virtual ~IKernelBuilder() = default; + virtual std::unique_ptr buildKernel(const std::string &id, + CustomKernelConfigParams &¶ms) const = 0; +}; + +} // namespace custom + +} // namespace backend + +} // namespace onert + +#endif // __ONERT_BACKEND_CUSTOM_KERNEL_BUILDER_H__ diff --git a/runtime/onert/core/include/backend/IConfig.h b/runtime/onert/core/include/backend/IConfig.h new file mode 100644 index 000000000..e4e1d5a7f --- /dev/null +++ b/runtime/onert/core/include/backend/IConfig.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ICONFIG_H__ +#define __ONERT_BACKEND_ICONFIG_H__ + +#include "util/ITimer.h" +#include +#include + +namespace onert +{ +namespace backend +{ + +struct IConfig +{ + virtual ~IConfig() = default; + + virtual std::string id() = 0; + virtual bool initialize() = 0; + // Support permute kernel + virtual bool SupportPermutation() = 0; + + // Timer is used for backend profiling. In case of default (nullptr) timer profiler won't work. + virtual std::unique_ptr timer() { return nullptr; } +}; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ICONFIG_H__ diff --git a/runtime/onert/core/include/backend/IConstantInitializer.h b/runtime/onert/core/include/backend/IConstantInitializer.h new file mode 100644 index 000000000..3872f333b --- /dev/null +++ b/runtime/onert/core/include/backend/IConstantInitializer.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ICONSTANT_INITIALIZER_H__ +#define __ONERT_BACKEND_ICONSTANT_INITIALIZER_H__ + +#include +#include + +#include "ITensorBuilder.h" +#include "ir/Coordinates.h" +#include "ir/Layout.h" +#include "ir/Operand.h" +#include "ir/Operands.h" +#include "ir/OperationVisitor.h" +#include "ir/OpSequence.h" +#include "util/logging.h" + +namespace +{ +template +static void Init(const onert::ir::Operand &model_obj, onert::backend::ITensor &obj, const bool copy, + const onert::ir::Layout frontend_layout = onert::ir::Layout::UNKNOWN) +{ + const auto shape = model_obj.shape(); + assert(model_obj.data()); + auto base = reinterpret_cast(model_obj.data()->base()); + + obj.access([&](::onert::backend::ITensor &tensor) { + switch (shape.rank()) + { + case 0: + { + assert(model_obj.data()->size() == sizeof(T)); + const auto value = *reinterpret_cast(base); + T *into = reinterpret_cast(tensor.buffer()); + *into = value; + break; + } + case 1: + { + auto vec_size = shape.dim(0); + for (int32_t n = 0; n < vec_size; ++n) + { + const T *from = reinterpret_cast(base) + n; + const auto value = *from; + + T *into = reinterpret_cast(tensor.buffer()) + n; + + *into = value; + } + break; + } + case 2: + { + const int32_t copy_len = shape.dim(1); + + for (auto i = 0; i < shape.dim(0); ++i) + { + ::onert::ir::Coordinates coords{i, 0}; + memcpy(tensor.buffer() + tensor.calcOffset(coords), base + i * copy_len, + copy_len * sizeof(T)); + } + break; + } + case 3: + { + const int32_t width = shape.dim(1); + const int32_t copy_len = shape.dim(2); + + for (auto i = 0; i < shape.dim(0); ++i) + { + for (auto j = 0; j < shape.dim(1); ++j) + { + ::onert::ir::Coordinates coords{i, j, 0}; + memcpy(tensor.buffer() + tensor.calcOffset(coords), + base + i * width * copy_len + j * copy_len, copy_len * sizeof(T)); + } + } + break; + } + case 4: + { + const int32_t height = shape.dim(1); + const int32_t width = shape.dim(2); + const int32_t copy_len = shape.dim(3); + for (auto i = 0; i < shape.dim(0); ++i) + { + for (auto j = 0; j < shape.dim(1); ++j) + { + for (auto k = 0; k < shape.dim(2); ++k) + { + if (copy) + { + ::onert::ir::Coordinates coords{i, j, k, 0}; + memcpy(tensor.buffer() + tensor.calcOffset(coords), + base + i * height * width * copy_len + j * width * copy_len + k * copy_len, + copy_len * sizeof(T)); + } + else + { + for (auto l = 0; l < shape.dim(3); ++l) + { + const auto coords = ::onert::ir::convertCoordinates({i, j, k, l}, frontend_layout, + tensor.layout()); + T *into = reinterpret_cast(tensor.buffer() + tensor.calcOffset(coords)); + T value = *(base + i * height * width * copy_len + j * width * copy_len + + k * copy_len + l); + *into = value; + } + } + } + } + } + break; + } + default: + throw std::runtime_error{"Not yet supported"}; + } + }); +} + +template +void copyInit(const onert::ir::Operand &model_obj, onert::backend::ITensor &obj) +{ + Init(model_obj, obj, true); +} + +template +void permuteInit(const onert::ir::Operand &model_obj, onert::backend::ITensor &obj, + const onert::ir::Layout frontend_layout) +{ + const bool copy = frontend_layout == obj.layout(); + Init(model_obj, obj, copy, frontend_layout); +} + +} // namespace + +namespace onert +{ +namespace backend +{ + +class IConstantInitializer : public ir::OperationVisitor +{ +public: + virtual ~IConstantInitializer() = default; + +public: + void run() + { + assert(tensor_builder().get()); + for (const auto &it : _init_map) + { + const auto &ind = it.first; + const auto &fn = it.second; + + const auto &model_obj = _operands.at(ind); + auto tensor_obj = tensor_builder()->tensorAt(ind); + assert(tensor_obj != nullptr); + fn(model_obj, *tensor_obj); + VERBOSE(FillOperandData) << "Fill data for operand " << ind.value() << std::endl; + } + _init_map.clear(); + } + +public: + IConstantInitializer(const ir::Operands &operands) + : _operands{operands}, _current_op_seq_layout{ir::Layout::UNKNOWN} + { + } + +public: + using Initializer = std::function; + + void setLayout(ir::Layout layout) { _current_op_seq_layout = layout; } + +protected: + using OperationVisitor::visit; + +protected: + virtual std::shared_ptr tensor_builder() const = 0; + +public: + void registerCopyInitializer(const ir::OperandIndex &index, const ir::Operand &obj) + { + // For only CONSTANTS + // TODO Add to check if tensor has been allocated + if (!obj.isConstant()) + return; + + const auto type = obj.typeInfo().type(); + using ir::DataType; + + switch (type) + { + case DataType::FLOAT32: + _init_map[index] = copyInit; + break; + case DataType::INT32: + _init_map[index] = copyInit; + break; + case DataType::UINT32: + _init_map[index] = copyInit; + break; + case DataType::BOOL8: + case DataType::QUANT8_ASYMM: + _init_map[index] = copyInit; + break; + case DataType::QUANT8_SYMM: + _init_map[index] = copyInit; + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } + } + +public: + void registerPermuteInitializer(const ir::OperandIndex &index, const ir::Operand &obj) + { + // For only CONSTANTS + // TODO Add to check if tensor has been allocated + if (!obj.isConstant()) + return; + + const auto type = obj.typeInfo().type(); + using ir::DataType; + using namespace std::placeholders; + + switch (type) + { + case DataType::FLOAT32: + _init_map[index] = std::bind(permuteInit, _1, _2, _current_op_seq_layout); + break; + case DataType::INT32: + _init_map[index] = std::bind(permuteInit, _1, _2, _current_op_seq_layout); + break; + case DataType::UINT32: + _init_map[index] = std::bind(permuteInit, _1, _2, _current_op_seq_layout); + break; + case DataType::BOOL8: + case DataType::QUANT8_ASYMM: + _init_map[index] = std::bind(permuteInit, _1, _2, _current_op_seq_layout); + break; + case DataType::QUANT8_SYMM: + _init_map[index] = std::bind(permuteInit, _1, _2, _current_op_seq_layout); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } + } + +public: + bool exist(const ir::OperandIndex &ind) { return _init_map.find(ind) != _init_map.end(); } + +protected: + const ir::Operands &_operands; + std::unordered_map _init_map; + ir::Layout _current_op_seq_layout; // TODO Rename this to _current_layout +}; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ICONSTANT_INITIALIZER_H__ diff --git a/runtime/onert/core/include/backend/IKernelGenerator.h b/runtime/onert/core/include/backend/IKernelGenerator.h new file mode 100644 index 000000000..afc34ec21 --- /dev/null +++ b/runtime/onert/core/include/backend/IKernelGenerator.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_IKERNEL_GENERATOR_H__ +#define __ONERT_BACKEND_IKERNEL_GENERATOR_H__ + +#include +#include +#include + +#include "ITensorBuilder.h" +#include "ir/OperationVisitor.h" +#include "ir/OpSequence.h" +#include +#include "exec/FunctionSequence.h" + +namespace onert +{ +namespace backend +{ + +class IKernelGenerator : public ir::OperationVisitor +{ +public: + virtual ~IKernelGenerator() = default; + + std::unique_ptr releaseFunction() + { + assert(_return_fn); + return std::move(_return_fn); + } + + std::unique_ptr generate(const ir::OpSequence &op_seq) + { + op_seq.accept(*this); + return std::move(_return_fn_seq); + } + +protected: + using OperationVisitor::visit; + + void visit(const ir::OpSequence &) override + { + throw std::runtime_error("KernelGenerator: NYI for operation 'OpSequence'"); + } + +#define OP(InternalName) \ + void visit(const ir::operation::InternalName &) override \ + { \ + throw std::runtime_error("KernelGenerator: NYI for operation '" #InternalName "'"); \ + } +#include "ir/Operations.lst" +#undef OP + +protected: + std::unique_ptr _return_fn; + std::unique_ptr _return_fn_seq; // TODO Extract this out +}; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_IKERNEL_GENERATOR_H__ diff --git a/runtime/onert/core/include/backend/IMemoryManager.h b/runtime/onert/core/include/backend/IMemoryManager.h new file mode 100644 index 000000000..bad2fd51a --- /dev/null +++ b/runtime/onert/core/include/backend/IMemoryManager.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_IMEMORY_MANAGER_H__ +#define __ONERT_BACKEND_IMEMORY_MANAGER_H__ + +namespace onert +{ +namespace backend +{ + +struct IMemoryManager +{ + virtual ~IMemoryManager() = default; + + virtual void allocate(void) = 0; + virtual void deallocate(void) = 0; +}; + +} // namespace backend +} // namespace onert + +#include +#include + +namespace onert +{ +namespace backend +{ + +using MemoryManagerSet = std::unordered_set>; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_IMEMORY_MANAGER_H__ diff --git a/runtime/onert/core/include/backend/IOptimizer.h b/runtime/onert/core/include/backend/IOptimizer.h new file mode 100644 index 000000000..4844d21b9 --- /dev/null +++ b/runtime/onert/core/include/backend/IOptimizer.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_I_OPTIMIZER_H__ +#define __ONERT_BACKEND_I_OPTIMIZER_H__ + +namespace onert +{ +namespace ir +{ +class LoweredGraph; +} +} // namespace onert + +namespace onert +{ +namespace backend +{ + +/** + * @brief Class for backend optimizations. This is an optional class so not all backends must have + * it. + * + */ +struct IOptimizer +{ + virtual ~IOptimizer() = default; + /** + * @brief Run optimization + * + */ + virtual void optimize() = 0; +}; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_I_OPTIMIZER_H__ diff --git a/runtime/onert/core/include/backend/IShapeFixer.h b/runtime/onert/core/include/backend/IShapeFixer.h new file mode 100644 index 000000000..35c8d33f0 --- /dev/null +++ b/runtime/onert/core/include/backend/IShapeFixer.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ISHAPE_FIXER_H__ +#define __ONERT_BACKEND_ISHAPE_FIXER_H__ + +#include +#include + +#include "ir/LowerInfoMap.h" +#include "ITensorBuilder.h" +#include "ir/OperationVisitor.h" +#include "ir/OpSequence.h" +#include + +namespace onert +{ +namespace backend +{ + +class IShapeFixer : public ir::OperationVisitor +{ +public: + virtual ~IShapeFixer() = default; + +protected: +#define OP(InternalName) \ + void visit(const ir::operation::InternalName &) override \ + { \ + throw std::runtime_error("ShapeFixer: NYI for operation '" #InternalName "'"); \ + } +#include "ir/Operations.lst" +#undef OP + +public: + void fix(const ir::OpSequence &op_seq) { op_seq.accept(*this); }; +}; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ISHAPE_FIXER_H__ diff --git a/runtime/onert/core/include/backend/ITensor.h b/runtime/onert/core/include/backend/ITensor.h new file mode 100644 index 000000000..69f319a36 --- /dev/null +++ b/runtime/onert/core/include/backend/ITensor.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_OPERAND_I_TENSOR_H__ +#define __ONERT_BACKEND_OPERAND_I_TENSOR_H__ + +#include +#include +#include + +#include "ir/Layout.h" +#include "ir/Coordinates.h" + +namespace onert +{ +namespace backend +{ + +class ITensor +{ +public: + virtual ~ITensor() = default; + +public: + virtual uint8_t *buffer() const = 0; + virtual size_t total_size() const = 0; + virtual size_t dimension(size_t index) const = 0; + virtual size_t num_dimensions() const = 0; + virtual size_t calcOffset(const ir::Coordinates &coords) const = 0; + virtual ir::Layout layout() const = 0; + virtual bool has_padding() const = 0; + virtual void access(const std::function &fn) = 0; + + /** + * @brief Return true if the tensor needs dynamic allocation, meaning that during compile-time + * the outpus shape cannot be known and the output shape is calculated during + * kernel execution-time. + */ + virtual bool is_dynamic() const { return false; /* default */ } +}; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_OPERAND_I_TENSOR_H__ diff --git a/runtime/onert/core/include/backend/ITensorBuilder.h b/runtime/onert/core/include/backend/ITensorBuilder.h new file mode 100644 index 000000000..f747b678f --- /dev/null +++ b/runtime/onert/core/include/backend/ITensorBuilder.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ITENSOR_BUILDER_H__ +#define __ONERT_BACKEND_ITENSOR_BUILDER_H__ + +#include + +#include "ir/Index.h" +#include "ir/OperandInfo.h" +#include "ir/Operation.h" +#include "ir/Layout.h" +#include "ITensor.h" +#include "ITensorManager.h" + +namespace onert +{ +namespace backend +{ + +struct ITensorBuilder +{ + using IterateFunction = std::function; + + virtual ~ITensorBuilder(void) = default; + + /** + * @brief Register tensor information to allocate on backend + */ + virtual void registerTensorInfo(const ir::OperandIndex &, const ir::OperandInfo &, + ir::Layout backend_layout, bool as_const) = 0; + + virtual void notifyFirstUse(const ir::OperandIndex &) = 0; + virtual void notifyLastUse(const ir::OperandIndex &) = 0; + + virtual bool isRegistered(const ir::OperandIndex &) const = 0; + + virtual void prepare(void) = 0; + virtual void allocate() = 0; + virtual void postFunctionPrepare() = 0; + + virtual std::shared_ptr tensorAt(const ir::OperandIndex &ind) = 0; + virtual void iterate(const IterateFunction &fn) = 0; + + virtual std::unique_ptr releaseTensorManager(void) = 0; +}; + +} // namespace backend +} // namespace onert + +#include +#include + +namespace onert +{ +namespace backend +{ + +using TensorBuilderSet = std::unordered_set>; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ITENSOR_BUILDER_H__ diff --git a/runtime/onert/core/include/backend/ITensorManager.h b/runtime/onert/core/include/backend/ITensorManager.h new file mode 100644 index 000000000..1fcbe140f --- /dev/null +++ b/runtime/onert/core/include/backend/ITensorManager.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ITENSOR_MANAGER_H__ +#define __ONERT_BACKEND_ITENSOR_MANAGER_H__ + +namespace onert +{ +namespace backend +{ + +// NOTE This name ITensorManager has been discussed whether or not the name is proper. +// Anyone can argue with any better name. +/** + * @brief Interface as an abstract tensor manager which has MemoryManager + */ +struct ITensorManager +{ + virtual ~ITensorManager() = default; +}; + +} // namespace backend +} // namespace onert + +#include +#include + +namespace onert +{ +namespace backend +{ + +using TensorManagerSet = std::unordered_set>; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ITENSOR_MANAGER_H__ diff --git a/runtime/onert/core/include/backend/ITensorRegister.h b/runtime/onert/core/include/backend/ITensorRegister.h new file mode 100644 index 000000000..bceaebf32 --- /dev/null +++ b/runtime/onert/core/include/backend/ITensorRegister.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_BACKEND_ITENSOR_REGISTER_H__ +#define __ONERT_BACKEND_ITENSOR_REGISTER_H__ + +#include "ir/LowerInfoMap.h" +#include "ITensorBuilder.h" +#include "ir/Layout.h" +#include "ir/OperandIndexSequence.h" +#include "ir/OperandInfo.h" +#include "ir/Operands.h" +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace backend +{ + +class ITensorRegister : public ir::OperationVisitor +{ +public: + virtual ~ITensorRegister() = default; + +public: + void registerTensors(const ir::OpSequence &op_seq, const ir::LowerInfoMap *lower_info_map) + { + _current_op_seq_layout = op_seq.getLayout(); + _lower_info_map = lower_info_map; + assert(_lower_info_map != nullptr); + assert(tensor_builder().get() != nullptr); + op_seq.accept(*this); + } + +protected: + virtual const ir::Operands &operands() const = 0; + virtual std::shared_ptr tensor_builder() const = 0; + +protected: +#define OP(InternalName) \ + void visit(const ir::operation::InternalName &node) override \ + { \ + for (const auto &ind : node.getInputs() + node.getOutputs()) \ + { \ + defaultRegisterTensorInfo(ind); \ + } \ + } +#include "ir/Operations.lst" +#undef OP + +protected: + void defaultRegisterTensorInfo(const ir::OperandIndex &index) const + { + if (tensor_builder()->isRegistered(index)) + { + return; + } + + const auto &obj = operands().at(index); + const auto frontend_layout = frontendLayout(); + const auto backend_layout = backendLayout(index); + ir::OperandInfo backend_info{permuteShape(obj.shape(), frontend_layout, backend_layout), + obj.typeInfo()}; + tensor_builder()->registerTensorInfo(index, backend_info, backend_layout, obj.isConstant()); + } + +protected: + ir::Layout frontendLayout() const { return _current_op_seq_layout; } + ir::Layout backendLayout(const ir::OperandIndex &index) const + { + assert(_lower_info_map != nullptr); + const auto lower_info = _lower_info_map->operand.at(index).get(); + return lower_info->def_factors().getOnlyElement().layout(); + } + +private: + ir::Layout _current_op_seq_layout; + const ir::LowerInfoMap *_lower_info_map{nullptr}; +}; + +} // namespace backend +} // namespace onert + +#endif // __ONERT_BACKEND_ITENSOR_REGISTER_H__ diff --git a/runtime/onert/core/include/compiler/BackendManager.h b/runtime/onert/core/include/compiler/BackendManager.h new file mode 100644 index 000000000..95ba2c223 --- /dev/null +++ b/runtime/onert/core/include/compiler/BackendManager.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_BACKEND_MANAGER_H__ +#define __ONERT_COMPILER_BACKEND_MANAGER_H__ + +#include +#include + +#include "ir/Operands.h" +#include "backend/Backend.h" + +namespace onert +{ +namespace compiler +{ + +class BackendManager +{ +public: + using backend_create_t = backend::Backend *(*)(); + using backend_destroy_t = void (*)(backend::Backend *); + using dlhandle_destroy_t = void (*)(void *); + + static BackendManager &get(); + +public: + backend::Backend *get(const std::string &key); + const backend::Backend *get(const std::string &key) const; + const backend::Backend *getDefault() const; + const std::vector &getAll() const { return _available_backends; }; + /** + * @brief load backend plugin + * + * @param backend backend to be loaded + * + * @return + */ + void loadBackend(const std::string &backend); + +private: + BackendManager() = default; + +private: + std::vector _available_backends; + std::map> _handle_map; + std::map> _gen_map; + /** + * @brief Allocate an object of a class of a plugin by loading a plugin function, that does + * allocation, and calling it + * + * @param object_of_plugin_class target object + * @param obj_creator_func_name name of the plugin function, that allocates an object + * @param handle handle of the plugin + * @param args arguments to pass to constructor of the plugin class + * + * @return + */ + template + void loadObjectFromPlugin(std::shared_ptr &object_of_plugin_class, + const std::string obj_creator_func_name, void *handle, + Types &&... args); +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_BACKEND_MANAGER_H__ diff --git a/runtime/onert/core/include/compiler/BackendResolver.h b/runtime/onert/core/include/compiler/BackendResolver.h new file mode 100644 index 000000000..a316b4335 --- /dev/null +++ b/runtime/onert/core/include/compiler/BackendResolver.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_BACKEND_RESOLVER_H__ +#define __ONERT_COMPILER_BACKEND_RESOLVER_H__ + +#include +#include + +#include "backend/Backend.h" +#include "ir/OperationIndexMap.h" + +namespace onert +{ +namespace compiler +{ + +class BackendResolver +{ +public: + const backend::Backend *getBackend(const ir::OperationIndex &index) const + { + return _gen_map.at(index); + } + + void setBackend(const ir::OperationIndex &index, const backend::Backend *backend) + { + _gen_map[index] = backend; + } + + void + iterate(const std::function &fn) const + { + for (const auto &e : _gen_map) + { + fn(e.first, *e.second); + } + } + +private: + ir::OperationIndexMap _gen_map; +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_BACKEND_RESOLVER_H__ diff --git a/runtime/onert/core/include/compiler/CodeMap.h b/runtime/onert/core/include/compiler/CodeMap.h new file mode 100644 index 000000000..e13d3334c --- /dev/null +++ b/runtime/onert/core/include/compiler/CodeMap.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_CODE_MAP_H__ +#define __ONERT_COMPILER_CODE_MAP_H__ + +#include + +namespace onert +{ +namespace compiler +{ + +struct CodeAndInfo +{ + const ir::OpSequence *op_seq; + const ir::operation::LowerInfo *lower_info; + std::unique_ptr fn_seq; + + CodeAndInfo(const ir::OpSequence *op_seq, const ir::operation::LowerInfo *lower_info, + std::unique_ptr &&fn_seq) + : op_seq{op_seq}, lower_info{lower_info}, fn_seq{std::move(fn_seq)} + { + } +}; + +using CodeMap = std::unordered_map; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_CODE_MAP_H__ diff --git a/runtime/onert/core/include/compiler/Compiler.h b/runtime/onert/core/include/compiler/Compiler.h new file mode 100644 index 000000000..c25eb7b36 --- /dev/null +++ b/runtime/onert/core/include/compiler/Compiler.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Compiler.h + * @brief This file contains Compiler class to define and run compilation phase + */ + +#ifndef __ONERT_COMPILER_COMPILE_H_ +#define __ONERT_COMPILER_COMPILE_H_ + +#include "ir/Graph.h" +#include "exec/IExecutor.h" + +namespace onert +{ + +namespace compiler +{ + +enum class State +{ + CREATED, // Before compilation + STARTED, // Compile is started + LOWERED, // Backend is decided + COMPILED // Success compilation +}; + +struct ManualSchedulerOptions +{ + std::string backend_for_all; + std::unordered_map opcode_to_backend; + std::unordered_map index_to_backend; +}; + +struct CompilerOptions +{ + // GENERAL OPTIONS + std::vector backend_list; + + // OPTIONS ONLY FOR DEBUGGING/PROFILING + std::string trace_filepath; //< File path to save trace records + int graph_dump_level; //< Graph dump level, values between 0 and 2 are valid + int op_seq_max_node; //< Number of nodes that can be + std::string executor; //< Executor name to use + ManualSchedulerOptions manual_scheduler_options; //< Options for ManualScheduler + bool he_scheduler; //< HEScheduler if true, ManualScheduler otherwise + bool he_profiling_mode; //< Whether HEScheduler profiling mode ON/OFF + bool delete_cached_data; //< Whether CachedData deletion ON/OFF + bool disable_compile; //< Run with Interpreter if true, try compilation otherwise +}; + +CompilerOptions fetchCompilerOptionsFromGlobalConfig(const ir::Graph &graph); + +/** + * @brief Class to compile graph model + */ +class Compiler +{ +public: + /** + * @brief Construct a new Compiler object + * @param[in] model Graph model + */ + Compiler(const std::shared_ptr &graph); + +public: + /** + * @brief Run compilation. Compilation result will be saved in _plan + */ + void compile(void); + /** + * @brief Pass plan reference + * @param[out] plan Plan reference to return\n + * Set nullptr if compile is not run yet + */ + void release(std::shared_ptr &executor) { executor = _executor; } + + void state(State state) { _state = state; } + State state(void) const { return _state; } + + /** + * @brief Check if model can compile + * @return @c true if model can compile, otherwise @c false + * @note This method don't check model correctness,\n + * so model verification should be done before calling this method + */ + bool checkCompilable(); + CompilerOptions &options() { return _options; } + +private: + void checkProfilerConditions(); + +private: + std::shared_ptr _graph; + std::shared_ptr _executor; + State _state; + CompilerOptions _options; +}; + +} // namespace compiler + +} // namespace onert + +#endif // __ONERT_COMPILER_COMPILE_H_ diff --git a/runtime/onert/core/include/compiler/ExecutionBuilder.h b/runtime/onert/core/include/compiler/ExecutionBuilder.h new file mode 100644 index 000000000..d54d9d046 --- /dev/null +++ b/runtime/onert/core/include/compiler/ExecutionBuilder.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_EXECUTION_BUILDER_H__ +#define __ONERT_COMPILER_EXECUTION_BUILDER_H__ + +#include + +#include "ir/operation/LowerInfo.h" +#include "ir/OpSequence.h" +#include "exec/FunctionSequence.h" +#include "CodeMap.h" + +namespace onert +{ +namespace compiler +{ + +class ExecutionBuilder +{ +public: + void append(const ir::OpSequenceIndex index, CodeAndInfo &&code_and_info) + { + _code_map.emplace(index, std::move(code_and_info)); + } + + CodeMap releaseCodeMap() { return std::move(_code_map); } + +private: + CodeMap _code_map; +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_EXECUTION_BUILDER_H__ diff --git a/runtime/onert/core/include/exec/ExecTime.h b/runtime/onert/core/include/exec/ExecTime.h new file mode 100644 index 000000000..846d0930b --- /dev/null +++ b/runtime/onert/core/include/exec/ExecTime.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_EXEC_TIME_H__ +#define __ONERT_EXEC_EXEC_TIME_H__ + +#include "backend/Backend.h" +#include "backend/IConfig.h" +#include "JSONExecTime.h" +#include +#include +#include +#include +#include + +namespace onert +{ +namespace exec +{ +class ExecTime +{ +public: + explicit ExecTime(const std::vector &backends) + : _json(backends, _measurements) + { + } + +public: + /** + * @brief Get exec time of an operation with input size + * or linearly interpolated value based on size if there is no record for given size + * + * @param[in] backend id of a backend + * @param[in] operation name of an operation + * @param[in] quant if input type quantized + * @param[in] op_size sum of operation's flattened sizes of inputs and outputs + * @return execution time for given input sizes + * -1 if there are no records for given parameters (backend, op, quantization). + */ + int64_t getOperationExecTime(const backend::Backend *backend, const std::string &operation, + bool quant, uint32_t op_size) const; + /** + * @brief Update exec time of the operation on a backend with given input size or + * add new entity if there is no one. + * + * @param[in] backend id of a backend + * @param[in] operation name of an operation + * @param[in] quant if input type quantized + * @param[in] op_size sum of operation's flattened sizes of inputs and outputs + * @param[in] time real measured value + */ + void updateOperationExecTime(const backend::Backend *backend, const std::string &operation, + bool quant, uint32_t op_size, int64_t time); + /** + * @brief Get the permute time from one backend to another + * + * @param[in] from_backend + * @param[in] to_backend + * @param[in] quant if input type quantized + * @param[in] op_size sum of operation's flattened sizes of inputs and outputs + * @return permutation time for operation size + */ + int64_t getPermuteTime(const backend::Backend *from_backend, const backend::Backend *to_backend, + bool quant, uint32_t op_size) const; + /** + * @brief Update permute time from one backend to another + * + * @param[in] from_backend + * @param[in] to_backend + * @param[in] quant if input type quantized + * @param[in] time measured permutation time + * @param[in] op_size sum of operation's flattened sizes of inputs and outputs + */ + void updatePermuteTime(const backend::Backend *from_backend, const backend::Backend *to_backend, + bool quant, uint32_t op_size, int64_t time); + /** + * @brief Get the max value of int32_t in int64_t + * @return max value + */ + static int64_t getMax() { return _MAX; } + /** + * @brief Update metrics file with new data. + */ + void uploadOperationsExecTime() const { _json.uploadOperationsExecTime(); } + static const int64_t NOT_FOUND = -1; + +private: + /// @brief Measurement data, which is shared with serializer + MeasurementData _measurements; + // int64_t::max may cause integer overflow + static const int64_t _MAX = std::numeric_limits::max(); + /// @brief Serializer + JSON _json; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_EXEC_TIME_H__ diff --git a/runtime/onert/core/include/exec/Execution.h b/runtime/onert/core/include/exec/Execution.h new file mode 100644 index 000000000..5ce5a8fee --- /dev/null +++ b/runtime/onert/core/include/exec/Execution.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Execution.h + * @brief This file defines execution + */ +#ifndef __ONERT_EXEC_EXECUTION_H__ +#define __ONERT_EXEC_EXECUTION_H__ + +#include "ir/Layout.h" +#include "exec/IExecutor.h" +#include "IODescription.h" + +#include + +namespace onert +{ +namespace exec +{ + +/** + * @brief Class to define execution instance to collect input/output information for inference + * and prepare executor run (TODO) + */ +class Execution +{ + +public: + /** + * @brief Construct a new Execution object + * @param[in] executor Model executor + */ + Execution(const std::shared_ptr &executor); + +public: + /** + * @brief Returns graph object + * @return Graph object + */ + const ir::Graph &graph() const { return _executor->graph(); } + /** + * @brief Set input data's information + * @param[in] index Input index + * @param[in] buffer Input data's buffer pointer + * @param[in] length Input data's length + * @param[in] layout Input data's data format + */ + void setInput(const ir::IOIndex &index, const void *buffer, size_t length, + ir::Layout layout = ir::Layout::NHWC); + /** + * @brief Set input data's information, especially to specify unknown dimensions on model + * build time. + * @param[in] index Input index + * @param[in] type Input data's type info + * @param[in] shape Input data's shape + * @param[in] buffer Input data's buffer pointer + * @param[in] length Input data's length + * @param[in] layout Input data's data format + */ + void setInput(const ir::IOIndex &index, const ir::TypeInfo &type, const ir::Shape &shape, + const void *buffer, size_t length, ir::Layout layout = ir::Layout::NHWC); + /** + * @brief Set output data's information + * @param[in] index Output index + * @param[in] buffer Output data's buffer pointer + * @param[in] length Output data's length + * @param[in] layout Output data's data format + */ + void setOutput(const ir::IOIndex &index, void *buffer, size_t length, + ir::Layout layout = ir::Layout::NHWC); + /** + * @brief Set output data's information, especially to specify unknown dimensions on model + * build time. + * @param[in] index Output index + * @param[in] type Output data's type info + * @param[in] shape Output data's shape + * @param[in] buffer Output data's buffer pointer + * @param[in] length Output data's length + * @param[in] layout Output data's data format + */ + void setOutput(const ir::IOIndex &index, const ir::TypeInfo &type, const ir::Shape &shape, + void *buffer, size_t length, ir::Layout layout = ir::Layout::NHWC); + /** + * @brief Set input data's data format + * @param[in] index Input index + * @param[in] layout Input data's data format + */ + void setInputLayout(const ir::IOIndex &index, ir::Layout layout); + /** + * @brief Set output data's data format + * @param[in] index Output index + * @param[in] layout Output data's data format + */ + void setOutputLayout(const ir::IOIndex &index, ir::Layout layout); + /** + * @brief Execution + * @note It should be called after setting input and output buffer + */ + void execute(); + + /** + * @brief Start asynchronous execution + * @note It returns after execution thread is started + * It should be called after setting input and output buffer + */ + void startExecute(void); + + /** + * @brief Return when execution is finished + * @note It waits until execution is finished + */ + void waitFinish(void); + + /** + * @brief Check execution is finished + * @return @c true if execution is finished, otherwise @c false + */ + bool isFinished(void) const; + +private: + const std::shared_ptr _executor; + IODescription _io_desc; + std::unique_ptr _exec_thread; + bool finished{false}; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_EXECUTION_H__ diff --git a/runtime/onert/core/include/exec/ExecutionObservers.h b/runtime/onert/core/include/exec/ExecutionObservers.h new file mode 100644 index 000000000..a993efee1 --- /dev/null +++ b/runtime/onert/core/include/exec/ExecutionObservers.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_OBSREVERS_H__ +#define __ONERT_EXEC_OBSREVERS_H__ + +#include "exec/IFunction.h" +#include "ir/OpSequence.h" +#include "ExecTime.h" +#include "util/ITimer.h" +#include "IExecutor.h" +#include "misc/EventCollector.h" +#include "misc/EventRecorder.h" + +namespace onert +{ +namespace exec +{ +class IExecutionObserver +{ +public: + /// @brief Invoked just before model (not individual operation) execution begins + virtual void handleBegin(IExecutor *) { return; } + + virtual void handleBegin(IExecutor *, const ir::OpSequence *, const backend::Backend *) = 0; + virtual void handleEnd(IExecutor *, const ir::OpSequence *, const backend::Backend *) = 0; + + /// @brief Invoked just after model (not individual operation) execution ends + virtual void handleEnd(IExecutor *) { return; } + + virtual ~IExecutionObserver() = default; +}; + +class ProfileObserver : public IExecutionObserver +{ +public: + explicit ProfileObserver(std::shared_ptr et) : _et(std::move(et)) {} + void handleBegin(IExecutor *, const ir::OpSequence *, const backend::Backend *) override; + void handleEnd(IExecutor *, const ir::OpSequence *, const backend::Backend *) override; + + void handleEnd(IExecutor *) override { _et->uploadOperationsExecTime(); } + +private: + std::unique_ptr _timer; + std::shared_ptr _et; +}; + +class ChromeTracingObserver : public IExecutionObserver +{ +public: + ChromeTracingObserver(const std::string &filepath); + ~ChromeTracingObserver(); + void handleBegin(IExecutor *) override; + void handleBegin(IExecutor *, const ir::OpSequence *, const backend::Backend *) override; + void handleEnd(IExecutor *, const ir::OpSequence *, const backend::Backend *) override; + void handleEnd(IExecutor *) override; + +private: + static std::string opSequenceTag(const ir::OpSequence *op_seq); + +private: + std::ofstream _ofs; + EventRecorder _recorder; + EventCollector _collector; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_OBSREVERS_H__ diff --git a/runtime/onert/core/include/exec/FunctionSequence.h b/runtime/onert/core/include/exec/FunctionSequence.h new file mode 100644 index 000000000..e11e10043 --- /dev/null +++ b/runtime/onert/core/include/exec/FunctionSequence.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_FUNCTION_SEQUENCE_H__ +#define __ONERT_EXEC_FUNCTION_SEQUENCE_H__ + +#include +#include +#include + +#include "exec/IFunction.h" +#include + +namespace onert +{ +namespace exec +{ + +class FunctionSequence : public IFunction +{ +public: + template FunctionSequence(Args &&... args) { initialize(std::move(args)...); } + +private: + void initialize() + { + // Template base case : do nothing + } + + template void initialize(std::unique_ptr &&fn, Args &&... args) + { + _functions.emplace_back(std::move(fn)); + initialize(std::move(args)...); + } + +public: + virtual ~FunctionSequence() = default; + + void run() override; + void runSync() override; + void prepare() override; + + /** + * @brief Appends an IFunction object to the function sequence + * + * @param function IFunction object to be appended + */ + void append(std::unique_ptr &&function); + + void iterate(const std::function &fn); + +private: + std::vector> _functions; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_FUNCTION_SEQUENCE_H__ diff --git a/runtime/onert/core/include/exec/IExecutor.h b/runtime/onert/core/include/exec/IExecutor.h new file mode 100644 index 000000000..8ae492696 --- /dev/null +++ b/runtime/onert/core/include/exec/IExecutor.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file IExecutor.h + * @brief This file defines interface of Executor + */ +#ifndef __ONERT_EXEC_I_EXECUTOR_H_ +#define __ONERT_EXEC_I_EXECUTOR_H_ + +#include "ir/Graph.h" +#include "IFunction.h" +#include "IODescription.h" +#include "ir/OperationIndexMap.h" + +namespace onert +{ +namespace exec +{ +class IExecutionObserver; +/** + * @brief Struct to define interface of Executor + */ +struct IExecutor +{ + /** + * @brief Construct a new IExecutor object + */ + IExecutor() = default; + /** + * @brief Destroy the IExecutor object + */ + virtual ~IExecutor() = default; + + /** + * @brief Returns graph object + * + * @return Graph object + */ + virtual const ir::Graph &graph() = 0; + + /** + * @brief Set an ordering on operations + * @param[in] ranks The table encoding the ordering + */ + virtual void setIndexedRanks(std::shared_ptr>) = 0; + + /** + * @brief Start execution + * @param[in] desc Input and output description + * @note This method should be thread-safe + */ + virtual void execute(const IODescription &desc) = 0; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_I_EXECUTOR_H_ diff --git a/runtime/onert/core/include/exec/IFunction.h b/runtime/onert/core/include/exec/IFunction.h new file mode 100644 index 000000000..258f1e5b3 --- /dev/null +++ b/runtime/onert/core/include/exec/IFunction.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_I_FUNCTION_H__ +#define __ONERT_EXEC_I_FUNCTION_H__ + +namespace onert +{ +namespace exec +{ + +class IFunction +{ +public: + virtual ~IFunction() = default; + virtual void run() = 0; + virtual void runSync() = 0; + virtual void prepare() {} +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_I_FUNCTION_H__ diff --git a/runtime/onert/core/include/exec/IODescription.h b/runtime/onert/core/include/exec/IODescription.h new file mode 100644 index 000000000..8bfddcde6 --- /dev/null +++ b/runtime/onert/core/include/exec/IODescription.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_IO_DESCRIPTION_H__ +#define __ONERT_EXEC_IO_DESCRIPTION_H__ + +#include + +#include "ir/OperandInfo.h" + +namespace onert +{ +namespace exec +{ + +struct InputDesc +{ + const ir::OperandInfo info; + const void *buffer; + const size_t size; + const ir::Layout layout; + + InputDesc(void) = delete; + InputDesc(const ir::OperandInfo &info, const void *buffer, const size_t size, ir::Layout layout) + : info(info), buffer(buffer), size(size), layout(layout) + { + } +}; + +struct OutputDesc +{ + const ir::OperandInfo info; + void *buffer; + const size_t size; + const ir::Layout layout; + + OutputDesc(void) = delete; + OutputDesc(const ir::OperandInfo &info, void *buffer, const size_t size, ir::Layout layout) + : info(info), buffer(buffer), size(size), layout(layout) + { + } +}; + +struct IODescription +{ + std::vector> inputs; + std::vector> outputs; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_IO_DESCRIPTION_H__ diff --git a/runtime/onert/core/include/exec/JSONExecTime.h b/runtime/onert/core/include/exec/JSONExecTime.h new file mode 100644 index 000000000..a64cb3133 --- /dev/null +++ b/runtime/onert/core/include/exec/JSONExecTime.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_JSON_EXEC_TIME_H__ +#define __ONERT_EXEC_JSON_EXEC_TIME_H__ + +#include +#include +#include +#include +#include "backend/Backend.h" +#include "backend/IConfig.h" + +namespace onert +{ +namespace exec +{ + +/** + * @brief table, that contains execution time of an operation on some backend for different input + * sizes and transfer time from one backend to another for various input sizes (permutation time) + * + * backend -> op -> quant-> size --> time + * _measurements[Backend*]["string"][bool][uint32_t] = int64_t + */ +using MeasurementData = std::unordered_map< + const backend::Backend *, + std::unordered_map>>>; + +class JSON +{ +public: + explicit JSON(const std::vector &backends, + MeasurementData &measurements) + : _measurement_file("exec_time.json"), _backends(), _measurements(measurements) + { + for (const auto b : backends) + { + _backends.emplace(b->config()->id(), b); + } + loadOperationsExecTime(); + }; + /** + * @brief Update _operations_exec_time_file with new data. + */ + void uploadOperationsExecTime() const; + +private: + ///@brief file containing measurements + std::string _measurement_file; + std::unordered_map _backends; + std::unordered_map< + const backend::Backend *, + std::unordered_map>>> + &_measurements; + /** + * @brief Helper function for inserting data to OperationExecTimes + * + * @param backend String name of backend + * @param operation String name of operation + * @param quant if input type quantized + * @param stream File stream + */ + void readOperation(const std::string &backend, const std::string &operation, bool quant, + std::ifstream &stream); + + /** + * @brief Helper function for writing OperationExecTimes to stream + * + * @param operation_info Map of operations execution information + * @param stream File stream + */ + void printOperation(const std::map &operation_info, + std::ofstream &stream) const; + /** + * @brief Parse and load operations_exec_time from _operations_exec_time_file. + */ + void loadOperationsExecTime(); +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_JSON_EXEC_TIME_H__ diff --git a/runtime/onert/core/include/exec/NopFunction.h b/runtime/onert/core/include/exec/NopFunction.h new file mode 100644 index 000000000..df9537cb5 --- /dev/null +++ b/runtime/onert/core/include/exec/NopFunction.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file NopFunction.h + * @brief This file defines NopFunction + */ +#ifndef __ONERT_EXEC_NOP_FUNCTION_H_ +#define __ONERT_EXEC_NOP_FUNCTION_H_ + +#include "IFunction.h" + +namespace onert +{ +namespace exec +{ + +/** + * @brief A derivative of IFunction tha does nothing + * + */ +class NopFunction : public IFunction +{ +public: + NopFunction() = default; + void run() override + { + // DO NOTHING + } + void runSync() override + { + // this abstract method is used just for profiling and called for + // backend::acl_common::AclFunction + run(); + } +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_NOP_FUNCTION_H_ diff --git a/runtime/onert/core/include/interp/InterpExecutor.h b/runtime/onert/core/include/interp/InterpExecutor.h new file mode 100644 index 000000000..2e3f3ca54 --- /dev/null +++ b/runtime/onert/core/include/interp/InterpExecutor.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file InterpExecutor.h + * @brief This file contains InterpExecutor class\n + * to manage interpreter execution and environment + */ +#ifndef __ONERT_INTERP_INTERP_EXECUTOR_H__ +#define __ONERT_INTERP_INTERP_EXECUTOR_H__ + +#include "ir/OperandIndexMap.h" +#include "ir/Graph.h" +#include "exec/IExecutor.h" + +namespace onert +{ +namespace interp +{ + +class ITensor; + +/** + * @brief Class to execute model using interpreter + */ +class InterpExecutor final : public exec::IExecutor +{ +public: + explicit InterpExecutor(const ir::Graph &graph) : _graph(graph) + { + // DO NOTHING + } + +public: + /** + * @brief Return graph object + * @return Graph object + */ + const ir::Graph &graph() final { return _graph; } + void setIndexedRanks(std::shared_ptr>) override{ + // Not implemented + }; + /** + * @brief Start execution + * @note It should be called after setting input and output buffer + */ + void execute(const exec::IODescription &desc) final; + +private: + const ir::Graph &_graph; + ir::OperandIndexMap> _tensor_map; +}; + +} // namespace interp +} // namespace onert + +#endif // __ONERT_INTERP_INTERP_EXECUTOR_H__ diff --git a/runtime/onert/core/include/ir/BackendSet.h b/runtime/onert/core/include/ir/BackendSet.h new file mode 100644 index 000000000..dc635bdaf --- /dev/null +++ b/runtime/onert/core/include/ir/BackendSet.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_BACKEND_SET_H__ +#define __ONERT_IR_BACKEND_SET_H__ + +#include "util/Set.h" + +namespace onert +{ +namespace backend +{ +class Backend; +} // namespace backend +} // namespace onert + +namespace onert +{ +namespace ir +{ + +using BackendSet = util::Set; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_BACKEND_SET_H__ diff --git a/runtime/onert/core/include/ir/Coordinates.h b/runtime/onert/core/include/ir/Coordinates.h new file mode 100644 index 000000000..6938fecef --- /dev/null +++ b/runtime/onert/core/include/ir/Coordinates.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_COORDINATES_H__ +#define __ONERT_IR_COORDINATES_H__ + +#include +#include +#include + +#include "Layout.h" + +namespace onert +{ +namespace ir +{ + +/** + * @brief Class to represent position(offset) of tensor.\n + * Assume that the front is higher dimensional. + * i.g. N: 0, C: 1, H: 2, W: 3 for NCHW layout + */ +class Coordinates final +{ +public: + static constexpr size_t num_max_dimensions = 4; + +public: + /** + * @brief Construct a new Coordinates object with zero dimension + * @return N/A + */ + Coordinates() = default; + /** + * @brief Construct a new Coordinates object + * @param[in] init The initialzer_list with coordinates + * @return + */ + Coordinates(std::initializer_list init) : _coordinates{init} + { + assert(init.size() <= num_max_dimensions); + } + +public: + /** + * @brief Set the coordinate of one of the coordinates. + * + * @param[in] dimension Dimension for which the coordinate is set. + * @param[in] Coordinate Coordinate to be set for the dimension. + */ + void set(size_t dimension, int32_t coordinate) + { + assert(dimension < num_max_dimensions); + if (dimension >= _coordinates.size()) + { + _coordinates.resize(dimension + 1, 0); + } + _coordinates[dimension] = coordinate; + } + +public: + /** + * @brief Return size of coordinates + * + * @return size of coordinates + */ + size_t size() const { return _coordinates.size(); } + +public: + int32_t operator[](size_t dimension) const + { + assert(dimension < _coordinates.size()); + return _coordinates[dimension]; + } + +public: + /** + * @brief begin() of const_iterator for this class + * + * @return The first iterator of the coordinates + */ + std::vector::const_iterator begin() const { return _coordinates.begin(); } + /** + * @brief end() of const_iterator for this class + * + * @return The last iterator of the coordinates + */ + std::vector::const_iterator end() const { return _coordinates.end(); } + +private: + std::vector _coordinates; +}; + +Coordinates convertCoordinates(const Coordinates &from_coordinates, Layout from_layout, + Layout to_layout); + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_COORDINATES_H__ diff --git a/runtime/onert/core/include/ir/Data.h b/runtime/onert/core/include/ir/Data.h new file mode 100644 index 000000000..c85eb4847 --- /dev/null +++ b/runtime/onert/core/include/ir/Data.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_DATA_H__ +#define __ONERT_IR_DATA_H__ + +#include + +namespace onert +{ +namespace ir +{ + +struct Data +{ + virtual ~Data() = default; + + virtual size_t size(void) const = 0; + virtual const uint8_t *base(void) const = 0; +}; + +class CachedData final : public Data +{ +public: + CachedData(const uint8_t *base, size_t size) : _base{new uint8_t[size]}, _size{size} + { + std::copy(base, base + size, _base); + } + +public: + ~CachedData() { delete[] _base; } + +public: + size_t size(void) const override { return _size; } + const uint8_t *base(void) const override { return _base; } + +private: + uint8_t *_base; + size_t _size; +}; + +class ExternalData final : public Data +{ +public: + ExternalData(const uint8_t *base, size_t size) : _base{base}, _size{size} + { + // DO NOTHING + } + +public: + size_t size(void) const override { return _size; } + const uint8_t *base(void) const override { return _base; } + +private: + const uint8_t *_base; + const size_t _size; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_DATA_H__ diff --git a/runtime/onert/core/include/ir/DataType.h b/runtime/onert/core/include/ir/DataType.h new file mode 100644 index 000000000..f706d1375 --- /dev/null +++ b/runtime/onert/core/include/ir/DataType.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_DATATYPE_H__ +#define __ONERT_IR_DATATYPE_H__ + +#include + +namespace onert +{ +namespace ir +{ + +enum class DataType +{ + FLOAT32 = 0, + INT32 = 1, + UINT32 = 2, + QUANT8_ASYMM = 3, + BOOL8 = 4, + UINT8 = 5, + QUANT8_SYMM = 6, +}; + +inline size_t sizeOfDataType(DataType data_type) +{ + switch (data_type) + { + case DataType::FLOAT32: + return sizeof(float); + case DataType::INT32: + return sizeof(int32_t); + case DataType::UINT32: + return sizeof(uint32_t); + case DataType::BOOL8: + case DataType::QUANT8_ASYMM: + case DataType::UINT8: + return sizeof(uint8_t); + case DataType::QUANT8_SYMM: + return sizeof(int8_t); + default: + throw std::runtime_error{"Unsupported type size"}; + } +} + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_DATATYPE_H__ diff --git a/runtime/onert/core/include/ir/Graph.h b/runtime/onert/core/include/ir/Graph.h new file mode 100644 index 000000000..a61d1861c --- /dev/null +++ b/runtime/onert/core/include/ir/Graph.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_GRAPH_H__ +#define __ONERT_IR_GRAPH_H__ + +#include +#include + +#include "ir/Operands.h" +#include "ir/Operations.h" +#include "ir/OpSequence.h" +#include "ir/OpSequences.h" + +namespace onert +{ +namespace backend +{ +namespace custom +{ +class IKernelBuilder; +} // namespace custom +} // namespace backend +} // namespace onert + +namespace onert +{ +namespace ir +{ + +class Graph +{ +private: + enum class Phase + { + BUILDING, + MODEL + }; + +public: + Graph(void); + ~Graph(void); + + // Graph Building +public: + OperandIndex addOperand(const Shape &shape, const TypeInfo &type); + OperationIndex addOperation(std::unique_ptr &&node); + void setOperandValue(const OperandIndex &ind, std::shared_ptr data); + void addInput(const OperandIndex &ind); + void addOutput(const OperandIndex &ind); + void finishBuilding(void); + void removeOperand(const OperandIndex &ind) { _operands.remove(ind); } + bool isBuildingPhase(void) const { return _phase == Phase::BUILDING; } + void setLayout(Layout layout) { _layout = layout; } + +private: + void initializeUseDef(); + + // Custom operations support +public: + void + bindKernelBuilder(const std::shared_ptr &kernel_builder) + { + _kernel_builder = kernel_builder; + } + + const std::shared_ptr &getKernelBuilder() const + { + return _kernel_builder; + } + +private: + std::shared_ptr _kernel_builder; + + // Accessors +public: + const OperandIndexSequence &getInputs() const { return _inputs; } + OperandIndexSequence &getInputs() { return _inputs; } + const OperandIndexSequence &getOutputs() const { return _outputs; } + OperandIndexSequence &getOutputs() { return _outputs; } + const Operands &operands() const { return _operands; } + Operands &operands() { return _operands; } // TODO Remove this non-const accessor + const Operations &operations() const { return _operations; } + Operations &operations() { return _operations; } + Layout layout() { return _layout; } + +private: + Phase _phase{Phase::BUILDING}; + Operations _operations; + Operands _operands; + OperandIndexSequence _inputs; + OperandIndexSequence _outputs; + std::unordered_map> _subgraphs; + // TFLite and circle's default layout is NHWC; + Layout _layout{Layout::NHWC}; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_GRAPH_H__ diff --git a/runtime/onert/core/include/ir/Index.h b/runtime/onert/core/include/ir/Index.h new file mode 100644 index 000000000..4f04546bc --- /dev/null +++ b/runtime/onert/core/include/ir/Index.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERAND_INDEX_H__ +#define __ONERT_IR_OPERAND_INDEX_H__ + +#include "util/Index.h" + +namespace onert +{ +namespace ir +{ + +struct OperationIndexTag; +using OperationIndex = ::onert::util::Index; + +struct OperandIndexTag; +using OperandIndex = ::onert::util::Index; + +struct IOIndexTag; +using IOIndex = ::onert::util::Index; + +struct OpSequenceIndexTag; +using OpSequenceIndex = ::onert::util::Index; + +struct SubgraphIndexTag; +using SubgraphIndex = ::onert::util::Index; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERAND_INDEX_H__ diff --git a/runtime/onert/core/include/ir/InternalType.h b/runtime/onert/core/include/ir/InternalType.h new file mode 100644 index 000000000..e42db72cf --- /dev/null +++ b/runtime/onert/core/include/ir/InternalType.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_INTERNAL_TYPE_H__ +#define __ONERT_IR_INTERNAL_TYPE_H__ + +#include + +namespace onert +{ +namespace ir +{ + +enum class Activation +{ + NONE = 0, + RELU = 1, + RELU1 = 2, + RELU6 = 3, + TANH = 4, + SIGMOID = 5 +}; + +struct Stride +{ + uint32_t vertical; + uint32_t horizontal; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_INTERNAL_TYPE_H__ diff --git a/runtime/onert/core/include/ir/Layout.h b/runtime/onert/core/include/ir/Layout.h new file mode 100644 index 000000000..082810172 --- /dev/null +++ b/runtime/onert/core/include/ir/Layout.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_LAYOUT_H__ +#define __ONERT_IR_LAYOUT_H__ + +#include +#include + +namespace onert +{ +namespace ir +{ + +enum class Layout +{ + UNKNOWN = 0, + NHWC, + NCHW +}; + +inline std::string to_string(Layout layout) +{ + switch (layout) + { + case Layout::NHWC: + return std::string{"NHWC"}; + case Layout::NCHW: + return std::string{"NCHW"}; + case Layout::UNKNOWN: + return std::string{"UNKNOWN"}; + default: + throw std::runtime_error("WRONG LAYOUT"); + } +} + +} // namespace ir +} // namespace onert + +namespace std +{ + +template <> struct hash +{ + size_t operator()(onert::ir::Layout value) const noexcept + { + using type = typename std::underlying_type::type; + return hash()(static_cast(value)); + } +}; + +} // namespace std + +#endif // __ONERT_IR_LAYOUT_H__ diff --git a/runtime/onert/core/include/ir/LowerInfoMap.h b/runtime/onert/core/include/ir/LowerInfoMap.h new file mode 100644 index 000000000..b42417092 --- /dev/null +++ b/runtime/onert/core/include/ir/LowerInfoMap.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_LOWER_INFO_MAP_H__ +#define __ONERT_IR_LOWER_INFO_MAP_H__ + +#include +#include + +#include "ir/operand/LowerInfo.h" +#include "ir/operation/LowerInfo.h" +#include "ir/OperandIndexMap.h" +#include "ir/Index.h" + +namespace onert +{ +namespace ir +{ + +struct LowerInfoMap +{ + std::unordered_map> operation; + OperandIndexMap> operand; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_LOWER_INFO_MAP_H__ diff --git a/runtime/onert/core/include/ir/LoweredGraph.h b/runtime/onert/core/include/ir/LoweredGraph.h new file mode 100644 index 000000000..41d9d962e --- /dev/null +++ b/runtime/onert/core/include/ir/LoweredGraph.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_LOWERED_GRAPH_H__ +#define __ONERT_IR_LOWERED_GRAPH_H__ + +#include "ir/Graph.h" +#include "ir/LowerInfoMap.h" +#include "ir/OpSequences.h" +#include "compiler/BackendResolver.h" +#include "compiler/Compiler.h" + +namespace onert +{ +namespace ir +{ + +class LoweredGraph +{ +public: + LoweredGraph(const Graph &graph, const compiler::CompilerOptions &options); + + Graph &graph() { return _graph; } + const Graph &graph() const { return _graph; } + const LowerInfoMap *getLowerInfo() const { return &_lower_info_map; } + const operation::LowerInfo *getLowerInfo(const OpSequenceIndex &op_seq_index) const; + void setLowerInfo(const OpSequenceIndex &op_seq_index, + std::unique_ptr &&lower_info); + void removeLowerInfo(const OpSequenceIndex &op_seq_index); + const operand::LowerInfo *getLowerInfo(const OperandIndex &index) const; + operand::LowerInfo *getLowerInfo(const OperandIndex &index); + void setLowerInfo(const OperandIndex &index, std::unique_ptr &&lower_info); + void removeLowerInfo(const OperandIndex &index); + OpSequences &op_seqs() { return _op_seqs; } + const OpSequences &op_seqs() const { return _op_seqs; } + const backend::BackendContexts &backend_contexts() { return _backend_contexts; } + const backend::BackendContexts &backend_contexts() const { return _backend_contexts; } + std::shared_ptr> indexed_ranks() { return _indexed_ranks; } + +private: + void makeOpSequences(OperandIndexMap> &operands_lower_info, + const compiler::CompilerOptions &options); + + void + manipulateLowerInfo(OperandIndexMap> &operands_lower_info); + void dumpLowerInfo(); + bool mergeable(const OpSequenceIndex &op_seq_index, const OperationIndex &node_index, + Layout layout); + OpSequenceIndex appendFreshSingleOpSequence(const OperationIndex &node_index, + const Operation &node); + +private: + Graph _graph; + backend::BackendContexts _backend_contexts; + std::unique_ptr _backend_resolver; // TODO Remove this + std::shared_ptr> _indexed_ranks; + LowerInfoMap _lower_info_map; + // Pass(for Perm) can accept only graph so that Graph has OpSequences as a member + OpSequences _op_seqs; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_LOWERED_GRAPH_H__ diff --git a/runtime/onert/core/include/ir/OpCode.h b/runtime/onert/core/include/ir/OpCode.h new file mode 100644 index 000000000..f22b36349 --- /dev/null +++ b/runtime/onert/core/include/ir/OpCode.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OP_CODE_H__ +#define __ONERT_IR_OP_CODE_H__ + +#include +#include + +namespace onert +{ +namespace ir +{ + +enum class OpCode +{ + Invalid, //< Unused +#define OP(Name) Name, //< All operations +#include "ir/Operations.lst" +#undef OP + COUNT +}; + +const char *toString(OpCode opcode); + +} // namespace ir +} // namespace onert + +namespace std +{ + +template <> struct hash +{ + size_t operator()(onert::ir::OpCode value) const noexcept + { + using type = typename std::underlying_type::type; + return hash()(static_cast(value)); + } +}; + +} // namespace std + +#endif // __ONERT_IR_OP_CODE_H__ diff --git a/runtime/onert/core/include/ir/OpSequence.h b/runtime/onert/core/include/ir/OpSequence.h new file mode 100644 index 000000000..1ca231384 --- /dev/null +++ b/runtime/onert/core/include/ir/OpSequence.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OP_SEQUENCE_H__ +#define __ONERT_IR_OP_SEQUENCE_H__ + +#include +#include +#include + +#include "ir/Layout.h" +#include "ir/Index.h" +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ + +// To support ValueSwappable, Element doesn't have members which are classes +// as value(or can have members which are classes as value and the classes +// support Swappable) +struct Element +{ + OperationIndex index; + const Operation *node; + + Element(const OperationIndex *i, const Operation *n) : index{*i}, node{n} + { + // DO NOTHING + } +}; + +class OpSequence +{ +public: + explicit OpSequence(Layout layout); + OpSequence(const OpSequence &) = delete; + +public: + void accept(OperationVisitor &v) const; + +public: + const OperandIndexSequence &getInputs() const { return _inputs; } + const OperandIndexSequence &getOutputs() const { return _outputs; } + void setInputs(const OperandIndexSequence &indexes) { _inputs = indexes; } + void setOutputs(const OperandIndexSequence &indexes) { _outputs = indexes; } + void replaceInput(const OperandIndex &from, const OperandIndex &to) { _inputs.replace(from, to); } + void replaceOutput(const OperandIndex &from, const OperandIndex &to) + { + _outputs.replace(from, to); + } + + void appendOperation(const OperationIndex &index, const Operation &node) + { + _operations.emplace_back(&index, &node); + } + + std::vector &operations(void) { return _operations; } + + const std::vector &operations(void) const { return _operations; } + + uint32_t size(void) const { return _operations.size(); } + + // TODO: Impl Dumper instead of this method + std::string getStr(void) const; + +public: + void remove(const OperationIndex &index); + +public: + Layout getLayout() const { return _layout; } + +public: + std::vector::const_iterator begin() const { return _operations.begin(); } + std::vector::const_iterator end() const { return _operations.end(); } + +private: + bool exist(const OperationIndex &index) const; + +private: + OperandIndexSequence _inputs; + OperandIndexSequence _outputs; + std::vector _operations; + +private: + Layout _layout; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OP_SEQUENCE_H__ diff --git a/runtime/onert/core/include/ir/OpSequences.h b/runtime/onert/core/include/ir/OpSequences.h new file mode 100644 index 000000000..2af9579b7 --- /dev/null +++ b/runtime/onert/core/include/ir/OpSequences.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OP_SEQUENCES_H__ +#define __ONERT_IR_OP_SEQUENCES_H__ + +#include "ir/Index.h" +#include "ir/OpSequence.h" +#include "util/ObjectManager.h" + +namespace onert +{ +namespace ir +{ + +/** + * @brief Class that manages OpSequence objects + */ +class OpSequences : public util::ObjectManager +{ +public: + /** + * @brief Create an instance of OpSequence with given op and push it to objects + * + * @param[in] op_idx Operation index that is emplaced + * @param[in] op Operation that is emplaced + * @param[in] layout OpSequence's layout + * @return OpSequenceIndex + */ + OpSequenceIndex emplace(const OperationIndex &op_index, const Operation &op, Layout layout); + + /** + * @brief Push an instance of OpSequence to objects + * + * @param[in] op_seq An instance of OpSequence + * @return OpSequenceIndex + */ + OpSequenceIndex emplace(std::unique_ptr &&op_seq); + + /** + * @brief Check if an operation does exist in any OpSequences + * + * @param operation_index Operation index to find + * @return true If such operation exists in any OpSequences otherwise false + */ + bool containsOperation(const OperationIndex &operation_index) const; + /** + * @brief Find an operation from all OpSequences + * + * @param operation_index Operation index to find + * @return OpSequenceIndex Index of OpSequence that contains given operation index + */ + OpSequenceIndex getOperation(const OperationIndex &operation_index) const; + /** + * @brief Dump OpSequences + * + * @param msg Message that will be displayed + */ + void dump(const std::string &msg) const; + /** + * @brief Remove an operation from OpSequence + * + * @param operation_index Operation index to be removed + */ + void removeFromOpSequence(const OperationIndex &operation_index); + +private: + OpSequenceIndex findOperation(const OperationIndex &operation_index) const; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OP_SEQUENCES_H__ diff --git a/runtime/onert/core/include/ir/Operand.h b/runtime/onert/core/include/ir/Operand.h new file mode 100644 index 000000000..3b6de9d15 --- /dev/null +++ b/runtime/onert/core/include/ir/Operand.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERAND_H__ +#define __ONERT_IR_OPERAND_H__ + +#include +#include +#include +#include + +#include "ir/Data.h" +#include "ir/DataType.h" +#include "ir/OperandInfo.h" +#include "ir/OperationIndexList.h" + +namespace onert +{ +namespace ir +{ + +class Operand +{ +public: + explicit Operand(const Shape &shape, const TypeInfo &type) : _info{shape, type}, _const{false} + { + // DO NOTHING + } + +public: + const Shape &shape(void) const { return _info.shape(); } + const TypeInfo &typeInfo(void) const { return _info.typeInfo(); } + const OperandInfo &info(void) const { return _info; } + OperandInfo &info(void) { return _info; } + size_t operandSize(void) const; + + const OperationIndexList &getUses() const { return _uses; } + const OperationIndexList &getDef() const { return _def; } + void appendUse(const OperationIndex &idx); + void removeUse(const OperationIndex &idx); + void appendDef(const OperationIndex &idx); + void removeDef(const OperationIndex &idx); + +public: + void type(const DataType type) { _info.type(type); }; + +public: + void data(std::shared_ptr &&data) + { + _data = std::move(data); + _const = true; + } + const Data *data(void) const { return _data.get(); } + + void releaseData(void) { _data.reset(); } + + /** + * @brief Get true if Operand is const, otherwise @c false + a @return @c true if Operand is const, otherwise @c false + */ + bool isConstant(void) const { return _const; } + +public: + template void data(Args &&... args) + { + data(std::make_unique(std::forward(args)...)); + } + +public: + template T asScalar(void) const + { + assert((shape().rank() == 0) || ((shape().rank() == 1) && (shape().dim(0) == 1))); + assert(_data != nullptr); + assert((_data->base() != nullptr) && (_data->size() == sizeof(T))); + + return *(reinterpret_cast(_data->base())); + } + + template std::vector asVector() const + { + assert(_data != nullptr); + assert(_data->size() % sizeof(T) == 0); + + const auto *base = reinterpret_cast(_data->base()); + const std::size_t size = _data->size() / sizeof(T); + return std::vector(base, base + size); + } + +private: + OperandInfo _info; + std::shared_ptr _data; + bool _const; + + OperationIndexList _uses; + OperationIndexList _def; // size is 0 (constant) or 1 (from def operation) +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERAND_H__ diff --git a/runtime/onert/core/include/ir/OperandConstraint.h b/runtime/onert/core/include/ir/OperandConstraint.h new file mode 100644 index 000000000..8da922bea --- /dev/null +++ b/runtime/onert/core/include/ir/OperandConstraint.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_MODEL_OPERAND_CONSTRAINT_H__ +#define __ONERT_MODEL_OPERAND_CONSTRAINT_H__ + +#include +#include +#include + +namespace onert +{ +namespace ir +{ + +class OperandConstraint +{ +private: + static const uint32_t INF = std::numeric_limits::max(); + +public: + static OperandConstraint createAny() { return OperandConstraint{0u, INF}; } + static OperandConstraint createExact(uint32_t exact) { return OperandConstraint{exact, exact}; } + static OperandConstraint createAtMost(uint32_t end) { return OperandConstraint{0u, end}; } + static OperandConstraint createAtLeast(uint32_t begin) { return OperandConstraint{begin, INF}; } + static OperandConstraint createInRange(uint32_t begin, uint32_t end) + { + return OperandConstraint{begin, end}; + } + +private: + OperandConstraint(uint32_t begin, uint32_t end) : _begin{begin}, _end{end} {} + +public: + bool check(uint32_t ind) const { return _begin <= ind && ind <= _end; } + +private: + uint32_t _begin; + uint32_t _end; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_MODEL_OPERAND_CONSTRAINT_H__ diff --git a/runtime/onert/core/include/ir/OperandIndexMap.h b/runtime/onert/core/include/ir/OperandIndexMap.h new file mode 100644 index 000000000..468162ffb --- /dev/null +++ b/runtime/onert/core/include/ir/OperandIndexMap.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERAND_INDEX_MAP_H__ +#define __ONERT_IR_OPERAND_INDEX_MAP_H__ + +#include + +#include "ir/Index.h" + +namespace onert +{ +namespace ir +{ + +template using OperandIndexMap = std::unordered_map; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERAND_INDEX_MAP_H__ diff --git a/runtime/onert/core/include/ir/OperandIndexSequence.h b/runtime/onert/core/include/ir/OperandIndexSequence.h new file mode 100644 index 000000000..1f5ab3d0a --- /dev/null +++ b/runtime/onert/core/include/ir/OperandIndexSequence.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_MODEL_OPERAND_INDEX_SEQUENCE_H__ +#define __ONERT_MODEL_OPERAND_INDEX_SEQUENCE_H__ + +#include +#include + +#include "ir/Index.h" + +namespace onert +{ +namespace ir +{ + +class OperandIndexSequence +{ +public: + OperandIndexSequence(void) = default; + OperandIndexSequence(std::initializer_list list); + OperandIndexSequence(std::initializer_list list); + OperandIndexSequence(std::initializer_list list); + +public: + void append(const OperandIndex &index) { _set.emplace_back(index); } + void append(const OperandIndexSequence &l) { _set.insert(_set.end(), l.begin(), l.end()); } + +public: + uint32_t size() const { return static_cast(_set.size()); } + const OperandIndex &at(IOIndex set_index) const { return _set.at(set_index.value()); } + const OperandIndex &at(uint32_t index) const { return _set.at(index); } + bool contains(const OperandIndex &index) const; + void replace(const OperandIndex &from, const OperandIndex &to); + +public: + OperandIndexSequence operator+(const OperandIndexSequence &other) const; + +public: + std::vector::const_iterator begin(void) const { return _set.begin(); } + std::vector::const_iterator end(void) const { return _set.end(); } + +private: + std::vector _set; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_MODEL_OPERAND_INDEX_SET_H__ diff --git a/runtime/onert/core/include/ir/OperandInfo.h b/runtime/onert/core/include/ir/OperandInfo.h new file mode 100644 index 000000000..6d66f1e12 --- /dev/null +++ b/runtime/onert/core/include/ir/OperandInfo.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file OperandInfo.h + * @brief This file contains OperandInfo class + */ +#ifndef __ONERT_IR_OPERAND_INFO_H__ +#define __ONERT_IR_OPERAND_INFO_H__ + +#include "ir/Shape.h" +#include "ir/TypeInfo.h" +#include "ir/Layout.h" + +namespace onert +{ +namespace ir +{ + +/** + * @brief enum class indicating when the memory for a tensor is allocated + */ +enum class MemAllocType +{ + /** + * @brief At compile time, shape for a tensor is known, thus requried memory capacity can be + * calculated + */ + STATIC, + + /** + * @brief At kernel execution time, shape for a tensor is known, thus requried memory capacity + * can be calculated + */ + DYNAMIC +}; + +/** + * @brief Class to save tensor's shape and type + */ +class OperandInfo +{ +public: + /** + * @brief Construct a new OperandInfo object (deleted) + */ + OperandInfo() = delete; + /** + * @brief Construct a new OperandInfo object + * @param[in] shape Tensor shape + * @param[in] typeInfo Tensor data type + * + * @todo Deprecated this constructor because setting member var implicitly can cause bug later. + * Please use the third constructor. (This constor needs for now not to break previous code) + */ + OperandInfo(const Shape &shape, const TypeInfo &typeInfo) + : _shape(shape), _typeInfo(typeInfo), _alloc_type(MemAllocType::STATIC) + { + // DO NOTHING + } + /** + * @brief Construct a new OperandInfo object + * @param[in] shape Tensor shape + * @param[in] typeInfo Tensor data type + * @param[in] alloc_type When the thesor needs memory allocation + */ + OperandInfo(const Shape &shape, const TypeInfo &typeInfo, MemAllocType alloc_type) + : _shape(shape), _typeInfo(typeInfo), _alloc_type(alloc_type) + { + // DO NOTHING + } + /** + * @brief Construct a new OperandInfo object + * @param[in] origin info for copy + */ + OperandInfo(const OperandInfo &origin) = default; + +public: + /** + * @brief Return tensor shape + * @return Tensor shape + */ + const Shape &shape() const { return _shape; } + /** + * @brief set shape + */ + void shape(const ir::Shape &new_shape) { _shape = new_shape; } + /** + * @brief Return tensor data type info + * @return Tensor data type + */ + const TypeInfo &typeInfo() const { return _typeInfo; } + /** + * @brief Set tensor data type + */ + void type(const DataType type) { _typeInfo.type(type); } + /** + * @brief Return size of tensor (bytes) + * @return Tensor size + */ + size_t total_size() const { return _shape.num_elements() * sizeOfDataType(_typeInfo.type()); } + + MemAllocType memAllocType() const { return _alloc_type; } + void memAllocType(MemAllocType alloc_type) { _alloc_type = alloc_type; } + +private: + Shape _shape; + TypeInfo _typeInfo; + + MemAllocType _alloc_type; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERAND_INFO_H__ diff --git a/runtime/onert/core/include/ir/Operands.h b/runtime/onert/core/include/ir/Operands.h new file mode 100644 index 000000000..be7b7061f --- /dev/null +++ b/runtime/onert/core/include/ir/Operands.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERANDS_H__ +#define __ONERT_IR_OPERANDS_H__ + +#include +#include + +#include "ir/Operand.h" +#include "ir/Index.h" +#include "util/ObjectManager.h" + +namespace onert +{ +namespace ir +{ + +class Operands : public util::ObjectManager +{ +public: + Operands() = default; + Operands(const Operands &obj); + Operands(Operands &&) = default; + Operands &operator=(const Operands &) = delete; + Operands &operator=(Operands &&) = default; + ~Operands() = default; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_MODEL_OPERAND_SET_H__ diff --git a/runtime/onert/core/include/ir/Operation.h b/runtime/onert/core/include/ir/Operation.h new file mode 100644 index 000000000..fb3472923 --- /dev/null +++ b/runtime/onert/core/include/ir/Operation.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_H__ +#define __ONERT_IR_OPERATION_H__ + +#include + +#include "ir/OpCode.h" +#include "ir/Operand.h" +#include "ir/OperandIndexSequence.h" +#include "ir/OperandConstraint.h" + +namespace onert +{ +namespace ir +{ + +struct OperationVisitor; + +class Operation +{ +public: + Operation(OperandConstraint input_constr, const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs); + explicit Operation(OperandConstraint input_constr); + + Operation(const Operation &) = default; + Operation(Operation &&) = default; + Operation &operator=(const Operation &) = default; + Operation &operator=(Operation &&) = default; + + virtual ~Operation(); + +public: + virtual void accept(OperationVisitor &v) const = 0; + virtual std::string name() const { return std::string{toString(opcode())}; } + virtual OpCode opcode() const = 0; + +public: + void replaceInput(const OperandIndex &from, const OperandIndex &to); + void replaceOutput(const OperandIndex &from, const OperandIndex &to); + const OperandIndexSequence &getInputs() const { return _inputs; } + const OperandIndexSequence &getOutputs() const { return _outputs; } + // It's for only input/output tensors but const data. + void setInputs(const OperandIndexSequence &indexes); + void setOutputs(const OperandIndexSequence &indexes); + +private: + OperandConstraint _input_constr; + OperandIndexSequence _inputs; + OperandIndexSequence _outputs; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_H__ diff --git a/runtime/onert/core/include/ir/OperationIndexList.h b/runtime/onert/core/include/ir/OperationIndexList.h new file mode 100644 index 000000000..7863ff29a --- /dev/null +++ b/runtime/onert/core/include/ir/OperationIndexList.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_MODEL_OPERATION_INDEX_LIST_H__ +#define __ONERT_MODEL_OPERATION_INDEX_LIST_H__ + +#include +#include +#include +#include + +#include "ir/Index.h" + +namespace onert +{ +namespace ir +{ + +class OperationIndexList +{ +public: + OperationIndexList(void) = default; + OperationIndexList(std::initializer_list list); + +public: + void append(const OperationIndex &index) { _list.push_back(index); } + void remove(const OperationIndex &index) + { + auto itr = std::find(_list.begin(), _list.end(), index); + assert(itr != _list.end()); + _list.erase(itr); + } + +public: + uint32_t size() const { return static_cast(_list.size()); } + const std::list &list() const { return _list; } + bool contains(const OperationIndex &index) const; + +private: + std::list _list; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_MODEL_OPERATION_INDEX_LIST_H__ diff --git a/runtime/onert/core/include/ir/OperationIndexMap.h b/runtime/onert/core/include/ir/OperationIndexMap.h new file mode 100644 index 000000000..50c21c0ab --- /dev/null +++ b/runtime/onert/core/include/ir/OperationIndexMap.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_INDEX_MAP_H__ +#define __ONERT_IR_OPERATION_INDEX_MAP_H__ + +#include + +#include "ir/Index.h" + +namespace onert +{ +namespace ir +{ + +template using OperationIndexMap = std::unordered_map; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_INDEX_MAP_H__ diff --git a/runtime/onert/core/include/ir/OperationVisitor.h b/runtime/onert/core/include/ir/OperationVisitor.h new file mode 100644 index 000000000..b7e66b935 --- /dev/null +++ b/runtime/onert/core/include/ir/OperationVisitor.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_VISITOR_H__ +#define __ONERT_IR_OPERATION_VISITOR_H__ + +#include "ir/Operations.Include.h" +#include "ir/OpSequence.h" + +namespace onert +{ +namespace ir +{ + +struct OperationVisitor +{ + virtual ~OperationVisitor() = default; + +#define OP(InternalName) \ + virtual void visit(const operation::InternalName &) {} +#include "ir/Operations.lst" +#undef OP + + // This OpSequence node should be handled specially so that + // Op.lst doesn't have OpSequence + // TODO Remove by pushing it down to derived classes. + virtual void visit(const OpSequence &op_seq) + { + for (const auto &e : op_seq.operations()) + { + e.node->accept(*this); + } + } +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_VISITOR_H__ diff --git a/runtime/onert/core/include/ir/Operations.Include.h b/runtime/onert/core/include/ir/Operations.Include.h new file mode 100644 index 000000000..6f14ad9f9 --- /dev/null +++ b/runtime/onert/core/include/ir/Operations.Include.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This file has no ifdef guard intentionally + +#include "ir/operation/BatchToSpaceND.h" +#include "ir/operation/Conv2D.h" +#include "ir/operation/MaxPool2D.h" +#include "ir/operation/AvgPool2D.h" +#include "ir/operation/Concat.h" +#include "ir/operation/Reshape.h" +#include "ir/operation/FullyConnected.h" +#include "ir/operation/Softmax.h" +#include "ir/operation/Transpose.h" +#include "ir/operation/Permute.h" +#include "ir/operation/ReduceSum.h" +#include "ir/operation/Add.h" +#include "ir/operation/Sub.h" +#include "ir/operation/DepthwiseConv2D.h" +#include "ir/operation/Slice.h" +#include "ir/operation/StridedSlice.h" +#include "ir/operation/Mul.h" +#include "ir/operation/Squeeze.h" +#include "ir/operation/Tanh.h" +#include "ir/operation/Logistic.h" +#include "ir/operation/Cast.h" +#include "ir/operation/Div.h" +#include "ir/operation/Exp.h" +#include "ir/operation/ReduceMax.h" +#include "ir/operation/Comparison.h" +#include "ir/operation/LogicalAnd.h" +#include "ir/operation/LogicalOr.h" +#include "ir/operation/LogicalNot.h" +#include "ir/operation/LSTM.h" +#include "ir/operation/RSQRT.h" +#include "ir/operation/ReLU.h" +#include "ir/operation/ResizeBilinear.h" +#include "ir/operation/ReLU1.h" +#include "ir/operation/ReLU6.h" +#include "ir/operation/RNN.h" +#include "ir/operation/Floor.h" +#include "ir/operation/SpaceToBatchND.h" +#include "ir/operation/SpaceToDepth.h" +#include "ir/operation/L2Pool2D.h" +#include "ir/operation/EmbeddingLookup.h" +#include "ir/operation/L2Normalization.h" +#include "ir/operation/HashtableLookup.h" +#include "ir/operation/InstanceNorm.h" +#include "ir/operation/PReLU.h" +#include "ir/operation/TransposeConv.h" +#include "ir/operation/SQRT.h" +#include "ir/operation/SquaredDifference.h" +#include "ir/operation/TopKV2.h" +#include "ir/operation/Gather.h" +#include "ir/operation/Neg.h" +#include "ir/operation/Abs.h" +#include "ir/operation/ArgMax.h" +#include "ir/operation/Dequantize.h" +#include "ir/operation/Mean.h" +#include "ir/operation/LocalResponseNormalization.h" +#include "ir/operation/DepthToSpace.h" +#include "ir/operation/Pack.h" +#include "ir/operation/ReduceMin.h" +#include "ir/operation/Split.h" +#include "ir/operation/Unpack.h" +#include "ir/operation/Pad.h" +#include "ir/operation/Min.h" +#include "ir/operation/Max.h" +#include "ir/operation/Custom.h" +#include "ir/operation/OneHot.h" +#include "ir/operation/Sin.h" +#include "ir/operation/Shape.h" +#include "ir/operation/ConvertFp32ToFp16.h" +#include "ir/operation/ConvertFp16ToFp32.h" diff --git a/runtime/onert/core/include/ir/Operations.h b/runtime/onert/core/include/ir/Operations.h new file mode 100644 index 000000000..0b5fbf529 --- /dev/null +++ b/runtime/onert/core/include/ir/Operations.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATIONS_H__ +#define __ONERT_IR_OPERATIONS_H__ + +#include "ir/Index.h" +#include "ir/Operation.h" +#include "util/ObjectManager.h" + +namespace onert +{ +namespace ir +{ + +class Operations : public util::ObjectManager +{ +public: + Operations() = default; + Operations(const Operations &obj); + Operations(Operations &&) = default; + Operations &operator=(const Operations &) = delete; + Operations &operator=(Operations &&) = default; + ~Operations() = default; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_MODEL_OPERATION_MANAGER_H__ diff --git a/runtime/onert/core/include/ir/Operations.lst b/runtime/onert/core/include/ir/Operations.lst new file mode 100644 index 000000000..de8c8364b --- /dev/null +++ b/runtime/onert/core/include/ir/Operations.lst @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OP +#error Define OP before including this file +#endif + +// Internal Name +OP(Add) +OP(Sub) +OP(BatchToSpaceND) +OP(Cast) +OP(Conv2D) +OP(DepthwiseConv2D) +OP(AvgPool2D) +OP(MaxPool2D) +OP(Concat) +OP(FullyConnected) +OP(ReduceSum) +OP(Reshape) +OP(Mul) +OP(Softmax) +OP(Squeeze) +OP(Slice) +OP(StridedSlice) +OP(Tanh) +OP(Logistic) +OP(Div) +OP(Transpose) +OP(Exp) +OP(ReduceMax) +OP(Comparison) +OP(LogicalAnd) +OP(LogicalOr) +OP(LogicalNot) +OP(LSTM) +OP(RSQRT) +OP(ReLU) +OP(ResizeBilinear) +OP(ReLU1) +OP(ReLU6) +OP(RNN) +OP(Floor) +OP(SpaceToBatchND) +OP(SpaceToDepth) +OP(L2Pool2D) +OP(EmbeddingLookup) +OP(L2Normalization) +OP(HashtableLookup) +OP(InstanceNorm) +OP(PReLU) +OP(TransposeConv) +OP(SQRT) +OP(SquaredDifference) +OP(TopKV2) +OP(Gather) +OP(Neg) +OP(Abs) +OP(ArgMax) +OP(Dequantize) +OP(Mean) +OP(LocalResponseNormalization) +OP(DepthToSpace) +OP(Pack) +OP(ReduceMin) +OP(Split) +OP(Unpack) +OP(Pad) +OP(Custom) +OP(Permute) +OP(Min) +OP(Max) +OP(OneHot) +OP(Sin) +OP(Shape) +OP(ConvertFp32ToFp16) +OP(ConvertFp16ToFp32) diff --git a/runtime/onert/core/include/ir/Padding.h b/runtime/onert/core/include/ir/Padding.h new file mode 100644 index 000000000..b9053914d --- /dev/null +++ b/runtime/onert/core/include/ir/Padding.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_PADDIGN_H__ +#define __ONERT_IR_PADDIGN_H__ + +#include "Shape.h" +#include "InternalType.h" + +#include +#include + +namespace onert +{ +namespace ir +{ + +enum class PaddingType +{ + EXPLICIT = 0, + SAME = 1, + VALID = 2 +}; + +/** + * @brief Converts a internal padding type to const char* + * @param[in] type Padding type to be converted + * @return A string holding the converted value + */ +inline std::string to_string(const PaddingType type); + +struct ExplicitPadding +{ + uint32_t left; + uint32_t right; + uint32_t top; + uint32_t bottom; +}; + +// TODO Resolve explicit padding param at frontend and save in value field +struct Padding +{ + Padding(void); + Padding(PaddingType paddingType); + Padding(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom); + + // TODO Change to private field + PaddingType type; + ExplicitPadding param; +}; + +// TODO Change to Padding struct's method +const ExplicitPadding calculatePadding(const Padding &padding, const FeatureShape &ifm_shape, + const FeatureShape &ofm_shape, const Stride &stride, + uint32_t kw, uint32_t kh); + +} // namespace ir +} // namespace onert + +#endif diff --git a/runtime/onert/core/include/ir/Shape.h b/runtime/onert/core/include/ir/Shape.h new file mode 100644 index 000000000..ebf46c555 --- /dev/null +++ b/runtime/onert/core/include/ir/Shape.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_SHAPE_H__ +#define __ONERT_IR_SHAPE_H__ + +#include "ir/Layout.h" +#include "misc/feature/Shape.h" + +#include +#include + +namespace onert +{ +namespace ir +{ + +// TODO Remove this dependency. +using FeatureShape = nnfw::misc::feature::Shape; + +struct Shape +{ +public: + Shape() = default; + + explicit Shape(int rank) : _dimensions(rank) {} + + Shape(std::initializer_list dimensions) : _dimensions(dimensions) {} + + int rank() const { return _dimensions.size(); } + + const std::vector &dims() const { return _dimensions; } + + int32_t dim(int i) const { return _dimensions.at(i); } + + int32_t &dim(int i) { return _dimensions.at(i); } + + uint64_t num_elements() const; + +public: + FeatureShape asFeature(Layout layout) const; + + /** + * @brief Add dimension to the beginning + * @param[in] d dimension to add to the beginning + */ + void prepend(int32_t d) { _dimensions.insert(_dimensions.cbegin(), d); } + + /** + * @brief Add dimension to the end + * @param[in] d dimension to add to the end + */ + void append(int32_t d) { _dimensions.emplace_back(d); } + + /** + * @brief Extend rank of Shape object for operand with param. + * @param[in] to_rank The rank value to be extended to + */ + void extendRank(int to_rank); + +private: + std::vector _dimensions; +}; + +inline bool operator==(const Shape &lhs, const Shape &rhs) { return lhs.dims() == rhs.dims(); } +inline bool operator!=(const Shape &lhs, const Shape &rhs) { return lhs.dims() != rhs.dims(); } + +Shape permuteShape(const Shape &shape, Layout frontend_layout, Layout backend_layout); + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_SHAPE_H__ diff --git a/runtime/onert/core/include/ir/TypeInfo.h b/runtime/onert/core/include/ir/TypeInfo.h new file mode 100644 index 000000000..07d82b6a7 --- /dev/null +++ b/runtime/onert/core/include/ir/TypeInfo.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_TYPEINFO_H__ +#define __ONERT_IR_TYPEINFO_H__ + +#include + +#include "ir/DataType.h" + +namespace onert +{ +namespace ir +{ + +class TypeInfo +{ +public: + TypeInfo() = delete; + + explicit TypeInfo(DataType type, float scale = 0, int32_t offset = 0) + : _type(type), _scale(scale), _offset(offset) + { + } + +public: + DataType type() const { return _type; } + float scale() const { return _scale; } + int32_t offset() const { return _offset; } + +public: + void type(const DataType type) { _type = type; } + +private: + DataType _type; + float _scale; + int32_t _offset; +}; + +bool operator==(const TypeInfo &lhs, const TypeInfo &rhs); +bool operator!=(const TypeInfo &lhs, const TypeInfo &rhs); + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_TYPEINFO_H__ diff --git a/runtime/onert/core/include/ir/operand/LowerInfo.h b/runtime/onert/core/include/ir/operand/LowerInfo.h new file mode 100644 index 000000000..b7f032b02 --- /dev/null +++ b/runtime/onert/core/include/ir/operand/LowerInfo.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERAND_LOWER_INFO_H__ +#define __ONERT_IR_OPERAND_LOWER_INFO_H__ + +#include +#include + +#include "ir/operand/PermuteFactor.h" +#include "util/Set.h" + +namespace onert +{ +namespace backend +{ +class Backend; +} // namespace backend +} // namespace onert + +namespace onert +{ +namespace ir +{ +namespace operand +{ +using PermuteFactorSet = util::Set; + +class LowerInfo +{ +public: + LowerInfo() + { + // DO NOTHING + } + +public: + const PermuteFactorSet &def_factors(void) const { return _def_factors; } + const PermuteFactorSet &use_factors(void) const { return _use_factors; } + +public: + void addDefPermuteFactor(const PermuteFactor &factor) { _def_factors.add(factor); } + void addUsePermuteFactor(const PermuteFactor &factor) { _use_factors.add(factor); } + void removeDefPermuteFactor(const PermuteFactor &factor) { _def_factors.remove(factor); } + void removeUsePermuteFactor(const PermuteFactor &factor) { _use_factors.remove(factor); } + +private: + PermuteFactorSet _def_factors; + PermuteFactorSet _use_factors; +}; + +} // namespace operand +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERAND_LOWER_INFO_H__ diff --git a/runtime/onert/core/include/ir/operand/PermuteFactor.h b/runtime/onert/core/include/ir/operand/PermuteFactor.h new file mode 100644 index 000000000..d0bfed337 --- /dev/null +++ b/runtime/onert/core/include/ir/operand/PermuteFactor.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file PermuteFactor.h + * @brief This file contains onert::ir::operand::PermuteFactor class + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __ONERT_IR_OPERAND_PERMUTE_FACTOR_H__ +#define __ONERT_IR_OPERAND_PERMUTE_FACTOR_H__ + +#include + +#include "ir/Layout.h" + +namespace onert +{ +namespace backend +{ +class Backend; +} // namespace backend +} // namespace onert + +namespace onert +{ +namespace ir +{ +namespace operand +{ + +/** + * @brief Class that has factors of permutation + */ +class PermuteFactor +{ +public: + /** + * @brief Construct PermuteFactor object. + * @param backend The backend factor + * @param layout The layout factor + */ + PermuteFactor(const backend::Backend *backend, Layout layout) : _backend{backend}, _layout{layout} + { + // DO NOTHING + } + /** + * @brief Construct PermuteFactor object by copy semantics. + */ + PermuteFactor(const PermuteFactor &f) : _backend{f._backend}, _layout{f._layout} + { + // DO NOTHING + } + /** + * @brief Construct PermuteFactor object by move semantics. + */ + PermuteFactor(PermuteFactor &&) = default; + +public: + /** + * @brief Get backend + * + * @return Backend factor + */ + const backend::Backend *backend() const { return _backend; } + /** + * @brief Get layout + * + * @return Layout factor + */ + Layout layout() const { return _layout; } + +public: + /** + * @brief operator overloading function for `==` + * + * @return Whether two PermuteFactor are the same + */ + bool operator==(const PermuteFactor &other) const + { + return _backend == other.backend() && _layout == other.layout(); + } + /** + * @brief operator overloading function for `!=` + * + * @return Whether two PermuteFactor are differenct + */ + bool operator!=(const PermuteFactor &other) const { return !(*this == other); } + +private: + const backend::Backend *_backend{nullptr}; + Layout _layout{Layout::UNKNOWN}; +}; + +} // namespace operand +} // namespace ir +} // namespace onert + +namespace std +{ + +/** + * @brief Structure that provides hash value of PermuteFactor + */ +template <> struct hash +{ + size_t operator()(const onert::ir::operand::PermuteFactor &factor) const noexcept + { + hash b_hash{}; + hash l_hash{}; + return b_hash(factor.backend()) ^ (l_hash(factor.layout()) << 1); + } +}; + +} // namespace std + +#endif // __ONERT_IR_OPERAND_PERMUTE_FACTOR_H__ diff --git a/runtime/onert/core/include/ir/operation/Abs.h b/runtime/onert/core/include/ir/operation/Abs.h new file mode 100644 index 000000000..9126c0027 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Abs.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_ABS_H__ +#define __ONERT_IR_OPERATION_ABS_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Abs : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Abs(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Abs; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_ABS_H__ diff --git a/runtime/onert/core/include/ir/operation/Add.h b/runtime/onert/core/include/ir/operation/Add.h new file mode 100644 index 000000000..5f5f4e0fe --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Add.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_ADD_H__ +#define __ONERT_IR_OPERATION_ADD_H__ + +#include "ir/Operation.h" +#include "ir/InternalType.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Add : public Operation +{ +public: + enum Input + { + LHS = 0, + RHS + }; + + struct Param + { + Activation activation; + }; + +public: + Add(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Add; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_ADD_H__ diff --git a/runtime/onert/core/include/ir/operation/ArgMax.h b/runtime/onert/core/include/ir/operation/ArgMax.h new file mode 100644 index 000000000..b006ea464 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ArgMax.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_ARG_MAX_H__ +#define __ONERT_IR_OPERATION_ARG_MAX_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ArgMax : public Operation +{ +public: + enum Input + { + INPUT + }; + + struct Param + { + int axis; + int rank; + }; + +public: + ArgMax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ArgMax; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_ARG_MAX_H__ diff --git a/runtime/onert/core/include/ir/operation/AvgPool2D.h b/runtime/onert/core/include/ir/operation/AvgPool2D.h new file mode 100644 index 000000000..d5b300a35 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/AvgPool2D.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_AVGPOOL2D_H__ +#define __ONERT_IR_OPERATION_AVGPOOL2D_H__ + +#include + +#include "ir/Operation.h" +#include "ir/InternalType.h" +#include "ir/Padding.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class AvgPool2D : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + uint32_t kh; + uint32_t kw; + + Stride stride; + Padding padding; + Activation activation; + }; + +public: + AvgPool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::AvgPool2D; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_AVGPOOL2D_H__ diff --git a/runtime/onert/core/include/ir/operation/BatchToSpaceND.h b/runtime/onert/core/include/ir/operation/BatchToSpaceND.h new file mode 100644 index 000000000..bb6be57d7 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/BatchToSpaceND.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_BATCH_TO_SPACE_ND_H__ +#define __ONERT_IR_OPERATION_BATCH_TO_SPACE_ND_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class BatchToSpaceND : public Operation +{ +public: + enum Input + { + INPUT = 0, + BLOCK_SIZE = 1 + }; + +public: + BatchToSpaceND(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::BatchToSpaceND; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_BATCH_TO_SPACE_ND_H__ diff --git a/runtime/onert/core/include/ir/operation/Cast.h b/runtime/onert/core/include/ir/operation/Cast.h new file mode 100644 index 000000000..6fb8c105b --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Cast.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_CAST_H__ +#define __ONERT_IR_OPERATION_CAST_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Cast : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Cast(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Cast; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_CAST_H__ diff --git a/runtime/onert/core/include/ir/operation/Comparison.h b/runtime/onert/core/include/ir/operation/Comparison.h new file mode 100644 index 000000000..8b53f163b --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Comparison.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_COMPARISON_H__ +#define __ONERT_IR_OPERATION_COMPARISON_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Comparison : public Operation +{ +public: + enum Input + { + INPUT0 = 0, + INPUT1 + }; + + enum class ComparisonType + { + Equal, + NotEqual, + Greater, + GreaterEqual, + Less, + LessEqual + }; + + struct Param + { + ComparisonType comparison_type; + }; + +public: + Comparison(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Comparison; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_COMPARISON_H__ diff --git a/runtime/onert/core/include/ir/operation/Concat.h b/runtime/onert/core/include/ir/operation/Concat.h new file mode 100644 index 000000000..42b6fbb51 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Concat.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_CONCAT_H__ +#define __ONERT_IR_OPERATION_CONCAT_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Concat : public Operation +{ +public: + struct Param + { + int32_t axis; + int32_t rank; + }; + +public: + Concat(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Concat; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_CONCAT_H__ diff --git a/runtime/onert/core/include/ir/operation/Conv2D.h b/runtime/onert/core/include/ir/operation/Conv2D.h new file mode 100644 index 000000000..e23bf3eb3 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Conv2D.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_CONV2D_H__ +#define __ONERT_IR_OPERATION_CONV2D_H__ + +#include + +#include "ir/Operation.h" +#include "ir/InternalType.h" +#include "ir/Padding.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Conv2D : public Operation +{ +public: + enum Input + { + INPUT = 0, + KERNEL, + BIAS + }; + + struct Param + { + Stride stride; + Padding padding; + Activation activation; + }; + +public: + Conv2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Conv2D; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_CONV2D_H__ diff --git a/runtime/onert/core/include/ir/operation/ConvertFp16ToFp32.h b/runtime/onert/core/include/ir/operation/ConvertFp16ToFp32.h new file mode 100644 index 000000000..15c48357f --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ConvertFp16ToFp32.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_CONVERT_FP16_TO_FP32_H__ +#define __ONERT_IR_OPERATION_CONVERT_FP16_TO_FP32_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ConvertFp16ToFp32 : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + ConvertFp16ToFp32(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ConvertFp16ToFp32; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_CONVERT_FP16_TO_FP32_H__ diff --git a/runtime/onert/core/include/ir/operation/ConvertFp32ToFp16.h b/runtime/onert/core/include/ir/operation/ConvertFp32ToFp16.h new file mode 100644 index 000000000..983ce4891 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ConvertFp32ToFp16.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_CONVERT_FP32_TO_FP16_H__ +#define __ONERT_IR_OPERATION_CONVERT_FP32_TO_FP16_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ConvertFp32ToFp16 : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + ConvertFp32ToFp16(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ConvertFp32ToFp16; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_CONVERT_FP32_TO_FP16_H__ diff --git a/runtime/onert/core/include/ir/operation/Custom.h b/runtime/onert/core/include/ir/operation/Custom.h new file mode 100644 index 000000000..c2a4b354a --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Custom.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ONERT_IR_OPERATION_CUSTOM_H__ +#define __ONERT_IR_OPERATION_CUSTOM_H__ + +#include "ir/Operation.h" + +#include + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Custom : public Operation +{ +public: + struct Userdata + { + char *data; + size_t size; + + Userdata() : data{nullptr}, size{0} {} + Userdata(const Userdata &o) + { + size = o.size; + data = new char[size]; + std::memcpy(data, o.data, size); + } + ~Userdata() { delete[] data; } + }; + + Custom(OperandConstraint input_constr, const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs, std::string id, const Userdata &userdata); + + void accept(OperationVisitor &v) const override; + +public: + /** + * @return unique operation identifier + */ + const std::string &id() const; + + std::string name() const override; + OpCode opcode() const final { return OpCode::Custom; } + + /** + * @return user-provided data + */ + const Userdata &userdata() const; + +private: + std::string _id; + Userdata _userdata; +}; + +} // namespace operation +} // namespace ir +} // namespace onert +#endif // __ONERT_IR_OPERATION_CUSTOM_H__ diff --git a/runtime/onert/core/include/ir/operation/DepthToSpace.h b/runtime/onert/core/include/ir/operation/DepthToSpace.h new file mode 100644 index 000000000..a5315051d --- /dev/null +++ b/runtime/onert/core/include/ir/operation/DepthToSpace.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_DEPTH_TO_SPACE_H__ +#define __ONERT_IR_OPERATION_DEPTH_TO_SPACE_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class DepthToSpace : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + std::int32_t block_size; + }; + +public: + DepthToSpace(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::DepthToSpace; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_DEPTH_TO_SPACE_H__ diff --git a/runtime/onert/core/include/ir/operation/DepthwiseConv2D.h b/runtime/onert/core/include/ir/operation/DepthwiseConv2D.h new file mode 100644 index 000000000..b10bf708c --- /dev/null +++ b/runtime/onert/core/include/ir/operation/DepthwiseConv2D.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_DEPTHWISECONV2D_H__ +#define __ONERT_IR_OPERATION_DEPTHWISECONV2D_H__ + +#include + +#include "ir/Operation.h" +#include "ir/InternalType.h" +#include "ir/Padding.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class DepthwiseConv2D : public Operation +{ +public: + enum Input + { + INPUT = 0, + KERNEL, + BIAS + }; + + struct Param + { + Stride stride; + Padding padding; + uint32_t multiplier; + Activation activation; + }; + +public: + DepthwiseConv2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::DepthwiseConv2D; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_DEPTHWISECONV2D_H__ diff --git a/runtime/onert/core/include/ir/operation/Dequantize.h b/runtime/onert/core/include/ir/operation/Dequantize.h new file mode 100644 index 000000000..97a08b33c --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Dequantize.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_DEQUANTIZE_H__ +#define __ONERT_IR_OPERATION_DEQUANTIZE_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Dequantize : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Dequantize(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Dequantize; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_DEQUANTIZE_H__ diff --git a/runtime/onert/core/include/ir/operation/Div.h b/runtime/onert/core/include/ir/operation/Div.h new file mode 100644 index 000000000..a7ec1c465 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Div.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_DIV_H__ +#define __ONERT_IR_OPERATION_DIV_H__ + +#include "ir/Operation.h" +#include "ir/InternalType.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Div : public Operation +{ +public: + enum Input + { + LHS = 0, + RHS + }; + + struct Param + { + Activation activation; + }; + +public: + Div(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Div; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_DIV_H__ diff --git a/runtime/onert/core/include/ir/operation/EmbeddingLookup.h b/runtime/onert/core/include/ir/operation/EmbeddingLookup.h new file mode 100644 index 000000000..54064faf0 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/EmbeddingLookup.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_EMBEDDING_LOOKUP_H__ +#define __ONERT_IR_OPERATION_EMBEDDING_LOOKUP_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class EmbeddingLookup : public Operation +{ +public: + enum Input + { + LOOKUPS = 0, + VALUES = 1 + }; + +public: + EmbeddingLookup(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::EmbeddingLookup; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_EMBEDDING_LOOKUP_H__ diff --git a/runtime/onert/core/include/ir/operation/Exp.h b/runtime/onert/core/include/ir/operation/Exp.h new file mode 100644 index 000000000..2e68ff07a --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Exp.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_EXP_H__ +#define __ONERT_IR_OPERATION_EXP_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Exp : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Exp(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Exp; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_EXP_H__ diff --git a/runtime/onert/core/include/ir/operation/Floor.h b/runtime/onert/core/include/ir/operation/Floor.h new file mode 100644 index 000000000..b34699c22 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Floor.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_FLOOR_H__ +#define __ONERT_IR_OPERATION_FLOOR_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Floor : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Floor(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Floor; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_FLOOR_H__ diff --git a/runtime/onert/core/include/ir/operation/FullyConnected.h b/runtime/onert/core/include/ir/operation/FullyConnected.h new file mode 100644 index 000000000..b6484ae4d --- /dev/null +++ b/runtime/onert/core/include/ir/operation/FullyConnected.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_FULLYCONNECTED_H__ +#define __ONERT_IR_OPERATION_FULLYCONNECTED_H__ + +#include + +#include "ir/Operation.h" +#include "ir/InternalType.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class FullyConnected : public Operation +{ +public: + enum Input + { + INPUT = 0, + WEIGHT, + BIAS + }; + + struct Param + { + Activation activation; + }; + +public: + FullyConnected(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::FullyConnected; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_FULLYCONNECTED_H__ diff --git a/runtime/onert/core/include/ir/operation/Gather.h b/runtime/onert/core/include/ir/operation/Gather.h new file mode 100644 index 000000000..daa198933 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Gather.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_GATHER_H__ +#define __ONERT_IR_OPERATION_GATHER_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Gather : public Operation +{ +public: + enum Input + { + INPUT = 0, + INDICES, + }; + + struct Param + { + int32_t axis; + int32_t rank; + }; + +public: + Gather(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Gather; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_GATHER_H__ diff --git a/runtime/onert/core/include/ir/operation/HashtableLookup.h b/runtime/onert/core/include/ir/operation/HashtableLookup.h new file mode 100644 index 000000000..4b6cf9362 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/HashtableLookup.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_HASHTABLE_LOOKUP_H__ +#define __ONERT_IR_OPERATION_HASHTABLE_LOOKUP_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class HashtableLookup : public Operation +{ +public: + enum Input + { + LOOKUPS = 0, + KEYS = 1, + VALUES = 2 + }; + + enum Output + { + OUTPUT = 0, + HITS = 1 + }; + +public: + HashtableLookup(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::HashtableLookup; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_HASHTABLE_LOOKUP_H__ diff --git a/runtime/onert/core/include/ir/operation/InstanceNorm.h b/runtime/onert/core/include/ir/operation/InstanceNorm.h new file mode 100644 index 000000000..6a3bb5189 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/InstanceNorm.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_INSTANCE_NORM_H__ +#define __ONERT_IR_OPERATION_INSTANCE_NORM_H__ + +#include "ir/Operation.h" +#include "ir/InternalType.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class InstanceNorm : public Operation +{ +public: + enum Input + { + INPUT = 0, + GAMMA, + BETA + }; + + struct Param + { + Activation activation; + float epsilon; + }; + +public: + InstanceNorm(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::InstanceNorm; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_INSTANCE_NORM_H__ diff --git a/runtime/onert/core/include/ir/operation/L2Normalization.h b/runtime/onert/core/include/ir/operation/L2Normalization.h new file mode 100644 index 000000000..f55301bd6 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/L2Normalization.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_L2_NORMALIZATION_H__ +#define __ONERT_IR_OPERATION_L2_NORMALIZATION_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class L2Normalization : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + struct Param + { + int32_t rank; + }; + +public: + L2Normalization(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::L2Normalization; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_L2_NORMALIZATION_H__ diff --git a/runtime/onert/core/include/ir/operation/L2Pool2D.h b/runtime/onert/core/include/ir/operation/L2Pool2D.h new file mode 100644 index 000000000..d369fd5fc --- /dev/null +++ b/runtime/onert/core/include/ir/operation/L2Pool2D.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_L2_POOL_2D_H__ +#define __ONERT_IR_OPERATION_L2_POOL_2D_H__ + +#include + +#include "ir/Operation.h" +#include "ir/InternalType.h" +#include "ir/Padding.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class L2Pool2D : public Operation +{ +public: + enum Input + { + INPUT = 0, + }; + + struct Param + { + Padding padding; + Stride stride; + uint32_t kw; + uint32_t kh; + Activation activation; + }; + +public: + L2Pool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::L2Pool2D; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_L2_POOL_2D_H__ diff --git a/runtime/onert/core/include/ir/operation/LSTM.h b/runtime/onert/core/include/ir/operation/LSTM.h new file mode 100644 index 000000000..1e6c00bf3 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/LSTM.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ONERT_IR_OPERATION_LSTM_H__ +#define __ONERT_IR_OPERATION_LSTM_H__ + +#include "ir/InternalType.h" +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class LSTM : public Operation +{ +public: + enum Input + { + INPUT = 0, + INPUT_TO_INPUT_WEIGHTS = 1, + INPUT_TO_FORGET_WEIGHTS = 2, + INPUT_TO_CELL_WEIGHTS = 3, + INPUT_TO_OUTPUT_WEIGHTS = 4, + RECURRENT_TO_INPUT_WEIGHTS = 5, + RECURRENT_TO_FORGET_WEIGHTS = 6, + RECURRENT_TO_CELL_WEIGHTS = 7, + RECURRENT_TO_OUTPUT_WEIGHTS = 8, + CELL_TO_INPUT_WEIGHTS = 9, + CELL_TO_FORGET_WEIGHTS = 10, + CELL_TO_OUTPUT_WEIGHTS = 11, + INPUT_GATE_BIAS = 12, + FORGET_GATE_BIAS = 13, + CELL_BIAS = 14, + OUTPUT_GATE_BIAS = 15, + PROJECTION_WEIGHTS = 16, + PROJECTION_BIAS = 17, + OUTPUT_STATE_IN = 18, + CELL_STATE_IN = 19, + }; + + enum Output + { + SCRATCH_BUFFER = 0, + OUTPUT_STATE_OUT = 1, + CELL_STATE_OUT = 2, + OUTPUT = 3 + }; + + struct Param + { + Activation activation; + float cell_threshold; + float projection_threshold; + }; + +public: + LSTM(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::LSTM; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_LSTM_H__ diff --git a/runtime/onert/core/include/ir/operation/LocalResponseNormalization.h b/runtime/onert/core/include/ir/operation/LocalResponseNormalization.h new file mode 100644 index 000000000..2946cfbad --- /dev/null +++ b/runtime/onert/core/include/ir/operation/LocalResponseNormalization.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_LOCAL_RESPONSE_NORMALIZATION_H__ +#define __ONERT_IR_OPERATION_LOCAL_RESPONSE_NORMALIZATION_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class LocalResponseNormalization : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + int radius; + float bias; + float alpha; + float beta; + }; + +public: + LocalResponseNormalization(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::LocalResponseNormalization; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_LOCAL_RESPONSE_NORMALIZATION_H__ diff --git a/runtime/onert/core/include/ir/operation/LogicalAnd.h b/runtime/onert/core/include/ir/operation/LogicalAnd.h new file mode 100644 index 000000000..dc853b6a9 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/LogicalAnd.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_LOGICAL_AND_H__ +#define __ONERT_IR_OPERATION_LOGICAL_AND_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class LogicalAnd : public Operation +{ +public: + enum Input + { + INPUT0 = 0, + INPUT1 = 1, + }; + +public: + LogicalAnd(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::LogicalAnd; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_LOGICAL_AND_H__ diff --git a/runtime/onert/core/include/ir/operation/LogicalNot.h b/runtime/onert/core/include/ir/operation/LogicalNot.h new file mode 100644 index 000000000..9519f6d47 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/LogicalNot.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_LOGICAL_NOT_H__ +#define __ONERT_IR_OPERATION_LOGICAL_NOT_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class LogicalNot : public Operation +{ +public: + enum Input + { + INPUT = 0, + }; + +public: + LogicalNot(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::LogicalNot; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_LOGICAL_NOT_H__ diff --git a/runtime/onert/core/include/ir/operation/LogicalOr.h b/runtime/onert/core/include/ir/operation/LogicalOr.h new file mode 100644 index 000000000..c4b658cd9 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/LogicalOr.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_LOGICAL_OR_H__ +#define __ONERT_IR_OPERATION_LOGICAL_OR_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class LogicalOr : public Operation +{ +public: + enum Input + { + INPUT0 = 0, + INPUT1 = 1, + }; + +public: + LogicalOr(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::LogicalOr; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_LOGICAL_OR_H__ diff --git a/runtime/onert/core/include/ir/operation/Logistic.h b/runtime/onert/core/include/ir/operation/Logistic.h new file mode 100644 index 000000000..5421e1c84 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Logistic.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_LOGISTIC_H__ +#define __ONERT_IR_OPERATION_LOGISTIC_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Logistic : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Logistic(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Logistic; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_LOGISTIC_H__ diff --git a/runtime/onert/core/include/ir/operation/LowerInfo.h b/runtime/onert/core/include/ir/operation/LowerInfo.h new file mode 100644 index 000000000..7ef53b8c7 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/LowerInfo.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_LOWER_INFO_H__ +#define __ONERT_IR_OPERATION_LOWER_INFO_H__ + +#include + +#include + +namespace onert +{ +namespace backend +{ +class Backend; +} // namespace backend +} // namespace onert + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class LowerInfo +{ +public: + LowerInfo(const backend::Backend *backend, Layout layout); + const backend::Backend *backend() const { return _permute_factor.backend(); } + Layout layout() const { return _permute_factor.layout(); } + +private: + operand::PermuteFactor _permute_factor; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_LOWER_INFO_H__ diff --git a/runtime/onert/core/include/ir/operation/Max.h b/runtime/onert/core/include/ir/operation/Max.h new file mode 100644 index 000000000..df72d3ae9 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Max.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_MAX_H__ +#define __ONERT_IR_OPERATION_MAX_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Max : public Operation +{ +public: + enum Input + { + LHS = 0, + RHS + }; + +public: + Max(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Max; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_MAX_H__ diff --git a/runtime/onert/core/include/ir/operation/MaxPool2D.h b/runtime/onert/core/include/ir/operation/MaxPool2D.h new file mode 100644 index 000000000..300f7cb3c --- /dev/null +++ b/runtime/onert/core/include/ir/operation/MaxPool2D.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_MAXPOOL2D_H__ +#define __ONERT_IR_OPERATION_MAXPOOL2D_H__ + +#include + +#include "ir/Operation.h" +#include "ir/InternalType.h" +#include "ir/Padding.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class MaxPool2D : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + uint32_t kh; + uint32_t kw; + Stride stride; + Padding padding; + Activation activation; + }; + +public: + MaxPool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::MaxPool2D; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_MAXPOOL2D_H__ diff --git a/runtime/onert/core/include/ir/operation/Mean.h b/runtime/onert/core/include/ir/operation/Mean.h new file mode 100644 index 000000000..5fe3946d6 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Mean.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_MEAN_H__ +#define __ONERT_IR_OPERATION_MEAN_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Mean : public Operation +{ +public: + enum Input + { + INPUT + }; + + struct Param + { + std::vector axes; + bool keep_dims; + int32_t rank; + }; + +public: + Mean(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Mean; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_MEAN_H__ diff --git a/runtime/onert/core/include/ir/operation/Min.h b/runtime/onert/core/include/ir/operation/Min.h new file mode 100644 index 000000000..117301c00 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Min.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_MIN_H__ +#define __ONERT_IR_OPERATION_MIN_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Min : public Operation +{ +public: + enum Input + { + LHS = 0, + RHS + }; + +public: + Min(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Min; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_MIN_H__ diff --git a/runtime/onert/core/include/ir/operation/Mul.h b/runtime/onert/core/include/ir/operation/Mul.h new file mode 100644 index 000000000..0f01b0ecf --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Mul.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_MUL_H__ +#define __ONERT_IR_OPERATION_MUL_H__ + +#include "ir/Operation.h" +#include "ir/InternalType.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Mul : public Operation +{ +public: + enum Input + { + LHS = 0, + RHS + }; + + struct Param + { + Activation activation; + }; + +public: + Mul(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Mul; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_MUL_H__ diff --git a/runtime/onert/core/include/ir/operation/Neg.h b/runtime/onert/core/include/ir/operation/Neg.h new file mode 100644 index 000000000..f8123c485 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Neg.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_NEG_H__ +#define __ONERT_IR_OPERATION_NEG_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Neg : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Neg(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Neg; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_NEG_H__ diff --git a/runtime/onert/core/include/ir/operation/OneHot.h b/runtime/onert/core/include/ir/operation/OneHot.h new file mode 100644 index 000000000..2cb0d23e1 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/OneHot.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_ONEHOT_H__ +#define __ONERT_IR_OPERATION_ONEHOT_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class OneHot : public Operation +{ +public: + enum Input + { + INDICES = 0, + DEPTH = 1, + ON_VALUE = 2, + OFF_VALUE = 3, + }; + + struct Param + { + int depth; // comes from input tensor, not from OneHotOptions + float on_value; // comes from input tensor, not from OneHotOptions + float off_value; // comes from input tensor, not from OneHotOptions + int axis; + }; + +public: + OneHot(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::OneHot; } + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_ONEHOT_H__ diff --git a/runtime/onert/core/include/ir/operation/PReLU.h b/runtime/onert/core/include/ir/operation/PReLU.h new file mode 100644 index 000000000..2981ffc6a --- /dev/null +++ b/runtime/onert/core/include/ir/operation/PReLU.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_PRELU_H__ +#define __ONERT_IR_OPERATION_PRELU_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class PReLU : public Operation +{ +public: + enum Input + { + INPUT = 0, + ALPHA = 1 + }; + +public: + PReLU(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::PReLU; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_PRELU_H__ diff --git a/runtime/onert/core/include/ir/operation/Pack.h b/runtime/onert/core/include/ir/operation/Pack.h new file mode 100644 index 000000000..39fca49d4 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Pack.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ONERT_IR_OPERATION_PACK_H__ +#define __ONERT_IR_OPERATION_PACK_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ +class Pack : public Operation +{ +public: + struct Param + { + int32_t num; + int32_t axis; + int32_t rank; + }; + +public: + Pack(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Pack; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; +} // namespace operation +} // namespace ir +} // namespace onert +#endif // __ONERT_IR_OPERATION_PACK_H__ diff --git a/runtime/onert/core/include/ir/operation/Pad.h b/runtime/onert/core/include/ir/operation/Pad.h new file mode 100644 index 000000000..18da18bc3 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Pad.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_PAD_H__ +#define __ONERT_IR_OPERATION_PAD_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Pad : public Operation +{ +public: + enum Input + { + INPUT = 0, + PAD = 1, + // VALUE = 2 Not allow padding value operand yet + }; + +public: + struct Param + { + int32_t rank; + }; + +public: + Pad(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Pad; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_PAD_H__ diff --git a/runtime/onert/core/include/ir/operation/Permute.h b/runtime/onert/core/include/ir/operation/Permute.h new file mode 100644 index 000000000..30930d2cc --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Permute.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_PERMUTE_H__ +#define __ONERT_IR_OPERATION_PERMUTE_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace backend +{ +class BackendContext; +} // namespace backend +} // namespace onert + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Permute : public Operation +{ +public: + enum class Type + { + NHWC_TO_NCHW, + NCHW_TO_NHWC, + COPY + }; + + struct Param + { + const backend::BackendContext *input_backend_ctx; + const backend::BackendContext *output_backend_ctx; + }; + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Permute; } + +public: + Permute(const OperandIndex &input, const OperandIndex &output, + const backend::BackendContext *input_backend_ctx, + const backend::BackendContext *output_backend_ctx, Type type, + DataType data_type = DataType::FLOAT32); + +public: + const Param ¶m() const { return _param; } + DataType getDataType() const { return _dataType; } + Type getPermuteType() const { return _type; } + +private: + Param _param; + Type _type; + DataType _dataType; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_PERMUTE_H__ diff --git a/runtime/onert/core/include/ir/operation/RNN.h b/runtime/onert/core/include/ir/operation/RNN.h new file mode 100644 index 000000000..087075da2 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/RNN.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ONERT_IR_OPERATION_RNN_H__ +#define __ONERT_IR_OPERATION_RNN_H__ + +#include "ir/InternalType.h" +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class RNN : public Operation +{ +public: + enum Input + { + INPUT = 0, + WEIGHTS = 1, + RECURRENT_WEIGHTS = 2, + BIAS = 3, + HIDDEN_STATE_IN = 4 + }; + + enum Output + { + OUTPUT = 0, + HIDDEN_STATE_OUT = 1 + }; + + struct Param + { + Activation activation; + }; + +public: + RNN(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::RNN; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_RNN_H__ diff --git a/runtime/onert/core/include/ir/operation/RSQRT.h b/runtime/onert/core/include/ir/operation/RSQRT.h new file mode 100644 index 000000000..64bb4f10a --- /dev/null +++ b/runtime/onert/core/include/ir/operation/RSQRT.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_RSQRT_H__ +#define __ONERT_IR_OPERATION_RSQRT_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class RSQRT : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + RSQRT(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::RSQRT; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_RSQRT_H__ diff --git a/runtime/onert/core/include/ir/operation/ReLU.h b/runtime/onert/core/include/ir/operation/ReLU.h new file mode 100644 index 000000000..9eb0c091b --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ReLU.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_RELU_H__ +#define __ONERT_IR_OPERATION_RELU_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ReLU : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + ReLU(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ReLU; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_RELU_H__ diff --git a/runtime/onert/core/include/ir/operation/ReLU1.h b/runtime/onert/core/include/ir/operation/ReLU1.h new file mode 100644 index 000000000..134ee573a --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ReLU1.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_ReLU1_H__ +#define __ONERT_IR_OPERATION_ReLU1_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ReLU1 : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + ReLU1(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ReLU1; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_ReLU1_H__ diff --git a/runtime/onert/core/include/ir/operation/ReLU6.h b/runtime/onert/core/include/ir/operation/ReLU6.h new file mode 100644 index 000000000..e658c4925 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ReLU6.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_ReLU6_H__ +#define __ONERT_IR_OPERATION_ReLU6_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ReLU6 : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + ReLU6(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ReLU6; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_ReLU6_H__ diff --git a/runtime/onert/core/include/ir/operation/ReduceMax.h b/runtime/onert/core/include/ir/operation/ReduceMax.h new file mode 100644 index 000000000..af4bd5a61 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ReduceMax.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_REDUCEMAX_H__ +#define __ONERT_IR_OPERATION_REDUCEMAX_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ReduceMax : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + std::vector axes; + bool keep_dims; + int32_t rank; + }; + +public: + ReduceMax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ReduceMax; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_REDUCEMAX_H__ diff --git a/runtime/onert/core/include/ir/operation/ReduceMin.h b/runtime/onert/core/include/ir/operation/ReduceMin.h new file mode 100644 index 000000000..46a3e9812 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ReduceMin.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_REDUCEMIN_H__ +#define __ONERT_IR_OPERATION_REDUCEMIN_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ReduceMin : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + std::vector axes; + bool keep_dims; + int32_t rank; + }; + +public: + ReduceMin(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ReduceMin; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_REDUCEMIN_H__ diff --git a/runtime/onert/core/include/ir/operation/ReduceSum.h b/runtime/onert/core/include/ir/operation/ReduceSum.h new file mode 100644 index 000000000..b7374a51d --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ReduceSum.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_REDUCE_SUM_H__ +#define __ONERT_IR_OPERATION_REDUCE_SUM_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ReduceSum : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + std::vector axes; + bool keep_dims; + int32_t rank; + }; + +public: + ReduceSum(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ReduceSum; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_REDUCE_SUM_H__ diff --git a/runtime/onert/core/include/ir/operation/Reshape.h b/runtime/onert/core/include/ir/operation/Reshape.h new file mode 100644 index 000000000..34c212376 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Reshape.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_RESHAPE_H__ +#define __ONERT_IR_OPERATION_RESHAPE_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Reshape : public Operation +{ +public: + enum Input + { + INPUT = 0, + SHAPE = 1 + }; + +public: + Reshape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Reshape; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_RESHAPE_H__ diff --git a/runtime/onert/core/include/ir/operation/ResizeBilinear.h b/runtime/onert/core/include/ir/operation/ResizeBilinear.h new file mode 100644 index 000000000..2887ed845 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/ResizeBilinear.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_RESIZE_BILINEAR_H__ +#define __ONERT_IR_OPERATION_RESIZE_BILINEAR_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class ResizeBilinear : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + int32_t height_out; + int32_t width_out; + }; + +public: + ResizeBilinear(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::ResizeBilinear; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_RESIZE_BILINEAR_H__ diff --git a/runtime/onert/core/include/ir/operation/SQRT.h b/runtime/onert/core/include/ir/operation/SQRT.h new file mode 100644 index 000000000..8563b1ab1 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/SQRT.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SQRT_H__ +#define __ONERT_IR_OPERATION_SQRT_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class SQRT : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + SQRT(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::SQRT; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SQRT_H__ diff --git a/runtime/onert/core/include/ir/operation/Shape.h b/runtime/onert/core/include/ir/operation/Shape.h new file mode 100644 index 000000000..4dea7e424 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Shape.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SHAPE_H__ +#define __ONERT_IR_OPERATION_SHAPE_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Shape : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Shape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Shape; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SHAPE_H__ diff --git a/runtime/onert/core/include/ir/operation/Sin.h b/runtime/onert/core/include/ir/operation/Sin.h new file mode 100644 index 000000000..aef44ab2e --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Sin.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SIN_H__ +#define __ONERT_IR_OPERATION_SIN_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Sin : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Sin(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Sin; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SIN_H__ diff --git a/runtime/onert/core/include/ir/operation/Slice.h b/runtime/onert/core/include/ir/operation/Slice.h new file mode 100644 index 000000000..71e117c9c --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Slice.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SLICE_H__ +#define __ONERT_IR_OPERATION_SLICE_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Slice : public Operation +{ +public: + enum Input + { + INPUT = 0, + BEGINS = 1, + SIZES = 2, + }; + +public: + struct Param + { + int32_t rank; + }; + +public: + Slice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Slice; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SLICE_H__ diff --git a/runtime/onert/core/include/ir/operation/Softmax.h b/runtime/onert/core/include/ir/operation/Softmax.h new file mode 100644 index 000000000..db7ae910e --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Softmax.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SOFTMAX_H__ +#define __ONERT_IR_OPERATION_SOFTMAX_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Softmax : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + float beta; + }; + +public: + Softmax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Softmax; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SOFTMAX_H__ diff --git a/runtime/onert/core/include/ir/operation/SpaceToBatchND.h b/runtime/onert/core/include/ir/operation/SpaceToBatchND.h new file mode 100644 index 000000000..99928ff24 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/SpaceToBatchND.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SPACE_TO_BATCH_ND_H__ +#define __ONERT_IR_OPERATION_SPACE_TO_BATCH_ND_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class SpaceToBatchND : public Operation +{ +public: + enum Input + { + INPUT = 0, + BLOCK_SIZE = 1, + PADDINGS = 2 + }; + +public: + SpaceToBatchND(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::SpaceToBatchND; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SPACE_TO_BATCH_ND_H__ diff --git a/runtime/onert/core/include/ir/operation/SpaceToDepth.h b/runtime/onert/core/include/ir/operation/SpaceToDepth.h new file mode 100644 index 000000000..6c8b09130 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/SpaceToDepth.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SPACE_TO_DEPTH_H__ +#define __ONERT_IR_OPERATION_SPACE_TO_DEPTH_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class SpaceToDepth : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + std::int32_t block_size; + }; + +public: + SpaceToDepth(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::SpaceToDepth; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SPACE_TO_DEPTH_H__ diff --git a/runtime/onert/core/include/ir/operation/Split.h b/runtime/onert/core/include/ir/operation/Split.h new file mode 100644 index 000000000..d17a9813c --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Split.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ONERT_IR_OPERATION_SPLIT_H__ +#define __ONERT_IR_OPERATION_SPLIT_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ +class Split : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + int axis; + int num_splits; + int rank; + }; + +public: + Split(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Split; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; +} // namespace operation +} // namespace ir +} // namespace onert +#endif // __ONERT_IR_OPERATION_SPLIT_H__ diff --git a/runtime/onert/core/include/ir/operation/SquaredDifference.h b/runtime/onert/core/include/ir/operation/SquaredDifference.h new file mode 100644 index 000000000..392b11448 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/SquaredDifference.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SQUARED_DIFFERENCE_H__ +#define __ONERT_IR_OPERATION_SQUARED_DIFFERENCE_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class SquaredDifference : public Operation +{ +public: + enum Input + { + LHS = 0, + RHS + }; + +public: + SquaredDifference(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::SquaredDifference; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SQUARED_DIFFERENCE_H__ diff --git a/runtime/onert/core/include/ir/operation/Squeeze.h b/runtime/onert/core/include/ir/operation/Squeeze.h new file mode 100644 index 000000000..c370472b7 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Squeeze.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SQUEEZE_H__ +#define __ONERT_IR_OPERATION_SQUEEZE_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Squeeze : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + // Please see tensorflow/lite/c/builtin_op_data.h and squeeze.cc. + // tensorflow lite supports only for ndim <= 8. + int dims[8]; + int ndim; + }; + +public: + Squeeze(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Squeeze; } + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SQUEEZE_H__ diff --git a/runtime/onert/core/include/ir/operation/StridedSlice.h b/runtime/onert/core/include/ir/operation/StridedSlice.h new file mode 100644 index 000000000..8c493b21d --- /dev/null +++ b/runtime/onert/core/include/ir/operation/StridedSlice.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_STRIDED_SLICE_H__ +#define __ONERT_IR_OPERATION_STRIDED_SLICE_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class StridedSlice : public Operation +{ +public: + enum Input + { + INPUT = 0, + STARTS = 1, + ENDS = 2, + STRIDES = 3 + }; + + struct Param + { + int32_t begin_mask; + int32_t end_mask; + int32_t shrink_axis_mask; + int32_t rank; + }; + +public: + StridedSlice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::StridedSlice; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_STRIDED_SLICE_H__ diff --git a/runtime/onert/core/include/ir/operation/Sub.h b/runtime/onert/core/include/ir/operation/Sub.h new file mode 100644 index 000000000..0674e6e4d --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Sub.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_SUB_H__ +#define __ONERT_IR_OPERATION_SUB_H__ + +#include "ir/Operation.h" +#include "ir/InternalType.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Sub : public Operation +{ +public: + enum Input + { + LHS = 0, + RHS + }; + + struct Param + { + Activation activation; + }; + +public: + Sub(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Sub; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_SUB_H__ diff --git a/runtime/onert/core/include/ir/operation/Tanh.h b/runtime/onert/core/include/ir/operation/Tanh.h new file mode 100644 index 000000000..9b8d03bca --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Tanh.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_TANH_H__ +#define __ONERT_IR_OPERATION_TANH_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Tanh : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + +public: + Tanh(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Tanh; } +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_TANH_H__ diff --git a/runtime/onert/core/include/ir/operation/TopKV2.h b/runtime/onert/core/include/ir/operation/TopKV2.h new file mode 100644 index 000000000..179a599ca --- /dev/null +++ b/runtime/onert/core/include/ir/operation/TopKV2.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_TOPK_V2_H__ +#define __ONERT_IR_OPERATION_TOPK_V2_H__ + +#include + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class TopKV2 : public Operation +{ +public: + enum Input + { + INPUT + }; + + enum Output + { + OUTPUT_VALUES = 0, + OUTPUT_INDICES, + }; + + struct Param + { + std::int32_t k; + }; + +public: + TopKV2(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::TopKV2; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_TOPK_V2_H__ diff --git a/runtime/onert/core/include/ir/operation/Transpose.h b/runtime/onert/core/include/ir/operation/Transpose.h new file mode 100644 index 000000000..b2e04ca33 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Transpose.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_TRANSPOSE_H__ +#define __ONERT_IR_OPERATION_TRANSPOSE_H__ + +#include "ir/Operation.h" + +#include + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class Transpose : public Operation +{ +public: + enum Input + { + INPUT = 0, // for an n-D tensor, specifying the tensor to be transposed. + }; + + struct Param + { + std::vector perm; + int32_t rank; + }; + +public: + Transpose(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Transpose; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_TRANSPOSE_H__ diff --git a/runtime/onert/core/include/ir/operation/TransposeConv.h b/runtime/onert/core/include/ir/operation/TransposeConv.h new file mode 100644 index 000000000..05137ccf8 --- /dev/null +++ b/runtime/onert/core/include/ir/operation/TransposeConv.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_TRANSPOSE_CONV_H__ +#define __ONERT_IR_OPERATION_TRANSPOSE_CONV_H__ + +#include + +#include "ir/Operation.h" +#include "ir/InternalType.h" +#include "ir/Padding.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +class TransposeConv : public Operation +{ +public: + enum Input + { + OUTPUT_SHAPE = 0, + KERNEL, + INPUT + }; + + struct Param + { + Padding padding; + Stride stride; + }; + +public: + TransposeConv(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::TransposeConv; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; + +} // namespace operation +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_TRANSPOSE_CONV_H__ diff --git a/runtime/onert/core/include/ir/operation/Unpack.h b/runtime/onert/core/include/ir/operation/Unpack.h new file mode 100644 index 000000000..28e91afda --- /dev/null +++ b/runtime/onert/core/include/ir/operation/Unpack.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __ONERT_IR_OPERATION_UNPACK_H__ +#define __ONERT_IR_OPERATION_UNPACK_H__ + +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ +class Unpack : public Operation +{ +public: + enum Input + { + INPUT = 0 + }; + + struct Param + { + int32_t num; + int32_t axis; + int32_t rank; + }; + +public: + Unpack(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m); + +public: + void accept(OperationVisitor &v) const override; + OpCode opcode() const final { return OpCode::Unpack; } + +public: + const Param ¶m() const { return _param; } + +private: + Param _param; +}; +} // namespace operation +} // namespace ir +} // namespace onert +#endif // __ONERT_IR_OPERATION_UNPACK_H__ diff --git a/runtime/onert/core/include/util/Config.lst b/runtime/onert/core/include/util/Config.lst new file mode 100644 index 000000000..75767b8b1 --- /dev/null +++ b/runtime/onert/core/include/util/Config.lst @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CONFIG +#error Define CONFIG before including this file +#endif + +// Name | Type | Default +CONFIG(GRAPH_DOT_DUMP , int , "0") +CONFIG(BACKENDS , std::string , "acl_cl;acl_neon;cpu") +CONFIG(OP_BACKEND_ALLOPS , std::string , "") +CONFIG(OP_BACKEND_MAP , std::string , "") +CONFIG(DISABLE_COMPILE , bool , "0") +CONFIG(ONERT_LOG_ENABLE , bool , "0") +CONFIG(CPU_MEMORY_PLANNER , std::string , "WIC") +CONFIG(EXECUTOR , std::string , "Linear") +CONFIG(ACL_LAYOUT , std::string , "none") +CONFIG(NCNN_LAYOUT , std::string , "NCHW") +CONFIG(PROFILING_MODE , bool , "0") +CONFIG(USE_SCHEDULER , bool , "0") +CONFIG(OP_SEQ_MAX_NODE , int , "0") +CONFIG(TRACE_FILEPATH , std::string , "") +CONFIG(DELETE_CACHED_DATA , bool , "0") + +// Auto-generate all operations + +#define OP(InternalName) \ + CONFIG(OP_BACKEND_ ## InternalName, std::string, "") +#include "ir/Operations.lst" +#undef OP + diff --git a/runtime/onert/core/include/util/ConfigSource.h b/runtime/onert/core/include/util/ConfigSource.h new file mode 100644 index 000000000..b6a8144fd --- /dev/null +++ b/runtime/onert/core/include/util/ConfigSource.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_CONFIG_SOURCE_H__ +#define __ONERT_UTIL_CONFIG_SOURCE_H__ + +#include + +#include "IConfigSource.h" + +namespace onert +{ +namespace util +{ + +void config_source(std::unique_ptr &&source); + +bool toBool(const std::string &val); +int toInt(const std::string &val); + +bool getConfigBool(const std::string &key); +int getConfigInt(const std::string &key); +std::string getConfigString(const std::string &key); + +} // namespace util +} // namespace onert + +namespace onert +{ +namespace util +{ +namespace config +{ + +#define CONFIG(Name, Type, Default) extern const char *Name; + +#include "Config.lst" + +#undef CONFIG + +} // namespace config +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_CONFIG_SOURCE_H__ diff --git a/runtime/onert/core/include/util/EnvConfigSource.h b/runtime/onert/core/include/util/EnvConfigSource.h new file mode 100644 index 000000000..8c5d0e8e9 --- /dev/null +++ b/runtime/onert/core/include/util/EnvConfigSource.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_ENV_CONFIG_SOURCE_H__ +#define __ONERT_UTIL_ENV_CONFIG_SOURCE_H__ + +#include + +#include "util/GeneralConfigSource.h" + +namespace onert +{ +namespace util +{ + +class EnvConfigSource final : public GeneralConfigSource +{ +public: + std::string get(const std::string &key) const override; + +private: + std::unordered_map _default_attributes; +}; + +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_ENV_CONFIG_SOURCE_H__ diff --git a/runtime/onert/core/include/util/EventCollectorGlobal.h b/runtime/onert/core/include/util/EventCollectorGlobal.h new file mode 100644 index 000000000..1f110d906 --- /dev/null +++ b/runtime/onert/core/include/util/EventCollectorGlobal.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_EVENT_COLLECTOR_GLOBAL_H__ +#define __ONERT_UTIL_EVENT_COLLECTOR_GLOBAL_H__ + +#include "misc/EventRecorder.h" +#include "misc/EventCollector.h" + +namespace onert +{ +namespace util +{ + +/** + * @brief Singleton class for event collection from anywhere in code + * + */ +class EventCollectorGlobal +{ +public: + /** + * @brief Get the singleton object of this class + * + * @return EventCollectorGlobal& Singleton object + */ + static EventCollectorGlobal &get(); + +public: + /** + * @brief Getter for event collector object + * + * @return EventCollector& Collector object + */ + EventCollector &collector() { return _collector; } + +private: + EventCollectorGlobal(); + ~EventCollectorGlobal(); + +private: + EventRecorder _recorder; + EventCollector _collector; +}; + +/** + * @brief Helper class for emitting duration event which is handled automatically with ctor/dtor + * + */ +class EventDurationBlock +{ +public: + /** + * @brief Raise a duration event with type of BEGIN + * + * @param tag A label for the duration event + */ + EventDurationBlock(const std::string &tag); + /** + * @brief Raise a duration event with type of END + * + */ + ~EventDurationBlock(); + +private: + std::string _tag; +}; + +/** + * @brief Helper class for emitting duration event which is handled manually + * + * Usage: + * { + * ... + * EventDurationManual duration("some tag"); + * duration.begin(); + * ... + * ... // Code for duration + * ... + * duration.end(); + * } + * + */ +class EventDurationManual +{ +public: + /** + * @brief Construct a new Event Duration Manual object + * + * @param tag A label for the duration object + */ + EventDurationManual(const std::string &tag); + /** + * @brief Destroy the Event Duration Manual object + * + */ + ~EventDurationManual(); + + /** + * @brief Raise a duration event with type of BEGIN + * + */ + void begin(); + /** + * @brief Raise a duration event with type of END + * + */ + void end(); + +private: + std::string _tag; + bool _pair; +}; + +} // namespace util +} // namespace onert + +/** + * Helper Macro Definitions + * + * HOW TO USE + * + * void f(args) + * { + * EVENT_DURATION_FUNCTION(); + * ... + * if(cond) + * { + * EVENT_DURATION_REGION("if branch"); + * ... + * } + * ... + * } + */ + +#define EVENT_DURATION_FUNCTION() \ + ::onert::util::EventDurationBlock __event_duration__##__LINE__ { __FUNCTION__ } + +#define EVENT_DURATION_REGION(tag) \ + ::onert::util::EventDurationBlock __event_duration__##__LINE__ { tag } + +#endif // __ONERT_UTIL_EVENT_COLLECTOR_GLOBAL_H__ diff --git a/runtime/onert/core/include/util/GeneralConfigSource.h b/runtime/onert/core/include/util/GeneralConfigSource.h new file mode 100644 index 000000000..dedc820ec --- /dev/null +++ b/runtime/onert/core/include/util/GeneralConfigSource.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_GLOBAL_CONFIG_SOURCE_H__ +#define __ONERT_UTIL_GLOBAL_CONFIG_SOURCE_H__ + +#include + +#include "util/IConfigSource.h" + +namespace onert +{ +namespace util +{ + +class GeneralConfigSource : public IConfigSource +{ +public: + GeneralConfigSource() = default; + + std::string get(const std::string &key) const override; + void set(const std::string &key, const std::string &val); + +private: + std::unordered_map _map; +}; + +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_GLOBAL_CONFIG_SOURCE_H__ diff --git a/runtime/onert/core/include/util/IConfigSource.h b/runtime/onert/core/include/util/IConfigSource.h new file mode 100644 index 000000000..07b09848a --- /dev/null +++ b/runtime/onert/core/include/util/IConfigSource.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_I_CONFIG_SOURCE_H__ +#define __ONERT_UTIL_I_CONFIG_SOURCE_H__ + +#include + +namespace onert +{ +namespace util +{ + +struct IConfigSource +{ + /** + * @brief Destroy the IConfigSource object + */ + virtual ~IConfigSource() = default; + + /** + * @brief get the value for the matching key + * + * @param key string key to search + * @return string value associated with the key + */ + virtual std::string get(const std::string &key) const = 0; +}; + +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_I_CONFIG_SOURCE_H__ diff --git a/runtime/onert/core/include/util/ITimer.h b/runtime/onert/core/include/util/ITimer.h new file mode 100644 index 000000000..d5a4e1eb0 --- /dev/null +++ b/runtime/onert/core/include/util/ITimer.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_ITIMER_H__ +#define __ONERT_UTIL_ITIMER_H__ + +#include + +namespace onert +{ +namespace util +{ + +class ITimer +{ +public: + virtual void handleBegin() = 0; + virtual void handleEnd() = 0; + int getTime() { return _timer_res; }; + + virtual ~ITimer() = default; + +protected: + int _timer_res{0}; +}; + +class CPUTimer : public ITimer +{ +public: + void handleBegin() override { _start_time = std::chrono::steady_clock::now(); }; + + void handleEnd() override + { + const auto end_time = std::chrono::steady_clock::now(); + _timer_res = + std::chrono::duration_cast(end_time - _start_time).count(); + }; + +private: + std::chrono::steady_clock::time_point _start_time; // in microseconds +}; + +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_ITIMER_H__ diff --git a/runtime/onert/core/include/util/Index.h b/runtime/onert/core/include/util/Index.h new file mode 100644 index 000000000..d96c0cffe --- /dev/null +++ b/runtime/onert/core/include/util/Index.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_INDEX_H__ +#define __ONERT_UTIL_INDEX_H__ + +#include +#include +#include + +namespace onert +{ +namespace util +{ + +/** + * @brief A wrapper class for unsigned integral Index + * NOTE : Max value of the underlying type is used as the invalid value + * + * @tparam T Underlying type. Must be unsigned integral type otherwise its behavior is undefined. + * @tparam DummyTag Dummy type to distinguish types with a same underlying type. Using an opaque + * type is recommended. + */ +template class Index +{ +private: + static const T UNDEFINED = std::numeric_limits::max(); + +public: + /** + * @brief Construct a new Index object + */ + explicit Index(void) : _index{UNDEFINED} {} + /** + * @brief Construct a new Index object with a value in the underlying type + * + * @param o Value in the underlying type + */ + explicit Index(const T o) : _index{o} {} + /** + * @brief Copy Constructor + * + * @param o Object to be copied + */ + Index(const Index &o) = default; + + /** + * @brief Assign a value in the underlying time + * + * @param o Value in the underlying type + * @return Index& Reference of this pointer + */ + Index &operator=(const T o) + { + _index = o; + return *this; + } + + /** + * @brief Copy assignment operator + * + * @param o Object to be copied + * @return Index& Reference of this pointer + */ + Index &operator=(const Index &o) = default; + + /** + * @brief Equality operator + * + * @param o The other value in the underlying type to compare + * @return true if underlying value is the same, false otherwise + */ + bool operator==(T o) const { return _index == o; } + /** + * @brief Equality operator + * + * @param o The other object to compare + * @return true if underlying value is the same, false otherwise + */ + bool operator==(const Index &o) const { return _index == o._index; } + /** + * @brief Inquality operator + * + * @param o The other value in the underlying type to compare + * @return true if underlying value is different, false otherwise + */ + bool operator!=(T o) const { return !(*this == o); } + /** + * @brief Inquality operator + * + * @param o The other object to compare + * @return true if underlying value is different, false otherwise + */ + bool operator!=(const Index &o) const { return !(*this == o); } + + /** + * @brief Post increment operator + * + * @return Index Index before increment + */ + Index operator++(int) + { + Index temp = *this; + _index++; + return temp; + } + + /** + * @brief Check whether the value is valid or not + * + * @return true if valid, false otherwise + */ + bool valid() const { return _index != UNDEFINED; } + /** + * @brief Return underlying value + * + * @return T Underlying value + */ + T value() const { return _index; } + +private: + T _index; +}; + +} // namespace util +} // namespace onert + +namespace std +{ + +template struct hash<::onert::util::Index> +{ + size_t operator()(const ::onert::util::Index &index) const noexcept + { + return hash()(index.value()); + } +}; + +} // namespace std + +#endif // __ONERT_UTIL_INDEX_H__ diff --git a/runtime/onert/core/include/util/ObjectManager.h b/runtime/onert/core/include/util/ObjectManager.h new file mode 100644 index 000000000..d2dd881a8 --- /dev/null +++ b/runtime/onert/core/include/util/ObjectManager.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_OBJECT_MANAGER_H__ +#define __ONERT_UTIL_OBJECT_MANAGER_H__ + +#include +#include +#include +#include + +#include + +namespace onert +{ +namespace util +{ + +/** + * @brief Class that owns objects and maps them with indices as a handle for them + * + */ +template class ObjectManager +{ +public: + ObjectManager() : _index_count{0u} {} + +public: + /** + * @brief Create an object with args and put it in the container with a new Index for that + * + * @param[in] args Arguments for creating Operand object + * @return Created index that is associated to the object + */ + template Index emplace(Args &&... args) + { + auto index = generateIndex(); + _objects.emplace(index, std::make_unique(std::forward(args)...)); + return index; + } + + /** + * @brief Put object in the container with a new Index for that + * + * @param[in] object Object to be pushed + * @return Created index that is associated to the object + */ + Index push(std::unique_ptr &&object) + { + auto index = generateIndex(); + _objects.emplace(index, std::move(object)); + return index; + } + + /** + * @brief Remove the object that is associated with the given index + * + * @param[in] index Index of the object to be removed + * @return N/A + */ + void remove(const Index &index) { _objects.erase(index); } + + /** + * @brief Get the object that is associated with the given index + * + * @param[in] index Index of the object to be returned + * @return Object + */ + const Object &at(const Index &index) const { return *(_objects.at(index)); } + /** + * @brief Get the object that is associated with the given index + * + * @param[in] index Index of the object to be returned + * @return Object + */ + Object &at(const Index &index) { return *(_objects.at(index)); } + /** + * @brief Get the object that is associated with the given index + * + * @param[in] index Index of the object to be returned + * @return true if such entry exists otherwise false + */ + bool exist(const Index &index) const + { + auto it = _objects.find(index); + return it != _objects.end(); + } + /** + * @brief Iterate over the container with given function + * + * @param[in] fn Function to be run for every container entry + * @return N/A + */ + void iterate(const std::function &fn) const + { + for (const auto &e : _objects) + { + fn(e.first, *e.second); + } + } + /** + * @brief Iterate over the container with given function + * + * @param[in] fn Function to be run for every container entry + * @return N/A + */ + void iterate(const std::function &fn) + { + // TODO Remove this workaround + // This implementation is a workaround in case of adding operands while iteration + std::list l; + + for (auto &e : _objects) + { + l.push_back(e.first); + } + + for (auto index : l) + { + fn(index, *_objects[index]); + } + } + +private: + Index generateIndex() { return Index{_index_count++}; } + +protected: + std::unordered_map> _objects; + uint32_t _index_count; +}; + +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_OBJECT_MANAGER_H__ diff --git a/runtime/onert/core/include/util/Set.h b/runtime/onert/core/include/util/Set.h new file mode 100644 index 000000000..ee4062d25 --- /dev/null +++ b/runtime/onert/core/include/util/Set.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Set.h + * @brief This file contains onert::util::Set class + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __ONERT_UTIL_SET_H__ +#define __ONERT_UTIL_SET_H__ + +#include +#include + +namespace onert +{ +namespace util +{ + +/** + * @brief Class for set of custom element + & @tparam Element Key type of Set + */ +template class Set +{ +public: + /** + * @brief Construct default Set object. + */ + Set() = default; + /** + * @brief Construct Set object by copy semantics. + */ + Set(const Set &) = default; + /** + * @brief Construct move Set object by move semantics. + */ + Set(Set &&) = default; + +public: + /** + * @brief Add a given element to the set + * + * @param e Element added + */ + void add(const Element &e) { _set.insert(e); } + /** + * @brief remove a given element from the set + * + * @param e Element removed + */ + void remove(const Element &e) { _set.erase(e); } + /** + * @brief Get size of the set + * + * @return The size of the set + */ + uint32_t size() const { return static_cast(_set.size()); } + /** + * @brief Get whether the set is empty + * + * @return Whether the set is empty + */ + bool empty() const { return _set.empty(); } + /** + * @brief Get whether a given element exists in the set + * + * @param e A given element + * + * @return Whether a given element exists in the set + */ + bool contains(const Element &e) const { return _set.find(e) != _set.end(); } + /** + * @brief Get first element of the set + * + * @return first element of the set + */ + const Element &getOnlyElement() const + { + assert(_set.size() == 1u); + return *_set.begin(); + } + +public: + /** + * @brief operator overloading function for `|` + * + * @return A set with two sets combined + */ + Set operator|(const Set &other) const // Union + { + auto ret = *this; + for (auto e : other) + { + ret.add(e); + } + return ret; + } + /** + * @brief operator overloading function for `&` + * + * @return A set of elements that overlap in two sets + */ + Set operator&(const Set &other) const // Intersect + { + Set ret; + for (auto e : other) + { + if (contains(e)) + { + ret.add(e); + } + } + return ret; + } + /** + * @brief operator overloading function for `-` + * + * @return A set of subtracted from another set + */ + Set operator-(const Set &other) const // Minus + { + auto ret = *this; + for (auto e : other) + { + ret.remove(e); + } + return ret; + } + +public: + /** + * @brief begin() of const_iterator for this class + * + * @return The first iterator of the set + */ + typename std::unordered_set::const_iterator begin() const { return _set.begin(); } + /** + * @brief end() of const_iterator for this class + * + * @return The last iterator of the set + */ + typename std::unordered_set::const_iterator end() const { return _set.end(); } + +private: + std::unordered_set _set; +}; + +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_SET_H__ diff --git a/runtime/onert/core/include/util/ShapeInference.h b/runtime/onert/core/include/util/ShapeInference.h new file mode 100644 index 000000000..fbd3d19c8 --- /dev/null +++ b/runtime/onert/core/include/util/ShapeInference.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_GRAPH_SHAPE_INFERENCE_H__ +#define __ONERT_GRAPH_SHAPE_INFERENCE_H__ + +#include "ir/operation/AvgPool2D.h" +#include "ir/operation/Concat.h" +#include "ir/operation/MaxPool2D.h" +#include "ir/operation/Conv2D.h" +#include "ir/operation/DepthwiseConv2D.h" +#include "ir/operation/Reshape.h" +#include "ir/Operands.h" +#include "ir/Index.h" +#include "ir/Layout.h" +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace shape_inference +{ + +using Shapes = std::vector; + +Shapes inferEltwiseShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape); + +Shapes inferAvgPoolShape(const ir::Shape &in_shape, const ir::operation::AvgPool2D::Param ¶m, + ir::Layout layout = ir::Layout::NHWC); + +Shapes inferConcatShape(const Shapes &in_shapes, const ir::operation::Concat::Param ¶m); + +Shapes inferMaxPoolShape(const ir::Shape &in_shape, const ir::operation::MaxPool2D::Param ¶m, + ir::Layout layout = ir::Layout::NHWC); + +Shapes inferConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape, + const ir::operation::Conv2D::Param ¶m, + ir::Layout layout = ir::Layout::NHWC); + +Shapes inferDepthwiseConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape, + const ir::operation::DepthwiseConv2D::Param ¶m, + ir::Layout layout = ir::Layout::NHWC); + +Shapes inferFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &ker_shape); + +/** + * @brief Class to infer shape before running kernels. It does the following: + * - re-calculate and set output shape at compile time (before running kernels) + * - if calculation cannot be done at compile time, mark the outputs to be dynamic, meaning + * shapes of outputs will be calculated during running kernels + */ +class StaticInferer : public ir::OperationVisitor +{ +public: + StaticInferer(ir::Operands &operands) : _operands(operands) { /* empty */} + virtual ~StaticInferer() = default; + +public: + /** + * @brief Infer shape of operands beloning to ops and set the output shape. + * If output shape cannot be known without running op, mark it so that it can be allocated + * when running kernel. + * @param op_seq sequence of operations + */ + void infer(const ir::OpSequence &op_seq) { op_seq.accept(*this); }; + +private: + // TODO Define visitors for operations. List them in alphabetic order. + void visit(const ir::operation::Reshape &op); + +private: + ir::Operands &_operands; +}; + +} // namespace shape_inference +} // namespace onert + +#endif // __ONERT_GRAPH_SHAPE_INFERENCE_H__ diff --git a/runtime/onert/core/include/util/Utils.h b/runtime/onert/core/include/util/Utils.h new file mode 100644 index 000000000..847fb6971 --- /dev/null +++ b/runtime/onert/core/include/util/Utils.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Utils.h + * @brief This file contains utility macro + */ + +#ifndef __ONERT_UTIL_UTILS_H__ +#define __ONERT_UTIL_UTILS_H__ + +#define UNUSED_RELEASE(a) (void)(a) + +#endif // __ONERT_UTIL_UTILS_H__ diff --git a/runtime/onert/core/include/util/feature/nchw/Reader.h b/runtime/onert/core/include/util/feature/nchw/Reader.h new file mode 100644 index 000000000..586ba92dd --- /dev/null +++ b/runtime/onert/core/include/util/feature/nchw/Reader.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_FEATURE_NCHW_READER_H__ +#define __ONERT_UTIL_FEATURE_NCHW_READER_H__ + +#include + +#include "backend/ITensor.h" +#include "misc/feature/Reader.h" +#include "misc/feature/Shape.h" + +namespace onert +{ +namespace util +{ +namespace feature +{ +namespace nchw +{ + +template class Reader final : public nnfw::misc::feature::Reader +{ +public: + // Construct for buffer of model inputs + Reader(const ::nnfw::misc::feature::Shape &shape, const T *ptr, size_t len) + : _shape{shape}, _ptr{reinterpret_cast(ptr)}, _len{len} + { + assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len); + + // No padding + _strides.W = sizeof(T); + _strides.H = shape.W * sizeof(T); + _strides.C = shape.W * shape.H * sizeof(T); + _strides.N = shape.W * shape.H * shape.C * sizeof(T); + } + + // Construct for backend tensor + Reader(backend::ITensor *tensor) + : _ptr{tensor->buffer() + tensor->calcOffset({0, 0, 0, 0})}, _len{tensor->total_size()} + { + assert(tensor->layout() == ir::Layout::NCHW); + + const auto start_offset = tensor->calcOffset({0, 0, 0, 0}); + _strides.W = tensor->dimension(3) == 1 ? 0 : tensor->calcOffset({0, 0, 0, 1}) - start_offset; + _strides.H = tensor->dimension(2) == 1 ? 0 : tensor->calcOffset({0, 0, 1, 0}) - start_offset; + _strides.C = tensor->dimension(1) == 1 ? 0 : tensor->calcOffset({0, 1, 0, 0}) - start_offset; + _strides.N = tensor->dimension(0) == 1 ? 0 : tensor->calcOffset({1, 0, 0, 0}) - start_offset; + + _shape.W = tensor->dimension(3); + _shape.H = tensor->dimension(2); + _shape.C = tensor->dimension(1); + _shape.N = tensor->dimension(0); + } + +public: + T at(uint32_t ch, uint32_t row, uint32_t col) const override + { + const auto offset = feature_index_to_byte_offset(0, ch, row, col); + + const T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override + { + const auto offset = feature_index_to_byte_offset(batch, ch, row, col); + + const T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + +private: + size_t feature_index_to_byte_offset(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const + { + assert(1u * _shape.N > batch); // shape.N > batch + assert(1u * _shape.C > ch); // shape.C > ch + assert(1u * _shape.H > row); // shape.H > row + assert(1u * _shape.W > col); // shape.W > col + + uint32_t res = 0; + res += batch * _strides.N; + res += ch * _strides.C; + res += row * _strides.H; + res += col * _strides.W; + + return res; + } + +private: + // TODO Remove _shape + nnfw::misc::feature::Shape _shape; + using Strides = nnfw::misc::feature::Shape; + Strides _strides; + const uint8_t *_ptr; + size_t _len; +}; + +} // namespace nchw +} // namespace feature +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_FEATURE_NCHW_READER_H__ diff --git a/runtime/onert/core/include/util/feature/nchw/View.h b/runtime/onert/core/include/util/feature/nchw/View.h new file mode 100644 index 000000000..28c18d034 --- /dev/null +++ b/runtime/onert/core/include/util/feature/nchw/View.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_FEATURE_NCHW_VIEW_H__ +#define __ONERT_UTIL_FEATURE_NCHW_VIEW_H__ + +#include "misc/feature/Reader.h" +#include "misc/feature/Shape.h" + +#include "backend/ITensor.h" +#include "util/logging.h" + +#include + +namespace onert +{ +namespace util +{ +namespace feature +{ +namespace nchw +{ + +template class View final : public nnfw::misc::feature::Reader +{ +public: + // Construct for buffer of model inputs + View(const ::nnfw::misc::feature::Shape &shape, T *ptr, size_t len) + : _shape{shape}, _ptr{reinterpret_cast(ptr)}, _len{len} + { + assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len); + + _strides.W = sizeof(T); + _strides.H = shape.W * sizeof(T); + _strides.C = shape.W * shape.H * sizeof(T); + _strides.N = shape.W * shape.H * shape.C * sizeof(T); + } + + // Construct for backend tensor + View(::onert::backend::ITensor *tensor) + : _ptr{tensor->buffer() + tensor->calcOffset({0, 0, 0, 0})}, _len{tensor->total_size()} + { + assert(tensor->layout() == ir::Layout::NCHW); + + const auto start_offset = tensor->calcOffset({0, 0, 0, 0}); + _strides.W = tensor->dimension(3) == 1 ? 0 : tensor->calcOffset({0, 0, 0, 1}) - start_offset; + _strides.H = tensor->dimension(2) == 1 ? 0 : tensor->calcOffset({0, 0, 1, 0}) - start_offset; + _strides.C = tensor->dimension(1) == 1 ? 0 : tensor->calcOffset({0, 1, 0, 0}) - start_offset; + _strides.N = tensor->dimension(0) == 1 ? 0 : tensor->calcOffset({1, 0, 0, 0}) - start_offset; + + _shape.W = tensor->dimension(3); + _shape.H = tensor->dimension(2); + _shape.C = tensor->dimension(1); + _shape.N = tensor->dimension(0); + } + +public: + T at(uint32_t ch, uint32_t row, uint32_t col) const override + { + const auto offset = feature_index_to_byte_offset(0, ch, row, col); + + T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override + { + const auto offset = feature_index_to_byte_offset(batch, ch, row, col); + + T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + +public: + T &at(uint32_t ch, uint32_t row, uint32_t col) + { + const auto offset = feature_index_to_byte_offset(0, ch, row, col); + + T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) + { + const auto offset = feature_index_to_byte_offset(batch, ch, row, col); + + T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + +private: + size_t feature_index_to_byte_offset(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const + { + assert(1u * _shape.N > batch); // shape.N > batch + assert(1u * _shape.C > ch); // shape.C > ch + assert(1u * _shape.H > row); // shape.H > row + assert(1u * _shape.W > col); // shape.W > col + + uint32_t res = 0; + res += batch * _strides.N; + res += ch * _strides.C; + res += row * _strides.H; + res += col * _strides.W; + + return res; + } + +private: + // TODO Remove _shape + nnfw::misc::feature::Shape _shape; + using Strides = nnfw::misc::feature::Shape; + Strides _strides; + uint8_t *_ptr; + size_t _len; +}; + +} // namespace nchw +} // namespace feature +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_FEATURE_NCHW_VIEW_H__ diff --git a/runtime/onert/core/include/util/feature/nhwc/Reader.h b/runtime/onert/core/include/util/feature/nhwc/Reader.h new file mode 100644 index 000000000..f00a864a6 --- /dev/null +++ b/runtime/onert/core/include/util/feature/nhwc/Reader.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_FEATURE_NHWC_READER_H__ +#define __ONERT_UTIL_FEATURE_NHWC_READER_H__ + +#include + +#include "backend/ITensor.h" +#include "misc/feature/Reader.h" +#include "misc/feature/Shape.h" +#include "util/Utils.h" + +namespace onert +{ +namespace util +{ +namespace feature +{ +namespace nhwc +{ + +template class Reader final : public nnfw::misc::feature::Reader +{ +public: + // Construct for buffer of model inputs + Reader(const ::nnfw::misc::feature::Shape &shape, const T *ptr, size_t len) + : _shape{shape}, _ptr{reinterpret_cast(ptr)}, _len{len} + { + UNUSED_RELEASE(len); // Workaround for unused variable in release mode + assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len); + + // No padding + _strides.C = sizeof(T); + _strides.W = shape.C * sizeof(T); + _strides.H = shape.C * shape.W * sizeof(T); + _strides.N = shape.C * shape.W * shape.H * sizeof(T); + } + + // Construct for backend tensor + Reader(const backend::ITensor *tensor) + : _ptr{tensor->buffer() + tensor->calcOffset({0, 0, 0, 0})}, _len{tensor->total_size()} + { + assert(tensor->layout() == ir::Layout::NHWC); + + const auto start_offset = tensor->calcOffset({0, 0, 0, 0}); + _strides.C = tensor->dimension(3) == 1 ? 0 : tensor->calcOffset({0, 0, 0, 1}) - start_offset; + _strides.W = tensor->dimension(2) == 1 ? 0 : tensor->calcOffset({0, 0, 1, 0}) - start_offset; + _strides.H = tensor->dimension(1) == 1 ? 0 : tensor->calcOffset({0, 1, 0, 0}) - start_offset; + _strides.N = tensor->dimension(0) == 1 ? 0 : tensor->calcOffset({1, 0, 0, 0}) - start_offset; + + _shape.C = tensor->dimension(3); + _shape.W = tensor->dimension(2); + _shape.H = tensor->dimension(1); + _shape.N = tensor->dimension(0); + } + +public: + T at(uint32_t row, uint32_t col, uint32_t ch) const override + { + const auto offset = feature_index_to_byte_offset(0, row, col, ch); + + const T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + T at(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) const override + { + const auto offset = feature_index_to_byte_offset(batch, row, col, ch); + + const T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + +private: + size_t feature_index_to_byte_offset(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) const + { + assert(1u * _shape.N > batch); // shape.N > batch + assert(1u * _shape.H > row); // shape.H > row + assert(1u * _shape.W > col); // shape.W > col + assert(1u * _shape.C > ch); // shape.C > ch + + uint32_t res = 0; + res += batch * _strides.N; + res += row * _strides.H; + res += col * _strides.W; + res += ch * _strides.C; + + return res; + } + +private: + // TODO Remove _shape + nnfw::misc::feature::Shape _shape; + using Strides = nnfw::misc::feature::Shape; + Strides _strides; + const uint8_t *_ptr; + size_t _len; +}; + +} // namespace nhwc +} // namespace feature +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_FEATURE_NHWC_READER_H__ diff --git a/runtime/onert/core/include/util/feature/nhwc/View.h b/runtime/onert/core/include/util/feature/nhwc/View.h new file mode 100644 index 000000000..1dfdfe461 --- /dev/null +++ b/runtime/onert/core/include/util/feature/nhwc/View.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_FEATURE_NHWC_VIEW_H__ +#define __ONERT_UTIL_FEATURE_NHWC_VIEW_H__ + +#include +#include + +#include "backend/ITensor.h" +#include "misc/feature/Reader.h" +#include "misc/feature/Shape.h" +#include "util/Utils.h" + +namespace onert +{ +namespace util +{ +namespace feature +{ +namespace nhwc +{ + +template class View final : public nnfw::misc::feature::Reader +{ +public: + // Construct for buffer of model inputs + View(const ::nnfw::misc::feature::Shape &shape, T *ptr, size_t len) + : _shape{shape}, _ptr{reinterpret_cast(ptr)}, _len{len} + { + UNUSED_RELEASE(len); // Workaround for unused variable in release mode + assert(shape.N * shape.H * shape.W * shape.C * sizeof(T) == len); + + // No padding + _strides.C = sizeof(T); + _strides.W = shape.C * sizeof(T); + _strides.H = shape.C * shape.W * sizeof(T); + _strides.N = shape.C * shape.W * shape.H * sizeof(T); + } + + // Construct for backend tensor + View(backend::ITensor *tensor) + : _ptr{tensor->buffer() + tensor->calcOffset({0, 0, 0, 0})}, _len{tensor->total_size()} + { + assert(tensor->layout() == ir::Layout::NHWC); + + const auto start_offset = tensor->calcOffset({0, 0, 0, 0}); + _strides.C = tensor->dimension(3) == 1 ? 0 : tensor->calcOffset({0, 0, 0, 1}) - start_offset; + _strides.W = tensor->dimension(2) == 1 ? 0 : tensor->calcOffset({0, 0, 1, 0}) - start_offset; + _strides.H = tensor->dimension(1) == 1 ? 0 : tensor->calcOffset({0, 1, 0, 0}) - start_offset; + _strides.N = tensor->dimension(0) == 1 ? 0 : tensor->calcOffset({1, 0, 0, 0}) - start_offset; + + _shape.C = tensor->dimension(3); + _shape.W = tensor->dimension(2); + _shape.H = tensor->dimension(1); + _shape.N = tensor->dimension(0); + } + +public: + T at(uint32_t row, uint32_t col, uint32_t ch) const override + { + const auto offset = feature_index_to_byte_offset(0, row, col, ch); + + const T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + T at(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) const override + { + const auto offset = feature_index_to_byte_offset(batch, row, col, ch); + + const T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + + T &at(uint32_t row, uint32_t col, uint32_t ch) + { + const auto offset = feature_index_to_byte_offset(0, row, col, ch); + + T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + + T &at(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) + { + const auto offset = feature_index_to_byte_offset(batch, row, col, ch); + + T *ptr = reinterpret_cast(_ptr + offset); + + return *ptr; + } + +private: + size_t feature_index_to_byte_offset(uint32_t batch, uint32_t row, uint32_t col, uint32_t ch) const + { + assert(1u * _shape.N > batch); // shape.N > batch + assert(1u * _shape.H > row); // shape.H > row + assert(1u * _shape.W > col); // shape.W > col + assert(1u * _shape.C > ch); // shape.C > ch + + uint32_t res = 0; + res += batch * _strides.N; + res += row * _strides.H; + res += col * _strides.W; + res += ch * _strides.C; + + return res; + } + +private: + // TODO Remove _shape + nnfw::misc::feature::Shape _shape; + using Strides = nnfw::misc::feature::Shape; + Strides _strides; + uint8_t *_ptr; + size_t _len; +}; + +} // namespace nhwc +} // namespace feature +} // namespace util +} // namespace onert + +#endif // __ONERT_UTIL_FEATURE_NHWC_VIEW_H__ diff --git a/runtime/onert/core/include/util/logging.h b/runtime/onert/core/include/util/logging.h new file mode 100644 index 000000000..b8357793e --- /dev/null +++ b/runtime/onert/core/include/util/logging.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_UTIL_LOGGING_H__ +#define __ONERT_UTIL_LOGGING_H__ + +#include + +#include "util/ConfigSource.h" + +namespace onert +{ +namespace util +{ +namespace logging +{ + +class Context +{ +public: + Context() noexcept : _enabled{false} + { + const auto env = util::getConfigBool(util::config::ONERT_LOG_ENABLE); + + if (env) + { + _enabled = true; + } + } + + static Context &get() noexcept; + +public: + bool enabled(void) const { return _enabled; } + +private: + bool _enabled; +}; + +static Context &ctx = Context::get(); + +} // namespace logging +} // namespace util +} // namespace onert + +#define VERBOSE(name) \ + if (::onert::util::logging::ctx.enabled()) \ + std::cout << "[" << #name << "] " + +#endif // __ONERT_UTIL_LOGGING_H__ diff --git a/runtime/onert/core/src/backend/BackendContext.cc b/runtime/onert/core/src/backend/BackendContext.cc new file mode 100644 index 000000000..f2173de44 --- /dev/null +++ b/runtime/onert/core/src/backend/BackendContext.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "backend/BackendContext.h" + +#include "ir/Operation.h" +#include "backend/IShapeFixer.h" +#include "backend/IConstantInitializer.h" + +namespace onert +{ +namespace backend +{ + +void BackendContext::initialize(const std::vector &operation_list, + const std::vector &operand_list) +{ + _operation_list = operation_list; + _operand_list = operand_list; +} + +void BackendContext::fixShapes() +{ + for (auto &op : _operation_list) + { + _graph->operations().at(op.index).accept(*shape_fixer); + } +} + +void BackendContext::initConsts() +{ + for (auto &op : _operation_list) + { + constant_initializer->setLayout(op.layout); + _graph->operations().at(op.index).accept(*constant_initializer); + } + + for (auto ind : _operand_list) + { + const auto &obj = _graph->operands().at(ind); + if (obj.isConstant() && !constant_initializer->exist(ind)) + { + constant_initializer->registerPermuteInitializer(ind, obj); + } + } + + constant_initializer->run(); +} + +} // namespace backend +} // namespace onert diff --git a/runtime/onert/core/src/compiler/BackendManager.cc b/runtime/onert/core/src/compiler/BackendManager.cc new file mode 100644 index 000000000..bfed7ff2b --- /dev/null +++ b/runtime/onert/core/src/compiler/BackendManager.cc @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "compiler/BackendManager.h" + +#include +#include + +#include "backend/Backend.h" +#include "backend/IConfig.h" +#include "util/logging.h" +#include "util/ConfigSource.h" +#include "misc/string_helpers.h" + +namespace onert +{ +namespace compiler +{ + +BackendManager &BackendManager::get() +{ + static BackendManager object; + return object; +} + +template +void BackendManager::loadObjectFromPlugin(std::shared_ptr &object_of_plugin_class, + const std::string obj_creator_func_name, void *handle, + Types &&... args) +{ + T *(*allocate_obj)(Types && ... Args); + // load object creator function + allocate_obj = (T * (*)(Types && ... Args))dlsym(handle, obj_creator_func_name.c_str()); + if (allocate_obj == nullptr) + { + fprintf(stderr, "BackendManager: unable to open function %s: %s\n", + obj_creator_func_name.c_str(), dlerror()); + abort(); + } + + object_of_plugin_class.reset(allocate_obj(args...)); +} + +void BackendManager::loadBackend(const std::string &backend) +{ + if (get(backend) != nullptr) + { + return; + } + + const std::string backend_plugin = "libbackend_" + backend + ".so"; + void *handle = dlopen(backend_plugin.c_str(), RTLD_LAZY | RTLD_LOCAL); + if (handle == nullptr) + { + VERBOSE(BackendManager::loadBackend) << "loadBackend failed to load plugin of " + << backend.c_str() << " backend: " << dlerror() + << std::endl; + return; + } + + VERBOSE(BackendManager::loadBackend) << "loaded " << backend_plugin << " as a plugin of " + << backend << " backend\n"; + + { + // load object creator function + auto backend_create = (backend_create_t)dlsym(handle, "onert_backend_create"); + if (backend_create == nullptr) + { + fprintf(stderr, "BackendManager: unable to open function onert_backend_create : %s\n", + dlerror()); + abort(); + } + + // load object creator function + auto backend_destroy = (backend_destroy_t)dlsym(handle, "onert_backend_destroy"); + if (backend_destroy == nullptr) + { + fprintf(stderr, "BackendManager: unable to open function onert_backend_destroy : %s\n", + dlerror()); + abort(); + } + + auto backend_object = + std::unique_ptr(backend_create(), backend_destroy); + auto backend_object_raw = backend_object.get(); + bool initialized = backend_object->config()->initialize(); // Call initialize here? + if (!initialized) + { + VERBOSE(BackendManager::loadBackend) + << backend.c_str() << " backend initialization failed. Don't use this backend" + << std::endl; + dlclose(handle); + return; + } + _gen_map.emplace(backend_object->config()->id(), std::move(backend_object)); + _available_backends.push_back(backend_object_raw); + } + + // Save backend handle (avoid warning by handle lost without dlclose()) + auto u_handle = std::unique_ptr{handle, [](void *h) { dlclose(h); }}; + _handle_map.emplace(backend, std::move(u_handle)); +} + +backend::Backend *BackendManager::get(const std::string &key) +{ + if (_gen_map.find(key) != _gen_map.end()) + { + return _gen_map.at(key).get(); + } + + return nullptr; +} + +const backend::Backend *BackendManager::get(const std::string &key) const +{ + if (_gen_map.find(key) != _gen_map.end()) + { + return _gen_map.at(key).get(); + } + + return nullptr; +} + +const backend::Backend *BackendManager::getDefault() const { return get("cpu"); } + +} // namespace compiler +} // namespace onert diff --git a/runtime/onert/core/src/compiler/BackendResolver.cc b/runtime/onert/core/src/compiler/BackendResolver.cc new file mode 100644 index 000000000..a47d8d2d5 --- /dev/null +++ b/runtime/onert/core/src/compiler/BackendResolver.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "compiler/BackendResolver.h" + +namespace onert +{ +namespace compiler +{ + +} // namespace compiler +} // namespace onert diff --git a/runtime/onert/core/src/compiler/CachedDataDeleter.h b/runtime/onert/core/src/compiler/CachedDataDeleter.h new file mode 100644 index 000000000..73f00ced7 --- /dev/null +++ b/runtime/onert/core/src/compiler/CachedDataDeleter.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_CACHED_DATA_DELETER_H__ +#define __ONERT_COMPILER_CACHED_DATA_DELETER_H__ + +#include "ir/Index.h" +#include "ir/OperationVisitor.h" +#include "ir/OpSequences.h" +#include "ir/Operands.h" +#include "util/logging.h" + +namespace onert +{ +namespace compiler +{ + +class CachedDataDeleter : public ir::OperationVisitor +{ +public: + CachedDataDeleter(ir::Operands &operands) : _operands(operands) + { + // DO NOTHING + } + + virtual ~CachedDataDeleter() = default; + +public: + void run() + { + _operands.iterate( + [&](const ir::OperandIndex &ind, const ir::Operand &) { deleteCachedData(ind); }); + } + + void run(const ir::OpSequence &op_seq) + { + for (const auto &e : op_seq.operations()) + { + const auto &node = *(e.node); + node.accept(*this); + } + } + + // NOTE: Almost layers that have the big size constants are conv and fc. + void visit(const ir::operation::Conv2D &node) override + { + using ir::operation::Conv2D; + const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)}; + deleteCachedData(ker_index); + deleteCachedData(bias_index); + } + + void visit(const ir::operation::DepthwiseConv2D &node) override + { + using ir::operation::DepthwiseConv2D; + const auto ker_index{node.getInputs().at(DepthwiseConv2D::Input::KERNEL)}; + const auto bias_index{node.getInputs().at(DepthwiseConv2D::Input::BIAS)}; + deleteCachedData(ker_index); + deleteCachedData(bias_index); + } + + void visit(const ir::operation::FullyConnected &node) override + { + using ir::operation::FullyConnected; + const auto weight_index{node.getInputs().at(FullyConnected::Input::WEIGHT)}; + const auto bias_index{node.getInputs().at(FullyConnected::Input::BIAS)}; + deleteCachedData(weight_index); + deleteCachedData(bias_index); + } + +private: + void deleteCachedData(const ir::OperandIndex &ind) + { + auto &obj = _operands.at(ind); + if (obj.isConstant()) + { + assert(obj.data() != nullptr); + obj.releaseData(); + } + } + +private: + ir::Operands &_operands; +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_CACHED_DATA_DELETER_H__ diff --git a/runtime/onert/core/src/compiler/Compiler.cc b/runtime/onert/core/src/compiler/Compiler.cc new file mode 100644 index 000000000..85af843ae --- /dev/null +++ b/runtime/onert/core/src/compiler/Compiler.cc @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "compiler/Compiler.h" + +#include "ParamChecker.h" +#include "ExecutorFactory.h" +#include "OperationValidator.h" + +#include "compiler/BackendManager.h" +#include "compiler/IScheduler.h" +#include "compiler/ManualScheduler.h" +#include "compiler/HEScheduler.h" +#include "exec/ExecTime.h" +#include "ir/operation/LowerInfo.h" +#include "dumper/dot/DotDumper.h" +#include "compiler/Linear.h" +#include "interp/InterpExecutor.h" +#include "util/ConfigSource.h" +#include "ir/OperationDumper.h" +#include "compiler/CachedDataDeleter.h" +#include "misc/string_helpers.h" + +namespace onert +{ + +namespace compiler +{ + +CompilerOptions fetchCompilerOptionsFromGlobalConfig(const ir::Graph &graph) +{ + CompilerOptions options; + + options.backend_list = nnfw::misc::split(util::getConfigString(util::config::BACKENDS), ';'); + + options.trace_filepath = util::getConfigString(util::config::TRACE_FILEPATH); + options.graph_dump_level = util::getConfigInt(util::config::GRAPH_DOT_DUMP); + options.op_seq_max_node = util::getConfigInt(util::config::OP_SEQ_MAX_NODE); + options.executor = util::getConfigString(util::config::EXECUTOR); + options.he_scheduler = util::getConfigBool(util::config::USE_SCHEDULER); + options.he_profiling_mode = util::getConfigBool(util::config::PROFILING_MODE); + options.delete_cached_data = util::getConfigBool(util::config::DELETE_CACHED_DATA); + options.disable_compile = util::getConfigBool(util::config::DISABLE_COMPILE); + + { + // Backend for all + auto &ms_options = options.manual_scheduler_options; + + // Default value for op_backend_all is first element in the backend list + ms_options.backend_for_all = util::getConfigString(util::config::OP_BACKEND_ALLOPS); + +// Opcode to Backend +#define OP(OpName) \ + { \ + const auto &backend_str = util::getConfigString(util::config::OP_BACKEND_##OpName); \ + if (!backend_str.empty()) \ + { \ + ms_options.opcode_to_backend[ir::OpCode::OpName] = backend_str; \ + } \ + } +#include "ir/Operations.lst" +#undef OP + + // Index to Backend + auto map_str = util::getConfigString(util::config::OP_BACKEND_MAP); + auto key_val_list = nnfw::misc::split(map_str, ';'); + for (const auto &key_val_str : key_val_list) + { + if (key_val_str.empty()) + { + continue; + } + + auto key_val = nnfw::misc::split(key_val_str, '='); + const auto &key_str = key_val.at(0); + const auto &val = key_val.at(1); + auto key = static_cast(std::stoi(key_str)); + + graph.operations().at(ir::OperationIndex{key}); // Check if exist, or this wil throw + ms_options.index_to_backend.emplace(ir::OperationIndex{key}, val); + } + } + return options; +} + +Compiler::Compiler(const std::shared_ptr &graph) + : _graph{graph}, _executor{nullptr}, _state{State::CREATED} +{ + + // Set default values for CompilerOptions + // All these default values should not be fetched from Env, when we stop supporting Android NN + // API. + _options = fetchCompilerOptionsFromGlobalConfig(*_graph); +} + +void Compiler::checkProfilerConditions() +{ + if (!_options.he_scheduler) + throw std::runtime_error("Heterogeneous scheduler must be enabled during profiling."); + + if (_options.executor != "Dataflow") + throw std::runtime_error("Profiling mode works only with 'Dataflow' executor"); +} + +void Compiler::compile(void) +{ + _state = State::STARTED; + + /*************************************************** + * Prepare compilation phase + ***************************************************/ + + // Operation validation check + OperationValidator{*_graph}(); + + // Compilable check + if (!checkCompilable()) + { + _executor = std::make_shared(*_graph); + return; + } + + // Mode check + if (_options.he_profiling_mode) + checkProfilerConditions(); + + /*************************************************** + * Backend independent analysis & optimization phase + ***************************************************/ + auto dump_level = static_cast(_options.graph_dump_level); + + onert::dumper::dot::DotDumper dot_dumper(*_graph, dump_level); + dot_dumper.dump("before_lower"); + + // Lower: Assign backend + auto lowered_graph = std::make_unique(*_graph, _options); + + // NOTE. Current datas' reference of constant operands is 2 because of + // original graph and lowered graph. + // To delete cached data, this doing should be done for the original graph + // at this line and then once again for the lowered graph in ExecutorFactory + // TODO. Delete this code as code for disconnecting btw Graph and nnfw session lands + if (_options.delete_cached_data) + { + CachedDataDeleter(_graph->operands()).run(); + } + + auto indexed_ranks = lowered_graph->indexed_ranks(); + + /************************************************************* + * Backend independent analysis & optimization phase finished + *************************************************************/ + + _state = State::LOWERED; + + onert::dumper::dot::DotDumper dot_dumper_lowered(lowered_graph.get(), dump_level); + dot_dumper_lowered.dump("after_lower"); + + ir::OperationDumper dumper; + _graph->operations().iterate( + [&](const ir::OperationIndex &, const ir::Operation &op) { op.accept(dumper); }); + + _executor = std::shared_ptr{ + ExecutorFactory::get().create(std::move(lowered_graph), _options)}; + _executor->setIndexedRanks(indexed_ranks); + /******************************** + * Code generation phase finished + ********************************/ + _state = State::COMPILED; +} + +bool Compiler::checkCompilable() +{ + // Disable compile phase + // When ready to use interpreter backend, remove this config and use backend setting + if (_options.disable_compile) + { + return false; + } + + // TODO check unspecified operand shape + + // Check compilable parameter + ParamChecker paramChecker{_graph}; + paramChecker(); + if (paramChecker.haveNoneConstParam()) + { + return false; + } + + return true; +} + +} // namespace compiler + +} // namespace onert diff --git a/runtime/onert/core/src/compiler/ExecutorFactory.cc b/runtime/onert/core/src/compiler/ExecutorFactory.cc new file mode 100644 index 000000000..8d06d6bbe --- /dev/null +++ b/runtime/onert/core/src/compiler/ExecutorFactory.cc @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ExecutorFactory.h" + +#include +#include "exec/ExecutionObservers.h" +#include "exec/LinearExecutor.h" +#include "exec/DataflowExecutor.h" +#include "exec/ParallelExecutor.h" +#include "compiler/BackendManager.h" +#include "compiler/ExecutionBuilder.h" +#include "exec/ExecTime.h" +#include "compiler/Linear.h" +#include "backend/IConstantInitializer.h" +#include "backend/IKernelGenerator.h" +#include "backend/IShapeFixer.h" +#include "backend/IOptimizer.h" +#include "backend/ITensorRegister.h" +#include +#include "compiler/CachedDataDeleter.h" +#include "util/ShapeInference.h" + +namespace onert +{ +namespace compiler +{ + +ExecutorFactory &ExecutorFactory::get() +{ + static ExecutorFactory singleton; + return singleton; +} + +ExecutorFactory::ExecutorFactory() +{ + _map["Linear"] = createLinearExecutor; + _map["Dataflow"] = + std::bind(createDataflowExecutor, std::placeholders::_1, std::placeholders::_2, false); + _map["Parallel"] = + std::bind(createDataflowExecutor, std::placeholders::_1, std::placeholders::_2, true); +} + +exec::IExecutor *ExecutorFactory::create(std::unique_ptr lowered_graph, + const compiler::CompilerOptions &options) +{ + return _map.at(options.executor)(std::move(lowered_graph), options); +} + +void ExecutorFactory::initializeBackendContext(ir::LoweredGraph *lowered_graph) +{ + struct Entry + { + std::vector operation_list; + std::vector operand_list; + }; + std::unordered_map backend_assets; + + // Build lists for operations + lowered_graph->op_seqs().iterate( + [&](const ir::OpSequenceIndex &op_seq_index, const ir::OpSequence &op_seq) { + auto &op_seq_li = lowered_graph->getLowerInfo()->operation; + auto backend = op_seq_li.at(op_seq_index)->backend(); + for (auto &element : op_seq.operations()) + { + backend_assets[backend].operation_list.emplace_back(element.index, op_seq.getLayout()); + } + }); + + // Build lists for operands + lowered_graph->graph().operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &) { + const auto lower_info = lowered_graph->getLowerInfo(ind); + for (auto factor : lower_info->def_factors()) + { + auto backend = factor.backend(); + backend_assets[backend].operand_list.emplace_back(ind); + } + }); + + for (auto &pair : backend_assets) + { + auto backend = pair.first; + auto &arg = pair.second; + lowered_graph->backend_contexts().at(backend)->initialize(arg.operation_list, arg.operand_list); + } +} + +void ExecutorFactory::runTensorRegistration(ir::LoweredGraph *lowered_graph, + const std::vector &order) +{ + for (const auto index : order) + { + const auto &op_seq = lowered_graph->op_seqs().at(index); + const auto backend = lowered_graph->getLowerInfo(index)->backend(); + const auto tensor_register = lowered_graph->backend_contexts().at(backend)->tensor_register; + auto tensor_builder = lowered_graph->backend_contexts().at(backend)->tensor_builder; + if (tensor_register) + { + // Custom registration + tensor_register->registerTensors(op_seq, lowered_graph->getLowerInfo()); + } + else + { + // Default registration + for (const auto elem : op_seq) + { + const auto &op = *elem.node; + for (const auto &index : op.getInputs() + op.getOutputs()) + { + if (!tensor_builder->isRegistered(index)) + { + const auto &operand_lower_info = + lowered_graph->getLowerInfo(index)->def_factors().getOnlyElement(); + const auto &obj = lowered_graph->graph().operands().at(index); + const auto frontend_layout = op_seq.getLayout(); + const auto backend_layout = operand_lower_info.layout(); + ir::OperandInfo backend_info{permuteShape(obj.shape(), frontend_layout, backend_layout), + obj.typeInfo()}; + tensor_builder->registerTensorInfo(index, backend_info, backend_layout, + obj.isConstant()); + } + } + } + } + } +} + +exec::IExecutor * +ExecutorFactory::createLinearExecutor(std::unique_ptr lowered_graph, + const compiler::CompilerOptions &options) +{ + const auto &backend_contexts = lowered_graph->backend_contexts(); + + initializeBackendContext(lowered_graph.get()); + + // linearize + assert(!lowered_graph->graph().isBuildingPhase()); + + // Shape inference. + { + shape_inference::StaticInferer inferer(lowered_graph->graph().operands()); + lowered_graph->op_seqs().iterate( + [&](const ir::OpSequenceIndex &, const ir::OpSequence &op_seq) { inferer.infer(op_seq); }); + } + + for (auto &pair : backend_contexts) + { + pair.second->fixShapes(); + } + + /************************************************* + * Backend dependent analysis & optimization phase + *************************************************/ + + for (auto &pair : backend_contexts) + { + auto &optimizer = pair.second->optimizer; + if (optimizer) + optimizer->optimize(); + } + + /********************************************************** + * Backend dependent analysis & optimization phase finished + **********************************************************/ + + /*********************** + * Code generation phase + ***********************/ + + auto order = Linear::linearize(*lowered_graph); + runTensorRegistration(lowered_graph.get(), order); + Linear::dump(*lowered_graph, order); + Linear::planTensors(*lowered_graph, order); + + backend::TensorBuilderSet tensor_builders; + for (const auto &e : lowered_graph->backend_contexts()) + { + tensor_builders.insert(e.second->tensor_builder); + } + + for (auto &tensor_builder : tensor_builders) + { + tensor_builder->prepare(); + } + + ExecutionBuilder builder; + + // Generate kernels + lowered_graph->op_seqs().iterate( + [&](const ir::OpSequenceIndex &op_seq_index, const ir::OpSequence &op_seq) { + auto lower_info = lowered_graph->getLowerInfo(op_seq_index); + auto kernel_gen = lowered_graph->backend_contexts().at(lower_info->backend())->kernel_gen; + auto fn_seq = kernel_gen->generate(op_seq); + builder.append(op_seq_index, {&op_seq, lower_info, std::move(fn_seq)}); + }); + + for (auto &tensor_builder : tensor_builders) + { + tensor_builder->allocate(); + } + + for (auto &pair : backend_contexts) + { + pair.second->initConsts(); + } + + // Note. The best solution is not to use CachedDataDeleter but decreasing reference counts of data + // naturally + if (options.delete_cached_data) + { + CachedDataDeleter cached_data_deleter(lowered_graph->graph().operands()); + lowered_graph->op_seqs().iterate( + [&](const ir::OpSequenceIndex &, const ir::OpSequence &op_seq) { + cached_data_deleter.run(op_seq); + }); + } + + auto code_map = builder.releaseCodeMap(); + + for (auto &it : code_map) + { + auto op_seq_index = it.first; + auto &fn_seq = it.second.fn_seq; + + fn_seq->iterate([&](exec::IFunction &ifunc) { + ifunc.prepare(); + auto backend = lowered_graph->getLowerInfo(op_seq_index)->backend(); + auto tensor_builder = lowered_graph->backend_contexts().at(backend)->tensor_builder; + tensor_builder->postFunctionPrepare(); + }); + } + + auto exec = new exec::LinearExecutor{std::move(lowered_graph), tensor_builders, + std::move(code_map), order}; + + if (!options.trace_filepath.empty()) + { + std::unique_ptr ctp = + std::make_unique(options.trace_filepath); + exec->addObserver(std::move(ctp)); + } + + return exec; +} + +exec::IExecutor * +ExecutorFactory::createDataflowExecutor(std::unique_ptr lowered_graph, + const compiler::CompilerOptions &options, bool parallel) +{ + const auto &backend_contexts = lowered_graph->backend_contexts(); + + initializeBackendContext(lowered_graph.get()); + + for (auto &pair : backend_contexts) + { + pair.second->fixShapes(); + } + + auto order = Linear::linearize(*lowered_graph); + runTensorRegistration(lowered_graph.get(), order); + + backend::TensorBuilderSet tensor_builders; + for (const auto &e : lowered_graph->backend_contexts()) + { + tensor_builders.insert(e.second->tensor_builder); + } + + // To make tensors never be deallocated, this is a workaround to use static memory planner + for (auto &tensor_builder : tensor_builders) + { + lowered_graph->graph().operands().iterate( + [&](const ir::OperandIndex &ind, const ir::Operand &) { + if (tensor_builder->isRegistered(ind)) + { + tensor_builder->notifyFirstUse(ind); + } + }); + } + + for (auto &tensor_builder : tensor_builders) + { + tensor_builder->prepare(); + } + + ExecutionBuilder builder; + + // Generate kernels + lowered_graph->op_seqs().iterate( + [&](const ir::OpSequenceIndex &op_seq_index, const ir::OpSequence &op_seq) { + auto lower_info = lowered_graph->getLowerInfo(op_seq_index); + auto kernel_gen = lowered_graph->backend_contexts().at(lower_info->backend())->kernel_gen; + auto fn_seq = kernel_gen->generate(op_seq); + builder.append(op_seq_index, {&op_seq, lower_info, std::move(fn_seq)}); + }); + + for (const auto &tensor_builder : tensor_builders) + { + tensor_builder->allocate(); + } + + for (auto &pair : backend_contexts) + { + pair.second->initConsts(); + } + + if (options.delete_cached_data) + { + CachedDataDeleter cached_data_deleter(lowered_graph->graph().operands()); + lowered_graph->op_seqs().iterate( + [&](const ir::OpSequenceIndex &, const ir::OpSequence &op_seq) { + cached_data_deleter.run(op_seq); + }); + } + + auto code_map = builder.releaseCodeMap(); + + for (auto &it : code_map) + { + auto op_seq_index = it.first; + auto &fn_seq = it.second.fn_seq; + + fn_seq->iterate([&](exec::IFunction &ifunc) { + ifunc.prepare(); + auto backend = lowered_graph->getLowerInfo(op_seq_index)->backend(); + auto tensor_builder = lowered_graph->backend_contexts().at(backend)->tensor_builder; + tensor_builder->postFunctionPrepare(); + }); + } + + exec::ExecutorBase *exec = nullptr; + if (parallel) + { + exec = + new exec::ParallelExecutor{std::move(lowered_graph), tensor_builders, std::move(code_map)}; + } + else + { + auto dataflow_exec = + new exec::DataflowExecutor{std::move(lowered_graph), tensor_builders, std::move(code_map)}; + if (options.he_profiling_mode) + { + std::vector backends; + for (const auto &pair : backend_contexts) + { + backends.push_back(pair.first); + } + auto et = std::make_shared(backends); + std::unique_ptr obs = std::make_unique(et); + dataflow_exec->addObserver(std::move(obs)); + dataflow_exec->setProfilingMode(true); + } + exec = dataflow_exec; + } + + if (!options.trace_filepath.empty()) + { + std::unique_ptr ctp = + std::make_unique(options.trace_filepath); + exec->addObserver(std::move(ctp)); + } + + return exec; +} + +} // namespace compiler +} // namespace onert diff --git a/runtime/onert/core/src/compiler/ExecutorFactory.h b/runtime/onert/core/src/compiler/ExecutorFactory.h new file mode 100644 index 000000000..deba18d5e --- /dev/null +++ b/runtime/onert/core/src/compiler/ExecutorFactory.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_EXECUTOR_FACTORY_H__ +#define __ONERT_COMPILER_EXECUTOR_FACTORY_H__ + +#include + +#include "exec/IExecutor.h" +#include "ir/LoweredGraph.h" + +namespace onert +{ +namespace compiler +{ + +class ExecutorFactory +{ +public: + static ExecutorFactory &get(); + +public: + exec::IExecutor *create(std::unique_ptr lowered_graph, + const compiler::CompilerOptions &options); + +private: + ExecutorFactory(); + +private: + static void initializeBackendContext(ir::LoweredGraph *lowered_graph); + static void runTensorRegistration(ir::LoweredGraph *lowered_graph, + const std::vector &order); + static exec::IExecutor *createLinearExecutor(std::unique_ptr lowered_graph, + const compiler::CompilerOptions &options); + static exec::IExecutor *createDataflowExecutor(std::unique_ptr lowered_graph, + const compiler::CompilerOptions &options, + bool parallel); + +private: + std::unordered_map, + const compiler::CompilerOptions &options)>> + _map; +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_EXECUTOR_FACTORY_H__ diff --git a/runtime/onert/core/src/compiler/HEScheduler.cc b/runtime/onert/core/src/compiler/HEScheduler.cc new file mode 100644 index 000000000..f9a264908 --- /dev/null +++ b/runtime/onert/core/src/compiler/HEScheduler.cc @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Operand.h" +#include "compiler/HEScheduler.h" +#include "ir/Graph.h" +#include "util/ConfigSource.h" +#include "compiler/BackendResolver.h" +#include "backend/IShapeFixer.h" +#include "util/logging.h" +#include "util/Utils.h" +#include "exec/FunctionSequence.h" +#include +#include +#include + +namespace onert +{ + +namespace compiler +{ +static uint32_t getOperationsFlattenedIOSize(const ir::Graph &graph, const ir::Operation &node) +{ + uint32_t size = 0; + for (const auto &ind : node.getInputs() + node.getOutputs()) + { + size += graph.operands().at(ind).info().total_size(); + } + return size; +} + +static bool isQuant(const ir::Graph &graph, const ir::Operation &node) +{ + for (const auto &input : node.getInputs()) + { + const auto &obj = graph.operands().at(input); + if (obj.typeInfo().type() == ir::DataType::QUANT8_ASYMM) + { + return true; + } + } + return false; +} + +static bool isWorkaroundSkip(const ir::Graph &graph, const backend::Backend *backend, + const ir::Operation &node, bool quant) +{ + /* TODO: this is workaround, come up with better solution if have. + Adding exception in stage doesn't help. Because if there is a record for add without + broadcast, scheduling will select it since it doesn't distinguish broadcast and + non-broadcast like it does for quant non-quantized*/ + if (backend->config()->id() == "cpu" && + (node.opcode() == ir::OpCode::Add || node.opcode() == ir::OpCode::Sub || + node.opcode() == ir::OpCode::Mul)) + { + const auto lhs_index{node.getInputs().at(ir::operation::Add::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Add::Input::RHS)}; + /*Broadcasting isn't supported on CPU: no way to differ the existing exec_time record with and + * without broadcasting*/ + if (!(graph.operands().at(lhs_index).shape() == graph.operands().at(rhs_index).shape())) + { + return true; + } + } + /* TODO: this is workaround, come up with better solution if have. + Adding exception in stage doesn't help. Because if there is a record for Mul without + broadcast, scheduling will select it since it doesn't distinguish broadcast and + non-broadcast like it does for quant non-quantized*/ + else if (backend->config()->id() == "acl_neon" && node.opcode() == ir::OpCode::Mul) + { + const auto lhs_index{node.getInputs().at(ir::operation::Mul::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Mul::Input::RHS)}; + + // Nontrivial broadcasting isn't supported yet + if (quant || + !(graph.operands().at(lhs_index).shape() == graph.operands().at(rhs_index).shape())) + { + return true; + } + } + return false; +} + +// if a node can be merged into op_seq +static bool isMergeable(const ir::Graph &graph, const ir::Operation &node) +{ + size_t prev_op_cnt = 0; + for (const auto &input : node.getInputs()) + { + // only valid_inputs + const auto &operand = graph.operands().at(input); + if (operand.isConstant()) + continue; + + // This operand is output of operation, not weight or bias + if (operand.getDef().list().size() > 0) + ++prev_op_cnt; + + // Current node has multiple inputs as concat or at the beginning of the separated branch + if (prev_op_cnt > 1 || operand.getUses().list().size() > 1) + { + return false; + } + } + return true; +} + +void HEScheduler::scheduleShufflingBackends() +{ + VERBOSE(HEScheduler::schedule) + << "Started task scheduling: uses all backends to get more metrics for data transfer" + << std::endl; + size_t backend_ind = 0; + for (const auto &rank : _rank_to_op) + { + VERBOSE(HEScheduler::schedule) << "scheduling (" << rank.second.value() << ")" << std::endl; + const auto &node = _graph->operations().at(rank.second); + const bool quant = isQuant(*_graph, node); + const auto size = getOperationsFlattenedIOSize(*_graph, node); + for (size_t i = 0;; ++i) + { + if (i == _all_backends.size()) + { + // wasn't able to find backend + assert(false); + break; + } + if (backend_ind == _all_backends.size()) + { + backend_ind = 0; + } + if (isWorkaroundSkip(*_graph, _all_backends[backend_ind], node, quant)) + { + ++backend_ind; + continue; + } + const auto exec_time = + _exec_time->getOperationExecTime(_all_backends[backend_ind], node.name(), quant, size); + // Scheduling to measure data transfer must be done after measuring all backends separately + assert(exec_time != _exec_time->NOT_FOUND); + if (exec_time == _exec_time->getMax()) + { + ++backend_ind; + continue; + } + _backend_resolver->setBackend(rank.second, _all_backends[backend_ind]); + VERBOSE(HEScheduler::schedule) << "backend for " << node.name() << " is " + << _all_backends[backend_ind]->config()->id() << std::endl; + ++backend_ind; + break; + } + } +} + +bool HEScheduler::isNodeProfiled(const ir::Operation &node) +{ + const bool quant = isQuant(*_graph, node); + const auto size = getOperationsFlattenedIOSize(*_graph, node); + for (const auto *backend : _all_backends) + { + const auto exec_time = _exec_time->getOperationExecTime(backend, node.name(), quant, size); + if (exec_time == _exec_time->NOT_FOUND) + return false; + } + return true; +} + +void HEScheduler::scheduleBranch(const ir::OperationIndex &index, + ir::OperationIndexMap &scheduled) +{ + auto loc_index = index; + const backend::Backend *parent_backend = nullptr; + while (true) + { + if (scheduled[loc_index]) + { + return; + } + if (!schedule(loc_index, parent_backend)) + { + return; + } + scheduled[loc_index] = true; + parent_backend = _backend_resolver->getBackend(loc_index); + + const auto &node = _graph->operations().at(loc_index); + /* get the only output operand, that is input of the next single operation + * and just this nodes output.*/ + if (node.getOutputs().size() != 1) + { + return; + } + const auto &only_out_operand = _graph->operands().at(*node.getOutputs().begin()); + loc_index = only_out_operand.getUses().list().front(); + /* verify, that next node is neither beginning nor ending node of a branch*/ + const auto &next_node = _graph->operations().at(loc_index); + if (!isMergeable(*_graph, next_node)) + { + return; + } + } +} + +std::unique_ptr HEScheduler::schedule(const ir::Graph &graph) +{ + _graph = &graph; + VERBOSE(HEScheduler::schedule) << "task scheduling started" << std::endl; + // Make ranks and save in descending order + makeRank(); + + for (const auto *backend : _all_backends) + { + _backends_avail_time.emplace(backend, std::map{{0, 0}}); + } + + if (_is_profiling_mode) + { + // Check if profiling info about all backend/node pairs already exists + bool all_nodes_are_profiled = true; + _graph->operations().iterate([&](const ir::OperationIndex &, const ir::Operation &op) { + if (all_nodes_are_profiled) + all_nodes_are_profiled = isNodeProfiled(op); + }); + + // If all nodes are already profiled - schedule backends in such order, so more profiling + // information about between-backends data transfer could be collected + if (all_nodes_are_profiled) + { + scheduleShufflingBackends(); + VERBOSE(HEScheduler::schedule) << "task scheduling finished" << std::endl; + return std::move(_backend_resolver); + } + } + + ir::OperationIndexMap visited; + graph.operations().iterate( + [&](const ir::OperationIndex &index, const ir::Operation &) { visited[index] = false; }); + // for each task select the backend with the smallest earliest finishing time(eft) + for (const auto &rank : _rank_to_op) + { + scheduleBranch(rank.second, visited); + } + VERBOSE(HEScheduler::schedule) << "task scheduling finished" << std::endl; + return std::move(_backend_resolver); +} + +int64_t HEScheduler::getOpTime(const backend::Backend *backend, const std::string &operation, + bool quant, uint32_t size) +{ + const auto time = _exec_time->getOperationExecTime(backend, operation, quant, size); + if (time != _exec_time->NOT_FOUND) + return time; + + return _is_supported.at(backend).at(operation) ? 1 : _exec_time->getMax(); +} + +int64_t HEScheduler::getPermuteTime(const backend::Backend *src_backend, + const backend::Backend *dst_backend, bool quant, uint32_t size) +{ + const auto time = _exec_time->getPermuteTime(src_backend, dst_backend, quant, size); + if (time != _exec_time->NOT_FOUND) + return time; + + // Makes the scheduler prefer keeping computations on one backend + return size / 200; +} + +int64_t HEScheduler::tryBackend(const ir::Operation &node, const backend::Backend *backend) +{ + // if there is no profiling info don't use this backend during scheduling + if (!_is_profiling_mode) + { + VERBOSE(HEScheduler::tryBackend) + << "Trying to HE schedule while there is no profiling info for " << node.name() + << " on backend " << backend->config()->id() << ". So this backend won't be used. " + << std::endl; + _is_supported[backend][node.name()] = false; + return _exec_time->getMax(); + } + auto iter = _is_supported.find(backend); + if (iter != _is_supported.end()) + { + auto it2 = iter->second.find(node.name()); + if (it2 != iter->second.end()) + { + return _is_supported[backend][node.name()] ? 1 : _exec_time->getMax(); + } + } + try + { + node.accept(*_backend_contexts.at(backend)->shape_fixer); + + _is_supported[backend][node.name()] = true; + } + catch (std::runtime_error &e) + { + _is_supported[backend][node.name()] = false; + } + return _is_supported[backend][node.name()] ? 1 : _exec_time->getMax(); +} + +void HEScheduler::makeRank() +{ + VERBOSE(HEScheduler::makeRank) << "task prioritizing" << std::endl; + + _graph->operations().iterate( + [&](const ir::OperationIndex &index, const ir::Operation &) { DFSMaxRank(index); }); + + // Check that ranks are calculated for all operations(nodes) + _graph->operations().iterate([&](const ir::OperationIndex &index, const ir::Operation &) { + UNUSED_RELEASE(index); + assert(_op_to_rank->find(index) != _op_to_rank->end()); + }); + VERBOSE(HEScheduler::makeRank) << "task prioritizing finished" << std::endl; +} + +int64_t HEScheduler::DFSMaxRank(const ir::OperationIndex &index) +{ + auto op_to_rank_it = _op_to_rank->find(index); + if (op_to_rank_it != _op_to_rank->end()) + return op_to_rank_it->second; + + const auto &node = _graph->operations().at(index); + int64_t rank = 0; + const bool quant = isQuant(*_graph, node); + const auto size = getOperationsFlattenedIOSize(*_graph, node); + auto supported_backends_quantity = static_cast(_all_backends.size()); + + const auto max_child_rank = DFSChildrenMaxRank(index); + + // get average exec time of this op + for (const auto &backend : _all_backends) + { + auto exec_time = _exec_time->getOperationExecTime(backend, node.name(), quant, size); + if (exec_time == _exec_time->NOT_FOUND) + { + exec_time = tryBackend(node, backend); + } + if (exec_time < _exec_time->getMax()) + { + rank += exec_time; + } + else + { + // this operation isn't supported in this backend + --supported_backends_quantity; + } + } + if (supported_backends_quantity == 0) + { + throw std::runtime_error{"Encountered unsupported op: " + node.name()}; + } + rank /= supported_backends_quantity; + + // get standard deviation + int64_t std = 0; + for (const auto backend : _all_backends) + { + const auto exec_time = getOpTime(backend, node.name(), quant, size); + if (exec_time < _exec_time->getMax()) + { + std += (exec_time - rank) * (exec_time - rank); + } + } + std /= supported_backends_quantity; + if (std > 0) + { + std = static_cast(std::sqrt(std)); + rank *= std; + } + rank += max_child_rank; + + assert(rank >= 0); + _rank_to_op.emplace(rank, index); + _op_to_rank->emplace(index, rank); + VERBOSE(HEScheduler::DFSMaxRank) << "rank of operation (" << index.value() << ")" << node.name() + << " is " << rank << std::endl; + + return rank; +} + +int64_t HEScheduler::DFSChildrenMaxRank(const ir::OperationIndex &index) +{ + const auto &node = _graph->operations().at(index); + int64_t max_child_rank = 0; + for (const auto &output : node.getOutputs()) + { + const auto &operand = _graph->operands().at(output); + const bool quant = operand.typeInfo().type() == ir::DataType::QUANT8_ASYMM; + // average data transfer cost of this operand's data + int64_t avg_transfer_cost = 1; + for (const auto *backend : _all_backends) + { + for (const auto *other_backend : _all_backends) + { + if (backend == other_backend) + { + continue; + } + auto transfer_cost = + getPermuteTime(backend, other_backend, quant, operand.info().total_size()); + avg_transfer_cost += transfer_cost; + } + } + avg_transfer_cost /= _all_backends.size(); + for (const auto &use : operand.getUses().list()) + { + const auto cur_child_rank = DFSMaxRank(use); + max_child_rank = std::max(max_child_rank, cur_child_rank + avg_transfer_cost); + } + } + return max_child_rank; +} + +int64_t HEScheduler::backendAvailableTime(const backend::Backend *backend, + const int64_t &starting_time, const int64_t &time_amount) +{ + const auto backend_times = _backends_avail_time.at(backend); + // finishing and starting times of an op, that will come after current op + auto next_op_fst = backend_times.upper_bound(starting_time); + // finishing time of an op, that will come before current op + auto prev_op_ft = starting_time; + // until reach the "hole/gap", that is enough to run this op + while (next_op_fst != backend_times.end() && next_op_fst->second - prev_op_ft <= time_amount) + { + prev_op_ft = next_op_fst->first + 1; + ++next_op_fst; + } + return prev_op_ft; +} + +bool HEScheduler::schedule(const ir::OperationIndex &index, const backend::Backend *parent_backend) +{ + VERBOSE(HEScheduler::schedule) << "scheduling (" << index.value() << ")" << std::endl; + int64_t eft = std::numeric_limits::max(), selected_exec_time = 0; + const auto &node = _graph->operations().at(index); + + std::multimap selected_transfer_st_exec_time; + // select the backend with the smallest eft of this task + const backend::Backend *chosen_backend = nullptr; + for (const auto *backend : _all_backends) + { + std::multimap transfer_st_exec_time; + const auto est_and_et = ESTAndExecTime(backend, index, transfer_st_exec_time); + + if (eft > est_and_et.first + est_and_et.second) + { + eft = est_and_et.first + est_and_et.second; + selected_exec_time = est_and_et.second; + chosen_backend = backend; + selected_transfer_st_exec_time = transfer_st_exec_time; + } + } + + if (chosen_backend == nullptr) + { + throw std::runtime_error{"Fail to choose backend on scheduler"}; + } + + // this is part of a branch and it is assigned another backend + if (parent_backend && parent_backend != chosen_backend) + { + return false; + } + for (const auto &it : selected_transfer_st_exec_time) + { + auto prev_op_ft = backendAvailableTime(_cpu_backend, it.first, it.second); + _backends_avail_time[_cpu_backend].insert({prev_op_ft + it.second, prev_op_ft}); + } + + _ops_eft[index] = eft; + _backends_avail_time[chosen_backend].emplace(eft, eft - selected_exec_time); + _backend_resolver->setBackend(index, chosen_backend); + + VERBOSE(HEScheduler::schedule) << "backend for " << node.name() << " is " + << chosen_backend->config()->id() << ". Its eft: " << eft + << std::endl; + return true; +} + +std::pair +HEScheduler::ESTAndExecTime(const backend::Backend *backend, const ir::OperationIndex &index, + std::multimap &transfer_st_exec_time) +{ + // Permutation will cause creating a separate op_seq that contains just this permutation node. + // This isn't needed for Linear executor since it doesn't use op_seqs + // Number 1 ms is picked experimentally + int64_t permute_fine = 1000; + // Multiply cpu operations' exec time by 2 because in parallel executor it might be busy with + // permutation on other branches or non-nnfw specific tasks and have to wait for it. + // Number 2 is picked experimentally + const int64_t CPU_DELAY = 2; + const auto &node = _graph->operations().at(index); + const bool quant = isQuant(*_graph, node); + const auto size = getOperationsFlattenedIOSize(*_graph, node); + // if this node can be part of a op_seq, then assigning different backend will cause creating + // another op_seq + if (isMergeable(*_graph, node)) + { + permute_fine *= 2; + } + if (isWorkaroundSkip(*_graph, backend, node, quant)) + { + return {_exec_time->getMax(), _exec_time->getMax()}; + } + // get average exec time of the op on this backend + auto exec_time = getOpTime(backend, node.name(), quant, size); + if (backend->config()->id() == "cpu" && _is_parallel_exec) + { + exec_time *= CPU_DELAY; + } + + // get max eft of direct (one level above) predecessors + auto max_pred_eft = predMaxEFT(backend, node, transfer_st_exec_time); + + int64_t total_transfer_cost = 0; + std::vector::iterator> inserted_permutations; + // Find free time for data transferring and insert it into backend taskset. This is needed: + // 1. Time for multiple permutations for this node's input is found correctly + // 2. If backend==cpu, then free time for this node must come after permutations + for (auto &it : transfer_st_exec_time) + { + if (_is_parallel_exec) + { + it.second *= CPU_DELAY; + } + if (!_is_linear_exec) + { + it.second += permute_fine; + } + total_transfer_cost += it.second; + + const auto prev_op_ft = backendAvailableTime(_cpu_backend, it.first, it.second); + + max_pred_eft = std::max(max_pred_eft, prev_op_ft + it.second); + + const auto tmp = _backends_avail_time[_cpu_backend].emplace(prev_op_ft + it.second, prev_op_ft); + inserted_permutations.push_back(tmp.first); + } + // find the hole/gap, where this op can be put or the finishing time of the last assigned op + auto prev_op_ft = backendAvailableTime(backend, max_pred_eft, exec_time); + + // Remove inserted permutation from cpu's task set + for (const auto &it : inserted_permutations) + { + _backends_avail_time[_cpu_backend].erase(it); + } + + /* In case non-parallel executor measure just exec time and data transfer time + * because EFT(prev_op_ft) is the same for all backends. Since two operations + * can't be run simultaneously, finish of running operation must be waited for. + * When an operation starts, all backends are free. So, they need time just for + * data transfer.*/ + if (!_is_parallel_exec) + { + VERBOSE(HEScheduler::ESTAndExecTime) + << "exec_time of (" << index.value() << ") " << node.name() << " quant==" << quant << " on " + << backend->config()->id() << " is " << exec_time + << " microseconds. Data transfer cost: " << total_transfer_cost << std::endl; + + return {total_transfer_cost, exec_time}; + } + VERBOSE(HEScheduler::ESTAndExecTime) + << "exec_time of (" << index.value() << ") " << node.name() << " quant==" << quant << " on " + << backend->config()->id() << ": " << exec_time + << " microseconds. Backend available time: " << prev_op_ft + << " Parent's max eft: " << max_pred_eft - total_transfer_cost + << " data transfer cost: " << total_transfer_cost << std::endl; + + return {prev_op_ft, exec_time}; +} + +int64_t HEScheduler::predMaxEFT(const backend::Backend *backend, const ir::Operation &node, + std::multimap &transfer_st_exec_time) +{ + int64_t max_pred_eft = 0; + for (const auto &input_operand_idx : node.getInputs()) + { + const auto &input_operand = _graph->operands().at(input_operand_idx); + const bool quant = input_operand.typeInfo().type() == ir::DataType::QUANT8_ASYMM; + + for (const auto &input_node_idx : input_operand.getDef().list()) + { + // Data transfer cost from parent's node backend to current node's backend: + auto parent_backend = _backend_resolver->getBackend(input_node_idx); + + max_pred_eft = std::max(max_pred_eft, _ops_eft.at(input_node_idx)); + if (parent_backend != backend) + { + // Multiply operand size by 2 because size must describe input+output size + int64_t transfer_cost = + getPermuteTime(parent_backend, backend, quant, input_operand.info().total_size() * 2); + transfer_st_exec_time.emplace(_ops_eft.at(input_node_idx), transfer_cost); + } + } + } + return max_pred_eft; +} + +} // namespace compiler + +} // namespace onert diff --git a/runtime/onert/core/src/compiler/HEScheduler.h b/runtime/onert/core/src/compiler/HEScheduler.h new file mode 100644 index 000000000..dbd71d4cb --- /dev/null +++ b/runtime/onert/core/src/compiler/HEScheduler.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file HEScheduler.h + * @brief This file contains HEScheduler class to define and run task Heterogeneous Execution + * Scheduler + */ + +#ifndef __ONERT_COMPILER_H_E_SCHEDULER_H_ +#define __ONERT_COMPILER_H_E_SCHEDULER_H_ + +#include "compiler/IScheduler.h" +#include "compiler/BackendManager.h" +#include "compiler/Compiler.h" +#include "ir/Graph.h" +#include "exec/ExecTime.h" +#include "backend/Backend.h" +#include +#include "ir/OperationIndexMap.h" +#include +#include + +namespace onert +{ + +namespace compiler +{ +/** + * @brief Class to schedule tasks + */ +class HEScheduler : IScheduler +{ +public: + /** + * @brief Construct a new Heterogeneous Execution Scheduler object + * @param[in] model Graph model + * @param[in] backend_resolver backend resolver + */ + HEScheduler(const backend::BackendContexts &backend_contexts, const CompilerOptions &options) + : _backend_contexts{backend_contexts}, _is_supported{}, _backends_avail_time{}, _ops_eft{}, + _op_to_rank{std::make_shared>()}, + _is_profiling_mode{options.he_profiling_mode}, + _is_linear_exec{options.executor == "Linear"}, + _is_parallel_exec{options.executor == "Parallel"} + { + for (auto &entry : backend_contexts) + { + _all_backends.push_back(entry.first); + } + _backend_resolver = std::make_unique(); + _exec_time = std::make_unique(_all_backends); + + // Find cpu backend + auto cpu_backend_it = std::find_if( + _all_backends.begin(), _all_backends.end(), + [](const backend::Backend *backend) { return backend->config()->id() == "cpu"; }); + if (cpu_backend_it == _all_backends.end()) + throw std::runtime_error("HEScheduler could be used only if 'cpu' backend is available"); + _cpu_backend = *cpu_backend_it; + } + +public: + /** + * @brief Task scheduling + * + * @note The main idea is taken from HSIP algo: + * https://www.hindawi.com/journals/sp/2016/3676149/ + */ + std::unique_ptr schedule(const ir::Graph &graph) final; + std::shared_ptr> getIndexedRanks() { return _op_to_rank; } + +private: + bool isNodeProfiled(const ir::Operation &); + + bool schedule(const ir::OperationIndex &, const backend::Backend *parent_backend); + /** + * @brief Get earliest starting time and execution time of an operation on a backend. + * + * @note Returns a time when operation's inputs are ready and backend is available + * It also returns exec time. If this is "cpu" backend, then exec_time*CPU_DELAY + * + * @param[in] backend: backend, for which to return the time + * @param[in] index: index of an operation + * @param[out] transfer_st_exec_time: est and exec time of data transfer operation + * + * @return earliest starting time and execution time + */ + std::pair + ESTAndExecTime(const backend::Backend *backend, const ir::OperationIndex &index, + std::multimap &transfer_st_exec_time); + /** + * @brief Returns the latest finishing time of parents of a node. + * + * @param[in] backend: backend, for which to return the time + * @param[in] node: node to get eft of parents + * @param[out] transfer_st_exec_time: est and exec time of data transfer operation + * + * @return earliest finishing time of parent nodes + */ + int64_t predMaxEFT(const backend::Backend *backend, const ir::Operation &node, + std::multimap &transfer_st_exec_time); + + void makeRank(); + + int64_t DFSMaxRank(const ir::OperationIndex &index); + + int64_t DFSChildrenMaxRank(const ir::OperationIndex &index); + /** + * @brief Returns the time, when backend is available for at least given amount of time. + * + * @note Returns either hole/gap between two performing two already scheduled operations, + * or the finishing time of the last scheduled operation + * + * @param[in] backend backend, for which to return the time + * @param[in] starting_time time, starting which to look for gap + * @param[in] time_amount amount of the time, for which to look gap + * + * @return time, when backend has at least time_amount free time + */ + int64_t backendAvailableTime(const backend::Backend *backend, const int64_t &starting_time, + const int64_t &time_amount); + + int64_t getOpTime(const backend::Backend *backend, const std::string &operation, bool quant, + uint32_t size); + + int64_t getPermuteTime(const backend::Backend *src_backend, const backend::Backend *dst_backend, + bool quant, uint32_t size); + + void scheduleShufflingBackends(); + + int64_t tryBackend(const ir::Operation &node, const backend::Backend *backend); + + /** + * @brief Schedule a node and its successor until: + * 1. there is no branching or connection of multiple branches + * 2. for subsequent nodes: other than predecessor's backend is prefered + * + * @param[in] index: index of an operation + * @param[in] scheduled: a map to check if this node has already been scheduled + * + * @return N/A + */ + void scheduleBranch(const ir::OperationIndex &index, ir::OperationIndexMap &scheduled); + +private: + // This variable stores backend/node pairs with unknown execution time, and hints scheduler + // whether it should assign these backends to these nodes: + // * It stores false for unsupported nodes + // * During rank calculation with enabled profiling mode it stores true for supported nodes + const backend::BackendContexts &_backend_contexts; + std::unordered_map> _is_supported; + // Finishing and starting time of each backend + std::unordered_map> _backends_avail_time; + ir::OperationIndexMap _ops_eft; + std::multimap> _rank_to_op; + std::shared_ptr> _op_to_rank; + std::unique_ptr _backend_resolver; + std::unique_ptr _exec_time; + const ir::Graph *_graph{nullptr}; + std::vector + _all_backends; // TODO Remove this and use _backend_contexts instead + const backend::Backend *_cpu_backend{nullptr}; + bool _is_profiling_mode; + bool _is_linear_exec; + bool _is_parallel_exec; +}; + +} // namespace compiler + +} // namespace onert + +#endif // __ONERT_COMPILER_H_E_SCHEDULER_H_ diff --git a/runtime/onert/core/src/compiler/IScheduler.h b/runtime/onert/core/src/compiler/IScheduler.h new file mode 100644 index 000000000..5e9b9bd3c --- /dev/null +++ b/runtime/onert/core/src/compiler/IScheduler.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_CORE_COMPILER_I_SCHEDULER_H__ +#define __ONERT_CORE_COMPILER_I_SCHEDULER_H__ + +#include "compiler/BackendResolver.h" +#include "ir/Graph.h" + +namespace onert +{ +namespace compiler +{ + +struct IScheduler +{ + virtual ~IScheduler() = default; + + virtual std::unique_ptr schedule(const ir::Graph &graph) = 0; +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_CORE_COMPILER_I_SCHEDULER_H__ diff --git a/runtime/onert/core/src/compiler/Linear.cc b/runtime/onert/core/src/compiler/Linear.cc new file mode 100644 index 000000000..7c658de95 --- /dev/null +++ b/runtime/onert/core/src/compiler/Linear.cc @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "Linear.h" + +#include "backend/IShapeFixer.h" +#include "backend/IConfig.h" +#include "backend/IConstantInitializer.h" +#include "backend/ITensorRegister.h" +#include "backend/Backend.h" +#include "util/logging.h" + +namespace onert +{ +namespace compiler +{ + +std::vector Linear::linearize(const ir::LoweredGraph &lowered_graph) +{ + std::vector order; + { + const ir::Graph &graph = lowered_graph.graph(); + const ir::OpSequences &op_seqs = lowered_graph.op_seqs(); + const ir::Operands &operands = graph.operands(); + // op_seqs can't access a op_seq by an operand so that input_to_op_seqs can offer it + std::unordered_map> input_to_op_seqs; + + // Get the relations between input/op_seq to be used for dfs-post-iter + // + // [0] # input -> _input_to_op_seqs[0] = {OP_SEQS0} + // | + // [OP_SEQS0] + // | + // [1]---------. # input -> _input_to_op_seqs[1] = {OP_SEQS1, OP_SEQS2} + // | | + // [OP_SEQS1] [OP_SEQS2] + // | | + // [2] [3] # input -> _input_to_op_seqs[2] = {OP_SEQS3} + // \ / # input -> _input_to_op_seqs[3] = {OP_SEQS3} + // [OP_SEQS3] + // | + // [4] + op_seqs.iterate([&](const ir::OpSequenceIndex &op_seq_idx, const ir::OpSequence &op_seq) { + for (auto input : op_seq.getInputs()) + { + // only valid_inputs + const auto &operand = operands.at(input); + if (operand.isConstant()) + continue; + + auto it = input_to_op_seqs.find(input); + if (it == input_to_op_seqs.end()) + { + std::list list{op_seq_idx}; + input_to_op_seqs[input] = list; + } + else + { + it->second.push_back(op_seq_idx); + } + } + }); + + std::unordered_map visited; + op_seqs.iterate( + [&](const ir::OpSequenceIndex &index, const ir::OpSequence &) { visited[index] = false; }); + + std::function dfs_recursive = + [&](const ir::OpSequenceIndex &index, const ir::OpSequence &op_seq) -> void { + if (visited[index]) + return; + visited[index] = true; + + // The outputs should be not constants + for (auto output : op_seq.getOutputs()) + { + const auto it = input_to_op_seqs.find(output); + if (it != input_to_op_seqs.end()) + { + const auto &op_seq_index_list = it->second; + for (const auto &index : op_seq_index_list) + { + auto &op_seq = op_seqs.at(index); + dfs_recursive(index, op_seq); + } + } + } + + order.emplace_back(index); + }; + + op_seqs.iterate(dfs_recursive); + + // All of the nodes must have been visited. + assert( + std::all_of(visited.begin(), visited.end(), + [](const std::pair &v) { return v.second; })); + + // NOTE. Now these op_seq are on the reverse order + std::reverse(order.begin(), order.end()); + } + return order; +} + +void Linear::dump(const ir::LoweredGraph &lowered_graph, + const std::vector &order) +{ + { + const auto &toString = [](const onert::backend::Backend *backend) { + assert(backend); + std::string str; + str += backend->config()->id(); + return "{" + str + "}"; + }; + + VERBOSE(Linear) << "Final OpSequence" << std::endl; + for (const auto index : order) + { + + const auto &op_seq = lowered_graph.op_seqs().at(index); + const auto lower_info = lowered_graph.getLowerInfo(index); + VERBOSE(Linear) << "* OP_SEQ " << toString(lower_info->backend()) << " " << op_seq.getStr() + << std::endl; + } + } +} + +void Linear::planTensors(const ir::LoweredGraph &lowered_graph, + const std::vector &order) +{ + const auto &graph = lowered_graph.graph(); + ir::OperandIndexMap> tensor_builder_map; + + ir::OperandIndexMap uses_map; + ir::OperandIndexMap def_map; + ir::OperandIndexSequence constants; + + // Prepare scanning + graph.operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) { + const auto lower_info = lowered_graph.getLowerInfo(ind); + // TODO Remove if onert doesn't support anymore such as + // GeneratedTests.reshape_quant8_weights_as_inputs + if (lower_info->def_factors().size() == 0 && lower_info->use_factors().size() == 0 && + !graph.getInputs().contains(ind)) + { + VERBOSE(LINEAR) << "Operand #" << ind.value() << " will not be used. no more process." + << std::endl; + return; + } + + uses_map[ind] = obj.getUses().size(); + def_map[ind] = obj.getDef().size(); // should be 1 or 0 + + bool is_const = obj.isConstant(); + if (is_const) + { + constants.append(ind); + } + + auto factor = lower_info->def_factors().getOnlyElement(); + auto backend = factor.backend(); + auto tensor_builder = lowered_graph.backend_contexts().at(backend)->tensor_builder; + if (!tensor_builder->isRegistered(ind)) + { + // These tensors do not exist in any op_seq (No use and def) + const auto info = obj.info(); + const auto backend_layout = factor.layout(); + // TODO Change tensor info to have permuted shape + tensor_builder->registerTensorInfo(ind, info, backend_layout, is_const); + } + + tensor_builder_map[ind] = tensor_builder; + }); + + // If a tensor is model output, increase the use of the tensor. + // This aim is same to above one. + for (const auto &ind : graph.getOutputs()) + { + uses_map[ind]++; + } + + // Start scanning to do notify{First|Last}Use for each tensor + + // If a tensor is a constant, increase the use of the tensor. + // It makes the tensor not be dealloced. It means these will be deallocated last. + // And allocate constant operands first + VERBOSE(LINEAR) << "TENSORS as CONSTANT" << std::endl; + for (const auto &ind : constants) + { + uses_map[ind]++; + tensor_builder_map[ind]->notifyFirstUse(ind); + } + + // Allocate Model's inputs + VERBOSE(LINEAR) << "TENSORS as MODEL INPUT" << std::endl; + for (const auto &ind : graph.getInputs()) + { + auto tensor_builder = tensor_builder_map[ind]; + if (!tensor_builder) // for GeneratedTests.xxx_weights_as_inputs + continue; + tensor_builder->notifyFirstUse(ind); + } + + // At each operation, + // 1. Scan DEF of outputs. If the DEF, allocate it + // 2. Scan USE of inputs. Decrease the USE and deallocate if the USE is 0 + VERBOSE(LINEAR) << "TENSORS" << std::endl; + for (const auto op_seq_ind : order) + { + const auto &op_seq = lowered_graph.op_seqs().at(op_seq_ind); + for (const auto &op : op_seq.operations()) + { + for (const auto &ind : op.node->getOutputs()) + { + assert(def_map.find(ind) != def_map.end()); + if (def_map[ind]) + { + def_map[ind] = 0; + tensor_builder_map[ind]->notifyFirstUse(ind); + } + } + + for (const auto &ind : op.node->getInputs()) + { + assert(uses_map.find(ind) != uses_map.end()); + assert(uses_map[ind] > 0); + uses_map[ind]--; + if (uses_map[ind] == 0) + { + tensor_builder_map[ind]->notifyLastUse(ind); + } + } + } + } + + // Dispose and validate + for (const auto &ind : graph.getOutputs()) + { + --uses_map[ind]; + if (uses_map[ind] == 0) // To prevent notifyLastUse from being called twice + { + tensor_builder_map[ind]->notifyLastUse(ind); + } + } + + for (const auto &ind : constants) + { + --uses_map[ind]; + if (uses_map[ind] == 0) // To prevent notifyLastUse from being called twice + { + tensor_builder_map[ind]->notifyLastUse(ind); + } + } + + assert( + std::all_of(uses_map.begin(), uses_map.end(), + [](std::pair it) { return it.second == 0; })); + + assert( + std::all_of(def_map.begin(), def_map.end(), + [](std::pair it) { return it.second == 0; })); +} + +} // namespace compiler +} // namespace onert diff --git a/runtime/onert/core/src/compiler/Linear.h b/runtime/onert/core/src/compiler/Linear.h new file mode 100644 index 000000000..faeff77f3 --- /dev/null +++ b/runtime/onert/core/src/compiler/Linear.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_LINEAR_H__ +#define __ONERT_COMPILER_LINEAR_H__ + +#include +#include + +#include "ir/OpSequences.h" +#include "ir/Index.h" +#include "backend/ITensorBuilder.h" +#include "ir/LoweredGraph.h" + +namespace onert +{ +namespace ir +{ +struct OperationVisitor; +} // namespace ir +} // namespace onert + +namespace onert +{ +namespace compiler +{ + +class Linear +{ +public: + static std::vector linearize(const ir::LoweredGraph &lowered_graph); + static void dump(const ir::LoweredGraph &lowered_graph, + const std::vector &order); + static void planTensors(const ir::LoweredGraph &lowered_graph, + const std::vector &order); +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_LINEAR_H__ diff --git a/runtime/onert/core/src/compiler/ManualScheduler.cc b/runtime/onert/core/src/compiler/ManualScheduler.cc new file mode 100644 index 000000000..5a5aa8219 --- /dev/null +++ b/runtime/onert/core/src/compiler/ManualScheduler.cc @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ManualScheduler.h" +#include "ir/OpCode.h" +#include "ir/Operations.Include.h" +#include "backend/Backend.h" +#include "backend/IConfig.h" +#include "compiler/BackendManager.h" +#include "util/ConfigSource.h" +#include "util/logging.h" +#include "misc/string_helpers.h" + +namespace onert +{ +namespace compiler +{ + +ManualScheduler::ManualScheduler(const compiler::ManualSchedulerOptions &options) + : _options{options} +{ +} + +std::unique_ptr ManualScheduler::schedule(const ir::Graph &graph) +{ + auto backend_resolver = std::make_unique(); + + // 1. Backend for All operations + const backend::Backend *backend_all = BackendManager::get().get(_options.backend_for_all); + if (!backend_all) + { + backend_all = BackendManager::get().getAll().at(0); + } + VERBOSE(ManualScheduler) << "Default backend for all ops: " << _options.backend_for_all + << std::endl; + + graph.operations().iterate([&](const ir::OperationIndex &index, const ir::Operation &) { + backend_resolver->setBackend(index, backend_all); + }); + + // 2. Backend per operation type + std::unordered_map op_type_map; + for (auto &pair : _options.opcode_to_backend) + { + op_type_map.emplace(pair.first, BackendManager::get().get(pair.second)); + } + // By default, Custom uses cpu backend + op_type_map[ir::OpCode::Custom] = BackendManager::get().get("cpu"); + + graph.operations().iterate([&](const ir::OperationIndex &index, const ir::Operation &operation) { + auto itr = op_type_map.find(operation.opcode()); + if (itr != op_type_map.end()) + { + backend_resolver->setBackend(index, itr->second); + } + }); + + // 3. Backend per operation + for (auto &pair : _options.index_to_backend) + { + const auto &key = pair.first; + const auto &val = pair.second; + + try + { + graph.operations().at(key); // Check if exist, or this will throw + backend_resolver->setBackend(key, BackendManager::get().get(val)); + } + catch (...) + { + VERBOSE(ManualScheduler) << "Invalid value while OperationIndex to Backend mapping : @" + << key.value() << " -> \"" << val << "\"" << std::endl; + } + } + + // 4. Operations that are specially handled + // All configuration above will be ignored(overwritten) + op_type_map[ir::OpCode::Permute] = BackendManager::get().get("cpu"); + + // Dump final assignment + backend_resolver->iterate([&](const ir::OperationIndex &index, const backend::Backend &backend) { + VERBOSE(ManualScheduler) << "backend for operation #" << index.value() << ": " + << backend.config()->id() << std::endl; + }); + + return backend_resolver; +} + +} // namespace compiler +} // namespace onert diff --git a/runtime/onert/core/src/compiler/ManualScheduler.h b/runtime/onert/core/src/compiler/ManualScheduler.h new file mode 100644 index 000000000..961dd14b2 --- /dev/null +++ b/runtime/onert/core/src/compiler/ManualScheduler.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_CORE_COMPILER_MANUAL_SCHEDULER_H__ +#define __ONERT_CORE_COMPILER_MANUAL_SCHEDULER_H__ + +#include "IScheduler.h" +#include "compiler/Compiler.h" + +namespace onert +{ +namespace compiler +{ + +class ManualScheduler : public IScheduler +{ +public: + ManualScheduler(const compiler::ManualSchedulerOptions &options); + std::unique_ptr schedule(const ir::Graph &graph) override; + +private: + compiler::ManualSchedulerOptions _options; +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_CORE_COMPILER_MANUAL_SCHEDULER_H__ diff --git a/runtime/onert/core/src/compiler/OperandContext.cc b/runtime/onert/core/src/compiler/OperandContext.cc new file mode 100644 index 000000000..cce555e33 --- /dev/null +++ b/runtime/onert/core/src/compiler/OperandContext.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperandContext.h" + +#include + +namespace onert +{ +namespace compiler +{ + +OperandContext &OperandContext::set(const ir::OperandIndex &id, + const std::shared_ptr &tensor) +{ + // Only one tensor for an id + assert(_tensors.find(id) == _tensors.end()); + _tensors[id] = tensor; + return (*this); +} + +void OperandContext::iterate( + const std::function &fn) +{ + for (auto &e : _tensors) + { + fn(e.first, *e.second); + } +} + +} // namespace compiler +} // namespace onert diff --git a/runtime/onert/core/src/compiler/OperandContext.h b/runtime/onert/core/src/compiler/OperandContext.h new file mode 100644 index 000000000..390b376fe --- /dev/null +++ b/runtime/onert/core/src/compiler/OperandContext.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_OPERAND_CONTEXT_H__ +#define __ONERT_COMPILER_OPERAND_CONTEXT_H__ + +#include "backend/ITensor.h" +#include "ir/OperandIndexMap.h" +#include +#include + +namespace onert +{ +namespace compiler +{ + +class OperandContext +{ +public: + OperandContext &set(const ir::OperandIndex &ind, const std::shared_ptr &tensor); + +public: + bool exist(const ir::OperandIndex &ind) const { return _tensors.find(ind) != _tensors.end(); } + +public: + std::shared_ptr at(const ir::OperandIndex &ind) const + { + return _tensors.at(ind); + } + + std::shared_ptr &at(const ir::OperandIndex &ind) { return _tensors.at(ind); } + + void iterate(const std::function &fn); + +private: + ir::OperandIndexMap> _tensors; +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_OPERAND_CONTEXT_H__ diff --git a/runtime/onert/core/src/compiler/OperationValidator.cc b/runtime/onert/core/src/compiler/OperationValidator.cc new file mode 100644 index 000000000..1368d11b9 --- /dev/null +++ b/runtime/onert/core/src/compiler/OperationValidator.cc @@ -0,0 +1,1079 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperationValidator.h" + +#include + +#include "ir/Graph.h" +#include "ir/operation/LowerInfo.h" + +#include "util/logging.h" +#include "util/Utils.h" + +namespace onert +{ +namespace compiler +{ + +OperationValidator::OperationValidator(const ir::Graph &graph) + : _graph{graph}, _ctx{graph.operands()}, _current_op_seq_layout{ir::Layout::UNKNOWN} +{ +} + +void OperationValidator::operator()() +{ + // TODO Get frontend layout from graph + _current_op_seq_layout = ir::Layout::NHWC; + + _graph.operations().iterate( + [&](const ir::OperationIndex &, const ir::Operation &node) { node.accept(*this); }); +} + +void OperationValidator::visit(const ir::operation::Abs &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape()); +} + +void OperationValidator::visit(const ir::operation::AvgPool2D &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::AvgPool2D::Input::INPUT)}; + + UNUSED_RELEASE(ofm_index); + UNUSED_RELEASE(ifm_index); + + assert(_ctx.at(ifm_index).shape().rank() == 4); +} + +void OperationValidator::visit(const ir::operation::BatchToSpaceND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::BatchToSpaceND::Input::INPUT)}; + const auto block_size_index{ + node.getInputs().at(ir::operation::BatchToSpaceND::Input::BLOCK_SIZE)}; + + const auto frontend_layout = _current_op_seq_layout; + const auto input_shape = _ctx.at(ifm_index).shape().asFeature(frontend_layout); + const auto output_shape = _ctx.at(ofm_index).shape().asFeature(frontend_layout); + + UNUSED_RELEASE(input_shape); + UNUSED_RELEASE(output_shape); + UNUSED_RELEASE(block_size_index); + + // All assertions as per NNAPI specification. + assert(_ctx.at(ifm_index).shape().rank() == 4); + assert(_ctx.at(ofm_index).shape().rank() == 4); + assert(_ctx.at(block_size_index).shape().rank() == 1); + + assert(_ctx.at(block_size_index).shape().dim(0) == 2); + + assert(_ctx.at(block_size_index).isConstant()); + + assert(input_shape.C == output_shape.C); +} + +void OperationValidator::visit(const ir::operation::Cast &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape()); +} + +void OperationValidator::visit(const ir::operation::Comparison &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT0)}; + const auto rhs_index{node.getInputs().at(ir::operation::Comparison::Input::INPUT1)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(lhs_index); + UNUSED_RELEASE(rhs_index); + + assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(rhs_index).typeInfo().type()); + assert(_ctx.at(output_index).typeInfo().type() == ir::DataType::BOOL8); +} + +void OperationValidator::visit(const ir::operation::Softmax &node) +{ + VERBOSE(Softmax) << "Configure SOFTMAX operation" << std::endl; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank()); +} + +void OperationValidator::visit(const ir::operation::InstanceNorm &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::InstanceNorm::Input::INPUT)}; + const auto gamma_index{node.getInputs().at(ir::operation::InstanceNorm::Input::GAMMA)}; + const auto beta_index{node.getInputs().at(ir::operation::InstanceNorm::Input::BETA)}; + + UNUSED_RELEASE(ofm_index); + UNUSED_RELEASE(ifm_index); + UNUSED_RELEASE(gamma_index); + UNUSED_RELEASE(beta_index); + + assert(_ctx.at(ifm_index).shape().rank() == 4); + assert(_ctx.at(ifm_index).shape() == _ctx.at(ofm_index).shape()); + assert(_ctx.at(gamma_index).shape().rank() == 1); + assert(_ctx.at(beta_index).shape().rank() == 1); +} + +void OperationValidator::visit(const ir::operation::Permute &node) +{ + VERBOSE(Permute) << "Configure Permute operation" << std::endl; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank()); +} + +void OperationValidator::visit(const ir::operation::ReduceSum &node) +{ + VERBOSE(Permute) << "Configure ReduceSum operation" << std::endl; + + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::ReduceSum::Input::INPUT)}; + const auto &axes = node.param().axes; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + UNUSED_RELEASE(axes); + + const auto input_shape = _ctx.at(input_index).shape(); + const auto output_shape = _ctx.at(output_index).shape(); + + UNUSED_RELEASE(output_shape); + UNUSED_RELEASE(input_shape); + + assert(input_shape.rank() <= 4); + assert(output_shape.rank() <= input_shape.rank()); + + // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only + // supports cases reducing height and width or reducing depth. + // TODO We have to support all cases of dimensions up to 4. + // For correct permuting, we have to set output's shape to be equal in dimension position of the + // input. But the positions of the same dimensions in the input and output may be set differently. + // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original + // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to + // extend it in 4 dimensions, it should be {1,1,3,5}. + // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of + // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the + // next operation is not desired. + if (input_shape.rank() == 4 && input_shape.rank() != output_shape.rank()) + { + if (output_shape.rank() == 2) + { + // Reducing HW + assert(input_shape.dim(0) == output_shape.dim(0) && + input_shape.dim(3) == output_shape.dim(1)); + } + else if (output_shape.rank() == 3) + { + // Reducing C or + // (Reducing H and C(input and output) == 1) or (Reducing W and C(input and output) == 1) + assert((input_shape.dim(0) == output_shape.dim(0) && + input_shape.dim(1) == output_shape.dim(1) && + input_shape.dim(2) == output_shape.dim(2)) || + (input_shape.dim(0) == output_shape.dim(0) && + (input_shape.dim(1) == output_shape.dim(1) || + input_shape.dim(2) == output_shape.dim(1)) && + input_shape.dim(3) == 1 && output_shape.dim(2) == 1)); + } + } +} + +void OperationValidator::visit(const ir::operation::Transpose &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Transpose::Input::INPUT)}; + const auto &perm{node.param().perm}; + + const auto &output_shape = _ctx.at(output_index).shape(); + const auto &input_shape = _ctx.at(input_index).shape(); + + UNUSED_RELEASE(output_shape); + UNUSED_RELEASE(input_shape); + UNUSED_RELEASE(perm); + + assert(input_shape.rank() == static_cast(perm.size())); + assert(input_shape.rank() == output_shape.rank()); +} + +void OperationValidator::visit(const ir::operation::ReduceMax &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::ReduceMax::Input::INPUT)}; + const auto &axes = node.param().axes; + + auto output_shape = _ctx.at(output_index).shape(); + auto input_shape = _ctx.at(input_index).shape(); + + UNUSED_RELEASE(output_shape); + UNUSED_RELEASE(input_shape); + UNUSED_RELEASE(axes); + + assert(input_shape.rank() <= 4); + assert(output_shape.rank() <= input_shape.rank()); + + // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only + // supports cases reducing height and width or reducing depth. + // TODO We have to support all cases of dimensions up to 4. + // For correct permuting, we have to set output's shape to be equal in dimension position of the + // input. But the positions of the same dimensions in the input and output may be set differently. + // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original + // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to + // extend it in 4 dimensions, it should be {1,1,3,5}. + // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of + // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the + // next operation is not desired. + if (input_shape.rank() == 4 && input_shape.rank() != output_shape.rank()) + { + if (output_shape.rank() == 2) + { + // Reducing HW + assert(input_shape.dim(0) == output_shape.dim(0) && + input_shape.dim(3) == output_shape.dim(1)); + } + else if (output_shape.rank() == 3) + { + // Reducing C or + // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1) + assert((input_shape.dim(0) == output_shape.dim(0) && + input_shape.dim(1) == output_shape.dim(1) && + input_shape.dim(2) == output_shape.dim(2)) || + (input_shape.dim(0) == output_shape.dim(0) && + (input_shape.dim(1) == output_shape.dim(1) || + input_shape.dim(2) == output_shape.dim(1)) && + input_shape.dim(3) == 1 && output_shape.dim(2) == 1)); + } + } +} + +void OperationValidator::visit(const ir::operation::RNN &node) +{ + // NOTE This validation is for static rnn(non-dynamic shape), but not for dynamic rnn + // TODO Support dynamic rnn + const auto output_index{node.getOutputs().at(ir::operation::RNN::Output::OUTPUT)}; + const auto hidden_state_out_index{ + node.getOutputs().at(ir::operation::RNN::Output::HIDDEN_STATE_OUT)}; + + const auto input_index{node.getInputs().at(ir::operation::RNN::Input::INPUT)}; + const auto weights_index{node.getInputs().at(ir::operation::RNN::Input::WEIGHTS)}; + const auto recurrent_weights_index{ + node.getInputs().at(ir::operation::RNN::Input::RECURRENT_WEIGHTS)}; + const auto bias_index{node.getInputs().at(ir::operation::RNN::Input::BIAS)}; + const auto hidden_state_in_index{node.getInputs().at(ir::operation::RNN::Input::HIDDEN_STATE_IN)}; + + const auto batch_size = _ctx.at(output_index).shape().dim(0); + const auto num_units = _ctx.at(output_index).shape().dim(1); + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(hidden_state_out_index); + UNUSED_RELEASE(input_index); + UNUSED_RELEASE(weights_index); + UNUSED_RELEASE(recurrent_weights_index); + UNUSED_RELEASE(bias_index); + UNUSED_RELEASE(hidden_state_in_index); + UNUSED_RELEASE(batch_size); + UNUSED_RELEASE(num_units); + + assert(_ctx.at(output_index).shape().rank() == 2 && + _ctx.at(hidden_state_out_index).shape().rank() == 2 && + _ctx.at(input_index).shape().rank() == 2 && _ctx.at(weights_index).shape().rank() == 2 && + _ctx.at(recurrent_weights_index).shape().rank() == 2 && + _ctx.at(hidden_state_in_index).shape().rank() == 2); + assert(_ctx.at(bias_index).shape().rank() == 1); + + assert(batch_size == _ctx.at(input_index).shape().dim(0) && + batch_size == _ctx.at(hidden_state_in_index).shape().dim(0) && + batch_size == _ctx.at(hidden_state_out_index).shape().dim(0)); + assert(_ctx.at(input_index).shape().dim(1) == _ctx.at(weights_index).shape().dim(1)); + + assert(num_units == _ctx.at(weights_index).shape().dim(0) && + num_units == _ctx.at(recurrent_weights_index).shape().dim(0) && + num_units == _ctx.at(bias_index).shape().dim(0)); + assert(num_units == _ctx.at(output_index).shape().dim(1) && + num_units == _ctx.at(recurrent_weights_index).shape().dim(1) && + num_units == _ctx.at(hidden_state_in_index).shape().dim(1) && + num_units == _ctx.at(hidden_state_out_index).shape().dim(1)); +} + +void OperationValidator::visit(const ir::operation::SpaceToBatchND &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::INPUT)}; + const auto block_size_index{ + node.getInputs().at(ir::operation::SpaceToBatchND::Input::BLOCK_SIZE)}; + const auto paddings_index{node.getInputs().at(ir::operation::SpaceToBatchND::Input::PADDINGS)}; + + const auto frontend_layout = _current_op_seq_layout; + const auto input_shape = _ctx.at(ifm_index).shape().asFeature(frontend_layout); + const auto output_shape = _ctx.at(ofm_index).shape().asFeature(frontend_layout); + + UNUSED_RELEASE(input_shape); + UNUSED_RELEASE(output_shape); + UNUSED_RELEASE(block_size_index); + UNUSED_RELEASE(paddings_index); + + // All assertions as per NNAPI specification. + assert(_ctx.at(ifm_index).shape().rank() == 4); + assert(_ctx.at(ofm_index).shape().rank() == 4); + assert(_ctx.at(block_size_index).shape().rank() == 1); + assert(_ctx.at(paddings_index).shape().rank() == 2); + + assert(_ctx.at(block_size_index).shape().dim(0) == 2); + assert(_ctx.at(paddings_index).shape().dim(0) == 2); + assert(_ctx.at(paddings_index).shape().dim(1) == 2); + + assert(_ctx.at(block_size_index).isConstant()); + assert(_ctx.at(paddings_index).isConstant()); + + assert(input_shape.C == output_shape.C); +} + +void OperationValidator::visit(const ir::operation::SpaceToDepth &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::SpaceToDepth::Input::INPUT)}; + + const auto frontend_layout = _current_op_seq_layout; + const auto input_shape = _ctx.at(ifm_index).shape().asFeature(frontend_layout); + const auto output_shape = _ctx.at(ofm_index).shape().asFeature(frontend_layout); + const auto block_size = node.param().block_size; + + UNUSED_RELEASE(input_shape); + UNUSED_RELEASE(output_shape); + UNUSED_RELEASE(block_size); + + // All assertions as per NNAPI specification. + assert(_ctx.at(ifm_index).shape().rank() == 4); + assert(_ctx.at(ofm_index).shape().rank() == 4); + assert((block_size >= 1) && (input_shape.H % block_size == 0) && + (input_shape.W % block_size == 0)); + assert(input_shape.N == output_shape.N); + assert(input_shape.C * block_size * block_size == output_shape.C); +} + +void OperationValidator::visit(const ir::operation::EmbeddingLookup &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto lookups_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::LOOKUPS)}; + const auto values_index{node.getInputs().at(ir::operation::EmbeddingLookup::Input::VALUES)}; + + const auto &output_obj = _ctx.at(output_index); + const auto &lookups_obj = _ctx.at(lookups_index); + const auto &values_obj = _ctx.at(values_index); + + UNUSED_RELEASE(output_obj); + UNUSED_RELEASE(lookups_obj); + UNUSED_RELEASE(values_obj); + + // Verify operand here, not at SimpleEmbeddingLookup::configure() to avoid acl's modifying + // TensorShape sometimes(Issue: https://github.sec.samsung.net/STAR/nnfw/issues/729) + { + assert(lookups_obj.typeInfo().type() == ir::DataType::INT32); + + const auto &output_shape = output_obj.shape(); + const auto &lookups_shape = lookups_obj.shape(); + const auto &values_shape = values_obj.shape(); + + UNUSED_RELEASE(output_shape); + UNUSED_RELEASE(lookups_shape); + UNUSED_RELEASE(values_shape); + + assert(lookups_shape.rank() == 1); + assert(values_shape.rank() >= 2); + + // output should be a n-D tensor with the same rank and shape as the values tensor, except for + // the first dimension which has the same size as lookups' only dimension. + assert(output_shape.rank() == values_shape.rank()); + assert(output_shape.dim(0) == lookups_shape.dim(0)); + for (int n = 1; n < output_shape.rank(); ++n) + { + assert(output_shape.dim(n) == values_shape.dim(n)); + } + } +} + +void OperationValidator::visit(const ir::operation::Exp &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Exp::Input::INPUT)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape()); + assert(_ctx.at(output_index).typeInfo().type() == _ctx.at(input_index).typeInfo().type()); +} + +void OperationValidator::visit(const ir::operation::Floor &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Floor::Input::INPUT)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape()); + assert(_ctx.at(output_index).typeInfo().type() == _ctx.at(input_index).typeInfo().type()); +} + +void OperationValidator::visit(const ir::operation::HashtableLookup &node) +{ + const auto output_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::OUTPUT)}; + const auto hits_index{node.getOutputs().at(ir::operation::HashtableLookup::Output::HITS)}; + + const auto lookups_index{node.getInputs().at(ir::operation::HashtableLookup::Input::LOOKUPS)}; + const auto keys_index{node.getInputs().at(ir::operation::HashtableLookup::Input::KEYS)}; + const auto values_index{node.getInputs().at(ir::operation::HashtableLookup::Input::VALUES)}; + + const auto &output_obj = _ctx.at(output_index); + const auto &hits_obj = _ctx.at(hits_index); + + const auto &lookups_obj = _ctx.at(lookups_index); + const auto &keys_obj = _ctx.at(keys_index); + const auto &values_obj = _ctx.at(values_index); + + assert(lookups_obj.typeInfo().type() == ir::DataType::INT32); + assert(keys_obj.typeInfo().type() == ir::DataType::INT32); + assert(hits_obj.typeInfo().type() == ir::DataType::QUANT8_ASYMM); + + const auto &output_shape = output_obj.shape(); + const auto &hits_shape = hits_obj.shape(); + + const auto &lookups_shape = lookups_obj.shape(); + const auto &keys_shape = keys_obj.shape(); + const auto &values_shape = values_obj.shape(); + + UNUSED_RELEASE(output_shape); + UNUSED_RELEASE(hits_shape); + UNUSED_RELEASE(lookups_shape); + UNUSED_RELEASE(keys_shape); + UNUSED_RELEASE(values_shape); + + assert(values_shape.rank() == output_shape.rank()); + assert(lookups_shape.rank() == 1); + assert(keys_shape.rank() == 1); + assert(values_shape.dim(0) == keys_shape.dim(0)); + assert(lookups_shape.dim(0) == output_shape.dim(0)); +} + +void OperationValidator::visit(const ir::operation::TransposeConv &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::TransposeConv::Input::INPUT)}; + const auto ker_index{node.getInputs().at(ir::operation::TransposeConv::Input::KERNEL)}; + + // Only 4D tensors are supported + assert(_ctx.at(ofm_index).shape().rank() == 4); + assert(_ctx.at(ofm_index).shape().rank() == _ctx.at(ifm_index).shape().rank()); + assert(_ctx.at(ofm_index).shape().rank() == _ctx.at(ker_index).shape().rank()); + + const auto frontend_layout = _current_op_seq_layout; + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(frontend_layout); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(frontend_layout); + // The kernel has only IHWO layout on frontend + // So ker_shape is treated here below + // I -> N + // H -> H + // W -> W + // O -> C + const auto ker_shape = _ctx.at(ker_index).shape().asFeature(ir::Layout::NHWC); + + UNUSED_RELEASE(ofm_shape); + UNUSED_RELEASE(ifm_shape); + UNUSED_RELEASE(ker_shape); + + assert((node.param().padding.type == ir::PaddingType::SAME) || + (node.param().padding.type == ir::PaddingType::VALID)); + assert(ifm_shape.N == ofm_shape.N); + assert(ifm_shape.C == ker_shape.C); + assert(ker_shape.N == ofm_shape.C); +} + +void OperationValidator::visit(const ir::operation::Gather &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + + const auto ifm_index{node.getInputs().at(ir::operation::Gather::Input::INPUT)}; + const auto indices_index{node.getInputs().at(ir::operation::Gather::Input::INDICES)}; + + const auto axis = node.param().axis; + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + const auto indices_shape = _ctx.at(indices_index).shape(); + const auto ofm_shape = _ctx.at(ofm_index).shape(); + + UNUSED_RELEASE(ifm_shape); + UNUSED_RELEASE(indices_shape); + UNUSED_RELEASE(ofm_shape); + UNUSED_RELEASE(axis); + + assert(ifm_shape.rank() <= 4); + assert(indices_shape.rank() <= 3); + assert(ofm_shape.rank() <= 4); +} + +void OperationValidator::visit(const ir::operation::Dequantize &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::Dequantize::Input::INPUT)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(input_index).shape().rank() <= 4); + assert(_ctx.at(input_index).shape() == _ctx.at(output_index).shape()); + assert(_ctx.at(input_index).typeInfo().type() == ir::DataType::QUANT8_ASYMM); + assert(_ctx.at(output_index).typeInfo().type() == ir::DataType::FLOAT32); +} + +void OperationValidator::visit(const ir::operation::Mean &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::Mean::Input::INPUT)}; + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + const auto ofm_shape = _ctx.at(ofm_index).shape(); + + // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only + // supports cases reducing height and width or reducing depth. + // TODO We have to support all cases of dimensions up to 4. + // For correct permuting, we have to set output's shape to be equal in dimension position of the + // input. But the positions of the same dimensions in the input and output may be set differently. + // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original + // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to + // extend it in 4 dimensions, it should be {1,1,3,5}. + // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of + // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the + // next operation is not desired. + if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank()) + { + if (ofm_shape.rank() == 2) + { + // Reducing HW + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1)); + } + else if (ofm_shape.rank() == 3) + { + // Reducing C or + // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1) + assert((ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) && + ifm_shape.dim(2) == ofm_shape.dim(2)) || + (ifm_shape.dim(0) == ofm_shape.dim(0) && + (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) && + ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1)); + } + } +} + +void OperationValidator::visit(const ir::operation::DepthToSpace &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::DepthToSpace::Input::INPUT)}; + + const auto frontend_layout = _current_op_seq_layout; + const auto output_shape = _ctx.at(output_index).shape().asFeature(frontend_layout); + const auto input_shape = _ctx.at(input_index).shape().asFeature(frontend_layout); + + UNUSED_RELEASE(output_shape); + UNUSED_RELEASE(input_shape); + + assert(_ctx.at(input_index).shape().rank() == 4); + assert(_ctx.at(output_index).shape().rank() == 4); + + int32_t block_size = node.param().block_size; + + UNUSED_RELEASE(block_size); + + assert(block_size > 0); + + { // assertions block + assert(output_shape.N == input_shape.N); + assert(output_shape.H == input_shape.H * block_size); + assert(output_shape.W == input_shape.W * block_size); + assert(input_shape.C % (block_size * block_size) == 0); + assert(output_shape.C == input_shape.C / (block_size * block_size)); + } +} + +void OperationValidator::visit(const ir::operation::Pack &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto num{node.param().num}; + const auto axis{node.param().axis}; + + const auto &output_shape = _ctx.at(output_index).shape(); + const auto output_rank = static_cast(output_shape.rank()); + + const auto input1_index{node.getInputs().at(0)}; + const auto input_shape = _ctx.at(input1_index).shape(); + + UNUSED_RELEASE(num); + UNUSED_RELEASE(axis); + UNUSED_RELEASE(output_rank); + + assert(num == static_cast(node.getInputs().size())); + assert(axis >= -output_rank && axis < output_rank); + for (const auto &index : node.getInputs()) + { + UNUSED_RELEASE(index); + assert(input_shape == _ctx.at(index).shape()); + } +} + +void OperationValidator::visit(const ir::operation::ReduceMin &node) +{ + const auto ofm_index{node.getOutputs().at(0)}; + const auto ifm_index{node.getInputs().at(ir::operation::ReduceMin::Input::INPUT)}; + const auto &axes = node.param().axes; + + auto ifm_shape = _ctx.at(ifm_index).shape(); + auto ofm_shape = _ctx.at(ofm_index).shape(); + + UNUSED_RELEASE(ifm_shape); + UNUSED_RELEASE(ofm_shape); + UNUSED_RELEASE(axes); + + assert(ifm_shape.rank() <= 4); + assert(ofm_shape.rank() <= ifm_shape.rank()); + + // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only + // supports cases reducing height and width or reducing depth. + // TODO We have to support all cases of dimensions up to 4. + // For correct permuting, we have to set output's shape to be equal in dimension position of the + // input. But the positions of the same dimensions in the input and output may be set differently. + // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original + // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to + // extend it in 4 dimensions, it should be {1,1,3,5}. + // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of + // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the + // next operation is not desired. + if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank()) + { + if (ofm_shape.rank() == 2) + { + // Reducing HW + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1)); + } + else if (ofm_shape.rank() == 3) + { + // Reducing C or + // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1) + assert((ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) && + ifm_shape.dim(2) == ofm_shape.dim(2)) || + (ifm_shape.dim(0) == ofm_shape.dim(0) && + (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) && + ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1)); + } + } +} + +void OperationValidator::visit(const ir::operation::LSTM &node) +{ + // NOTE This validation is for static rnn(non-dynamic shape), but not for dynamic rnn + // TODO Support dynamic rnn + const auto scratch_buffer_index{ + node.getOutputs().at(ir::operation::LSTM::Output::SCRATCH_BUFFER)}; + const auto output_state_out_index{ + node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT_STATE_OUT)}; + const auto cell_state_out_index{ + node.getOutputs().at(ir::operation::LSTM::Output::CELL_STATE_OUT)}; + const auto output_index{node.getOutputs().at(ir::operation::LSTM::Output::OUTPUT)}; + + const auto input_index{node.getInputs().at(ir::operation::LSTM::Input::INPUT)}; + const auto input_to_input_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_INPUT_WEIGHTS)}; + const auto input_to_forget_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_FORGET_WEIGHTS)}; + const auto input_to_cell_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_CELL_WEIGHTS)}; + const auto input_to_output_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)}; + const auto recurrent_to_input_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)}; + const auto recurrent_to_forget_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS)}; + const auto recurrent_to_cell_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_CELL_WEIGHTS)}; + const auto recurrent_to_output_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS)}; + const auto cell_to_input_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_INPUT_WEIGHTS)}; + const auto cell_to_forget_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_FORGET_WEIGHTS)}; + const auto cell_to_output_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::CELL_TO_OUTPUT_WEIGHTS)}; + const auto input_gate_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::INPUT_GATE_BIAS)}; + const auto forget_gate_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::FORGET_GATE_BIAS)}; + const auto cell_bias_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_BIAS)}; + const auto output_gate_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_GATE_BIAS)}; + const auto projection_weights_index{ + node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_WEIGHTS)}; + const auto projection_bias_index{ + node.getInputs().at(ir::operation::LSTM::Input::PROJECTION_BIAS)}; + const auto output_state_in_index{ + node.getInputs().at(ir::operation::LSTM::Input::OUTPUT_STATE_IN)}; + const auto cell_state_in_index{node.getInputs().at(ir::operation::LSTM::Input::CELL_STATE_IN)}; + + UNUSED_RELEASE(scratch_buffer_index); + UNUSED_RELEASE(output_state_out_index); + UNUSED_RELEASE(cell_state_out_index); + UNUSED_RELEASE(output_index); + + UNUSED_RELEASE(input_index); + UNUSED_RELEASE(input_to_input_weights_index); + UNUSED_RELEASE(input_to_forget_weights_index); + UNUSED_RELEASE(input_to_cell_weights_index); + UNUSED_RELEASE(input_to_output_weights_index); + UNUSED_RELEASE(recurrent_to_input_weights_index); + UNUSED_RELEASE(recurrent_to_forget_weights_index); + UNUSED_RELEASE(recurrent_to_cell_weights_index); + UNUSED_RELEASE(recurrent_to_output_weights_index); + UNUSED_RELEASE(cell_to_input_weights_index); + UNUSED_RELEASE(cell_to_forget_weights_index); + UNUSED_RELEASE(cell_to_output_weights_index); + UNUSED_RELEASE(input_gate_bias_index); + UNUSED_RELEASE(forget_gate_bias_index); + UNUSED_RELEASE(cell_bias_index); + UNUSED_RELEASE(output_gate_bias_index); + UNUSED_RELEASE(projection_weights_index); + UNUSED_RELEASE(projection_bias_index); + UNUSED_RELEASE(output_state_in_index); + UNUSED_RELEASE(cell_state_in_index); + + assert(_ctx.at(scratch_buffer_index).shape().rank() == 2 && + _ctx.at(output_state_out_index).shape().rank() == 2 && + _ctx.at(cell_state_out_index).shape().rank() == 2 && + _ctx.at(output_index).shape().rank() == 2 && _ctx.at(input_index).shape().rank() == 2 && + _ctx.at(input_to_input_weights_index).shape().rank() == 2 && + _ctx.at(input_to_forget_weights_index).shape().rank() == 2 && + _ctx.at(input_to_cell_weights_index).shape().rank() == 2 && + _ctx.at(input_to_output_weights_index).shape().rank() == 2 && + _ctx.at(recurrent_to_input_weights_index).shape().rank() == 2 && + _ctx.at(recurrent_to_forget_weights_index).shape().rank() == 2 && + _ctx.at(recurrent_to_cell_weights_index).shape().rank() == 2 && + _ctx.at(recurrent_to_output_weights_index).shape().rank() == 2 && + _ctx.at(projection_weights_index).shape().rank() == 2 && + _ctx.at(output_state_in_index).shape().rank() == 2 && + _ctx.at(cell_state_in_index).shape().rank() == 2); + + assert(_ctx.at(cell_to_input_weights_index).shape().rank() == 1 && + _ctx.at(cell_to_forget_weights_index).shape().rank() == 1 && + _ctx.at(cell_to_output_weights_index).shape().rank() == 1 && + _ctx.at(input_gate_bias_index).shape().rank() == 1 && + _ctx.at(forget_gate_bias_index).shape().rank() == 1 && + _ctx.at(cell_bias_index).shape().rank() == 1 && + _ctx.at(output_gate_bias_index).shape().rank() == 1 && + _ctx.at(projection_bias_index).shape().rank() == 1); + + // CIFG assertion + assert((_ctx.at(input_to_input_weights_index).shape().dim(0) == 0 && + _ctx.at(input_to_input_weights_index).shape().dim(1) == 0 && + _ctx.at(recurrent_to_input_weights_index).shape().dim(0) == 0 && + _ctx.at(recurrent_to_input_weights_index).shape().dim(1) == 0 && + _ctx.at(input_gate_bias_index).shape().dim(0) == 0 && + _ctx.at(cell_to_input_weights_index).shape().dim(0) == 0) || + (_ctx.at(input_to_input_weights_index).shape().dim(0) != 0 && + _ctx.at(input_to_input_weights_index).shape().dim(1) != 0 && + _ctx.at(recurrent_to_input_weights_index).shape().dim(0) != 0 && + _ctx.at(recurrent_to_input_weights_index).shape().dim(1) != 0 && + _ctx.at(input_gate_bias_index).shape().dim(0) != 0)); + + // Peephole assertion + assert((_ctx.at(cell_to_forget_weights_index).shape().dim(0) == 0 && + _ctx.at(cell_to_output_weights_index).shape().dim(0) == 0) || + (_ctx.at(cell_to_forget_weights_index).shape().dim(0) != 0 && + _ctx.at(cell_to_output_weights_index).shape().dim(0) != 0)); + + bool has_input_to_input_weights = _ctx.at(input_to_input_weights_index).shape().dim(0) != 0 && + _ctx.at(input_to_input_weights_index).shape().dim(1) != 0; + bool has_recurrent_to_input_weights = + _ctx.at(recurrent_to_input_weights_index).shape().dim(0) != 0 && + _ctx.at(recurrent_to_input_weights_index).shape().dim(1) != 0; + bool has_input_gate_bias = _ctx.at(input_gate_bias_index).shape().dim(0) != 0; + bool has_cell_to_input_weights = _ctx.at(cell_to_input_weights_index).shape().dim(0) != 0; + bool has_cell_to_forget_weights = _ctx.at(cell_to_forget_weights_index).shape().dim(0) != 0; + bool has_cell_to_output_weights = _ctx.at(cell_to_output_weights_index).shape().dim(0) != 0; + bool has_projection_weights = _ctx.at(projection_weights_index).shape().dim(0) != 0 && + _ctx.at(projection_weights_index).shape().dim(1) != 0; + bool has_projection_bias = _ctx.at(projection_bias_index).shape().dim(0); + + // NOTE The cell_to_input_weights do not exist in non-peephole although regular LSTM(non-CIFG). + // true: no CIFG + // false: CIFG + bool has_cifg_param = has_input_to_input_weights && has_recurrent_to_input_weights; + + // NOTE The cell_to_input_weights do not exist in regular CIFG although peephole. + // true: peephole + // false: no peephole + bool has_peephole_param = has_cell_to_forget_weights && has_cell_to_output_weights; + + // NOTE The projection weights may have data but the projection bias may not. + bool has_projection_param = has_projection_weights; + + UNUSED_RELEASE(has_input_to_input_weights); + UNUSED_RELEASE(has_recurrent_to_input_weights); + UNUSED_RELEASE(has_input_gate_bias); + UNUSED_RELEASE(has_cell_to_input_weights); + UNUSED_RELEASE(has_cell_to_forget_weights); + UNUSED_RELEASE(has_cell_to_output_weights); + UNUSED_RELEASE(has_projection_weights); + UNUSED_RELEASE(has_projection_bias); + UNUSED_RELEASE(has_cifg_param); + UNUSED_RELEASE(has_peephole_param); + UNUSED_RELEASE(has_projection_param); + + const auto batch_size = _ctx.at(input_index).shape().dim(0); + UNUSED_RELEASE(batch_size); + assert(batch_size == _ctx.at(output_state_in_index).shape().dim(0) && + batch_size == _ctx.at(cell_state_in_index).shape().dim(0) && + batch_size == _ctx.at(scratch_buffer_index).shape().dim(0) && + batch_size == _ctx.at(output_state_out_index).shape().dim(0) && + batch_size == _ctx.at(cell_state_out_index).shape().dim(0) && + batch_size == _ctx.at(output_index).shape().dim(0)); + + const auto input_size = _ctx.at(input_index).shape().dim(1); + UNUSED_RELEASE(input_size); + assert(input_size == _ctx.at(input_to_forget_weights_index).shape().dim(1) && + input_size == _ctx.at(input_to_cell_weights_index).shape().dim(1) && + input_size == _ctx.at(input_to_output_weights_index).shape().dim(1)); + + const auto num_units = _ctx.at(cell_state_out_index).shape().dim(1); + UNUSED_RELEASE(num_units); + assert(num_units == _ctx.at(input_to_forget_weights_index).shape().dim(0) && + num_units == _ctx.at(input_to_cell_weights_index).shape().dim(0) && + num_units == _ctx.at(input_to_output_weights_index).shape().dim(0) && + num_units == _ctx.at(recurrent_to_forget_weights_index).shape().dim(0) && + num_units == _ctx.at(recurrent_to_cell_weights_index).shape().dim(0) && + num_units == _ctx.at(recurrent_to_output_weights_index).shape().dim(0) && + num_units == _ctx.at(forget_gate_bias_index).shape().dim(0) && + num_units == _ctx.at(cell_bias_index).shape().dim(0) && + num_units == _ctx.at(output_gate_bias_index).shape().dim(0) && + num_units == _ctx.at(cell_state_in_index).shape().dim(1) && + (((num_units * 3) == _ctx.at(scratch_buffer_index).shape().dim(1)) || + ((num_units * 4) == _ctx.at(scratch_buffer_index).shape().dim(1)))); + + const auto output_size = _ctx.at(output_index).shape().dim(1); + UNUSED_RELEASE(output_size); + assert(output_size == _ctx.at(recurrent_to_forget_weights_index).shape().dim(1) && + output_size == _ctx.at(recurrent_to_cell_weights_index).shape().dim(1) && + output_size == _ctx.at(recurrent_to_output_weights_index).shape().dim(1) && + output_size == _ctx.at(output_state_in_index).shape().dim(1) && + output_size == _ctx.at(output_state_out_index).shape().dim(1)); + + if (has_cifg_param) + { + assert(input_size == _ctx.at(input_to_input_weights_index).shape().dim(1)); + assert(num_units == _ctx.at(input_to_input_weights_index).shape().dim(0) && + num_units == _ctx.at(recurrent_to_input_weights_index).shape().dim(0) && + (num_units == _ctx.at(cell_to_input_weights_index).shape().dim(0) || + _ctx.at(cell_to_input_weights_index).shape().dim(0) == 0 /* non-peephole */) && + num_units == _ctx.at(input_gate_bias_index).shape().dim(0)); + assert(output_size == _ctx.at(recurrent_to_input_weights_index).shape().dim(1)); + assert(has_input_to_input_weights && has_recurrent_to_input_weights && has_input_gate_bias); + if (has_cell_to_input_weights) + { + // NOTE The cell_to_input_weights exist only in case of non-CIFG and peephole. + assert(has_peephole_param); + } + assert(_ctx.at(scratch_buffer_index).shape().dim(1) == num_units * 4); + } + else + { + assert(_ctx.at(scratch_buffer_index).shape().dim(1) == num_units * 3); + } + + if (has_peephole_param) + { + assert(num_units == _ctx.at(cell_to_forget_weights_index).shape().dim(0) && + num_units == _ctx.at(cell_to_output_weights_index).shape().dim(0) && + (num_units == _ctx.at(cell_to_input_weights_index).shape().dim(0) || + _ctx.at(cell_to_input_weights_index).shape().dim(0) == 0 /* CIFG */)); + } + + if (has_projection_param) + { + assert(num_units == _ctx.at(projection_weights_index).shape().dim(1)); + assert(output_size == _ctx.at(projection_weights_index).shape().dim(0)); + if (has_projection_bias) + { + assert(output_size == _ctx.at(projection_bias_index).shape().dim(0)); + } + } +} + +void OperationValidator::visit(const ir::operation::Unpack &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Unpack::Input::INPUT)}; + const auto num{node.param().num}; + const auto axis{node.param().axis}; + + const auto &input_shape = _ctx.at(input_index).shape(); + const auto input_rank = static_cast(input_shape.rank()); + + UNUSED_RELEASE(num); + UNUSED_RELEASE(axis); + UNUSED_RELEASE(input_rank); + + assert(num == static_cast(node.getOutputs().size())); + assert(axis >= -input_rank && axis < input_rank); +} + +void OperationValidator::visit(const ir::operation::Pad &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Pad::Input::INPUT)}; + const auto pad_index{node.getInputs().at(ir::operation::Pad::Input::PAD)}; + const auto output_index{node.getInputs().at(0)}; + + const auto &pad_shape = _ctx.at(pad_index).shape(); + const auto input_rank = static_cast(_ctx.at(input_index).shape().rank()); + + UNUSED_RELEASE(pad_shape); + UNUSED_RELEASE(input_rank); + UNUSED_RELEASE(output_index); + + assert(pad_shape.rank() == 2); + assert(pad_shape.dim(0) == input_rank); + assert(pad_shape.dim(1) == 2); + assert(_ctx.at(pad_index).typeInfo().type() == ir::DataType::INT32); + assert(_ctx.at(input_index).shape().rank() == _ctx.at(output_index).shape().rank()); +} + +void OperationValidator::visit(const ir::operation::Min &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Min::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Min::Input::RHS)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(lhs_index); + UNUSED_RELEASE(rhs_index); + + assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(rhs_index).typeInfo().type()); + assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(output_index).typeInfo().type()); +} + +void OperationValidator::visit(const ir::operation::Max &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto lhs_index{node.getInputs().at(ir::operation::Max::Input::LHS)}; + const auto rhs_index{node.getInputs().at(ir::operation::Max::Input::RHS)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(lhs_index); + UNUSED_RELEASE(rhs_index); + + assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(rhs_index).typeInfo().type()); + assert(_ctx.at(lhs_index).typeInfo().type() == _ctx.at(output_index).typeInfo().type()); +} + +void OperationValidator::visit(const ir::operation::StridedSlice &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(ir::operation::StridedSlice::Input::INPUT)}; + const auto starts_index{node.getInputs().at(ir::operation::StridedSlice::Input::STARTS)}; + const auto ends_index{node.getInputs().at(ir::operation::StridedSlice::Input::ENDS)}; + const auto strides_index{node.getInputs().at(ir::operation::StridedSlice::Input::STRIDES)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + UNUSED_RELEASE(starts_index); + UNUSED_RELEASE(ends_index); + UNUSED_RELEASE(strides_index); + + assert(_ctx.at(output_index).typeInfo().type() == _ctx.at(input_index).typeInfo().type()); + assert(_ctx.at(input_index).shape().rank() <= 4); +} + +void OperationValidator::visit(const ir::operation::Split &node) +{ + const auto input_index{node.getInputs().at(ir::operation::Split::Input::INPUT)}; + const auto &num_splits = node.param().num_splits; + const auto &input_rank = node.param().rank; + const auto &axis = node.param().axis < 0 ? node.param().axis + input_rank : node.param().axis; + + UNUSED_RELEASE(input_index); + UNUSED_RELEASE(num_splits); + UNUSED_RELEASE(input_rank); + UNUSED_RELEASE(axis); + + assert(num_splits > 0 && num_splits <= 0xFFFF); + assert(axis >= 0 && axis < input_rank); + assert(_ctx.at(input_index).shape().dim(axis) % num_splits == 0); + assert(node.getOutputs().size() == static_cast(num_splits)); +} + +void OperationValidator::visit(const ir::operation::Sin &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape()); +} + +void OperationValidator::visit(const ir::operation::RSQRT &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape()); +} + +void OperationValidator::visit(const ir::operation::Shape &node) +{ + const auto output_index{node.getOutputs().at(0)}; + const auto input_index{node.getInputs().at(0)}; + + UNUSED_RELEASE(output_index); + UNUSED_RELEASE(input_index); + + assert(_ctx.at(output_index).shape().rank() == 1); +} + +} // namespace compiler +} // namespace onert diff --git a/runtime/onert/core/src/compiler/OperationValidator.h b/runtime/onert/core/src/compiler/OperationValidator.h new file mode 100644 index 000000000..10b0525c1 --- /dev/null +++ b/runtime/onert/core/src/compiler/OperationValidator.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_COMPILER_OPERATION_VALIDATOR_H__ +#define __ONERT_COMPILER_OPERATION_VALIDATOR_H__ + +#include "ir/Layout.h" +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +class Graph; +class Operands; +} // namespace ir +} // namespace onert + +namespace onert +{ +namespace compiler +{ + +class OperationValidator : public ir::OperationVisitor +{ +public: + OperationValidator(void) = delete; + OperationValidator(const ir::Graph &graph); + +public: + void operator()(); + +public: + void visit(const ir::operation::Abs &node) override; + void visit(const ir::operation::AvgPool2D &node) override; + void visit(const ir::operation::BatchToSpaceND &node) override; + void visit(const ir::operation::Cast &node) override; + void visit(const ir::operation::Comparison &node) override; + void visit(const ir::operation::Softmax &node) override; + void visit(const ir::operation::InstanceNorm &node) override; + void visit(const ir::operation::Permute &node) override; + void visit(const ir::operation::ReduceSum &node) override; + void visit(const ir::operation::Transpose &node) override; + void visit(const ir::operation::ReduceMax &node) override; + void visit(const ir::operation::RNN &node) override; + void visit(const ir::operation::SpaceToBatchND &node) override; + void visit(const ir::operation::SpaceToDepth &node) override; + void visit(const ir::operation::EmbeddingLookup &node) override; + void visit(const ir::operation::Exp &node) override; + void visit(const ir::operation::Floor &node) override; + void visit(const ir::operation::HashtableLookup &node) override; + void visit(const ir::operation::TransposeConv &node) override; + void visit(const ir::operation::Gather &node) override; + void visit(const ir::operation::Dequantize &node) override; + void visit(const ir::operation::Mean &node) override; + void visit(const ir::operation::DepthToSpace &node) override; + void visit(const ir::operation::Pack &node) override; + void visit(const ir::operation::ReduceMin &node) override; + void visit(const ir::operation::LSTM &node) override; + void visit(const ir::operation::Unpack &node) override; + void visit(const ir::operation::Pad &node) override; + void visit(const ir::operation::Min &node) override; + void visit(const ir::operation::Max &node) override; + void visit(const ir::operation::StridedSlice &node) override; + void visit(const ir::operation::Split &node) override; + void visit(const ir::operation::Sin &node) override; + void visit(const ir::operation::RSQRT &node) override; + void visit(const ir::operation::Shape &node) override; + +private: + // TODO Remove _ctx field + const ir::Graph &_graph; + const ir::Operands &_ctx; + ir::Layout _current_op_seq_layout; +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_OPERATION_VALIDATOR_H__ diff --git a/runtime/onert/core/src/compiler/ParamChecker.cc b/runtime/onert/core/src/compiler/ParamChecker.cc new file mode 100644 index 000000000..c4f80f087 --- /dev/null +++ b/runtime/onert/core/src/compiler/ParamChecker.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ParamChecker.h" + +#include "ir/Graph.h" + +namespace onert +{ +namespace compiler +{ + +void ParamChecker::operator()() +{ + _model->operations().iterate( + [&](const ir::OperationIndex &, const ir::Operation &node) { node.accept(*this); }); +} + +} // namespace compiler +} // namespace onert diff --git a/runtime/onert/core/src/compiler/ParamChecker.h b/runtime/onert/core/src/compiler/ParamChecker.h new file mode 100644 index 000000000..61429d521 --- /dev/null +++ b/runtime/onert/core/src/compiler/ParamChecker.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ParamChecker.h + * @brief This file contains ParamChecker to check\n + * operations' parameters are compilable at machine independent phase\n + * ex) Check param is constant + */ +#ifndef __ONERT_COMPILER_PARAM_CHECKER_H__ +#define __ONERT_COMPILER_PARAM_CHECKER_H__ + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +class Graph; +} // namespace ir +} // namespace onert + +namespace onert +{ +namespace compiler +{ + +class ParamChecker : public ir::OperationVisitor +{ +public: + /** + * @brief Construct a new Param Checker object (deleted) + */ + ParamChecker(void) = delete; + /** + * @brief Construct a new Param Checker object + * @param[in] model Graph model to check + */ + ParamChecker(std::shared_ptr model) : _model{model} {} + +public: + /** + * @brief Run parameter analysis + */ + void operator()(); + /** + * @brief Return analysis result if model have non-const parameter + * @return @c true if there is non-const parameter, otherwise @c false + */ + bool haveNoneConstParam(void) { return _nonConstParam; } + +private: + const std::shared_ptr _model; + bool _nonConstParam{false}; +}; + +} // namespace compiler +} // namespace onert + +#endif // __ONERT_COMPILER_OPERATION_VALIDATOR_H__ diff --git a/runtime/onert/core/src/dumper/dot/DotBuilder.cc b/runtime/onert/core/src/dumper/dot/DotBuilder.cc new file mode 100644 index 000000000..2a3a4af22 --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/DotBuilder.cc @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DotBuilder.h" + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +// DotDumper +DotBuilder::DotBuilder() {} + +void DotBuilder::update(const Node &node_info) +{ + add(node_info); + for (auto edge : node_info.edges()) + { + addEdge(node_info, *edge); + } +} + +void DotBuilder::addOpSequence(const DotOpSequenceInfo &op_sequence_info) +{ + _dot << "op_sequence cluster_" << op_sequence_info.index().value() << " {\n"; + _dot << " label=\"" << op_sequence_info.label() << "\";\n"; + _dot << " style=filled;\n"; + _dot << " color=lightgrey;\n"; + _dot << " "; + for (auto op : op_sequence_info.operations()) + { + _dot << "operation" << op.value() << "; "; + } + for (auto op : op_sequence_info.operands()) + { + _dot << "operand" << op.value() << "; "; + } + _dot << "\n"; + _dot << "}\n"; +} + +void DotBuilder::writeDot(std::ostream &os) +{ + os << "digraph D {\n" + << _dot.str() << "\n" + << "}\n"; +} + +void DotBuilder::add(const Node &node) +{ + _dot << node.id(); + std::stringstream ss; + _dot << "["; + for (auto attr : node.attributes()) + { + _dot << attr.first << "=\"" << attr.second << "\" "; + } + _dot << "];\n"; +} + +void DotBuilder::addEdge(const Node &node1, const Node &node2) +{ + _dot << node1.id() << " -> " << node2.id() << ";\n"; +} + +} // namespace dot +} // namespace dumper +} // namespace onert diff --git a/runtime/onert/core/src/dumper/dot/DotBuilder.h b/runtime/onert/core/src/dumper/dot/DotBuilder.h new file mode 100644 index 000000000..24a76533d --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/DotBuilder.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_DUMPER_DOT_DOT_BUILDER_H__ +#define __ONERT_DUMPER_DOT_DOT_BUILDER_H__ + +#include + +#include "ir/Index.h" +#include "ir/Operation.h" +#include "ir/Operand.h" + +#include "OperationNode.h" +#include "OperandNode.h" +#include "DotOpSequenceInfo.h" + +using Operation = onert::ir::Operation; +using Object = onert::ir::Operand; + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +class DotBuilder +{ +public: + DotBuilder(); + +public: + void update(const Node &dotinfo); + void addOpSequence(const DotOpSequenceInfo &op_sequence_info); + + void writeDot(std::ostream &os); + +private: + void add(const Node &dotinfo); + void addEdge(const Node &dotinfo1, const Node &dotinfo2); + + std::stringstream _dot; +}; + +} // namespace dot +} // namespace dumper +} // namespace onert + +#endif // __ONERT_DUMPER_DOT_DOT_BUILDER_H__ diff --git a/runtime/onert/core/src/dumper/dot/DotDumper.cc b/runtime/onert/core/src/dumper/dot/DotDumper.cc new file mode 100644 index 000000000..9bd8ed0ef --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/DotDumper.cc @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "DotDumper.h" +#include "DotBuilder.h" +#include "DotOpSequenceInfo.h" +#include "ir/OpSequence.h" +#include "ir/OperationIndexMap.h" +#include "backend/Backend.h" +#include "backend/IConfig.h" +#include "compiler/BackendManager.h" + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +void DotDumper::dump(const std::string &tag) +{ + if (_level == Level::OFF) + { + return; + } + + onert::dumper::dot::DotBuilder dot_builder; + + auto &operations = _graph.operations(); + auto &operands = _graph.operands(); + + ir::OperationIndexMap> operation_nodes; + std::unordered_map> operand_nodes; + + operations.iterate([&](const ir::OperationIndex &index, const ir::Operation &op) { + auto node = std::make_unique(index, op); + + for (auto output : op.getOutputs()) + { + using onert::dumper::dot::Operand; + auto child = std::make_shared(output, Operand::Type::MODEL_OUTPUT); + node->addEdge(child); + } + + operation_nodes.emplace(index, std::move(node)); + }); + + auto backend_to_fillcolor = [](const backend::Backend *backend) { + static const auto map = []() { + std::unordered_map ret; + uint32_t index = 1; // Start from 1 to avoid 0(red) which is too dark :( + for (const auto backend : compiler::BackendManager::get().getAll()) + { + ret.emplace(backend, Node::BG_COLORS[index]); + index = (index + 1) % (sizeof(Node::BG_COLORS) / sizeof(Node::BG_COLORS[0])); + } + return ret; + }(); + + auto itr = map.find(backend); + if (itr == map.end()) + { + return Node::DEFAULT_FILLCOLOR; + } + else + { + return itr->second; + } + }; + + util::Set shown_operand_set; + + operands.iterate([&](const ir::OperandIndex &index, const ir::Operand &object) { + bool showing_cond = false; + if (_level == Level::ALL) + { + showing_cond = true; + } + else + { + showing_cond = !object.isConstant(); + } + if (object.isConstant() || _graph.getInputs().contains(index)) + { + showing_cond = showing_cond && (object.getUses().size() > 0); + } + if (showing_cond) + { + shown_operand_set.add(index); + + auto type = [&]() { + using onert::dumper::dot::Operand; + if (_graph.getInputs().contains(index)) + return Operand::Type::MODEL_INPUT; + if (_graph.getOutputs().contains(index)) + return Operand::Type::MODEL_OUTPUT; + return Operand::Type::INTERNAL; + }(); + + auto node = std::make_unique(index, type); + + { + // Display LowerInfo attributes + std::string label = std::to_string(index.value()); + std::string fillcolor = ""; + if (_lowered_graph) + { + auto lower_info = _lowered_graph->getLowerInfo(index); + const auto &def_factors = lower_info->def_factors(); + if (def_factors.size() > 0) + { + label += "\\n["; + label += def_factors.getOnlyElement().backend()->config()->id(); + label += "]"; + + fillcolor = backend_to_fillcolor(lower_info->def_factors().getOnlyElement().backend()); + } + } + node->setAttribute("label", label); + node->setAttribute("fillcolor", fillcolor); + } + + for (auto operation_index : object.getUses().list()) + { + auto &operation = operations.at(operation_index); + auto child = std::make_shared(operation_index, operation); + node->addEdge(child); + } + + operand_nodes.emplace(index, std::move(node)); + } + }); + + if (_lowered_graph) + { + const auto &op_seqs = _lowered_graph->op_seqs(); + op_seqs.iterate([&](const ir::OpSequenceIndex &index, const ir::OpSequence &op_seq) { + const auto lower_info = _lowered_graph->getLowerInfo(index); + auto fillcolor = backend_to_fillcolor(lower_info->backend()); + std::string label = + std::to_string(index.value()) + " [" + lower_info->backend()->config()->id() + "]"; + DotOpSequenceInfo op_sequence_info{index, op_seq, shown_operand_set}; + op_sequence_info.label(label); + op_sequence_info.fillcolor(fillcolor); + dot_builder.addOpSequence(op_sequence_info); + + // Set fillcolor of all operations in the op_seq + for (const auto &op : op_seq.operations()) + { + auto found = operation_nodes.find(op.index); + if (found != operation_nodes.end()) + { + auto &&op = found->second; + op->setAttribute("fillcolor", fillcolor); + } + } + }); + } + + for (const auto &e : operation_nodes) + dot_builder.update(*e.second); + for (const auto &e : operand_nodes) + dot_builder.update(*e.second); + + // Dump to file + { + std::string file_name; + file_name += tag; + file_name += ".dot"; + std::filebuf fb; + + fb.open(file_name, std::ios::out); + std::ostream os(&fb); + + dot_builder.writeDot(os); + + fb.close(); + } +} + +} // namespace dot +} // namespace dumper +} // namespace onert diff --git a/runtime/onert/core/src/dumper/dot/DotDumper.h b/runtime/onert/core/src/dumper/dot/DotDumper.h new file mode 100644 index 000000000..668785a81 --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/DotDumper.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Graph.h" +#include "ir/LoweredGraph.h" + +#ifndef __ONERT_DUMPER_DOT_DOT_DUMPER_H__ +#define __ONERT_DUMPER_DOT_DOT_DUMPER_H__ + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +class DotDumper +{ +public: + enum Level + { + OFF = 0, //< Do not dump + ALL_BUT_CONSTANTS = 1, //< Emit all operations and operands but constants + ALL = 2 //< Emit all operations and operands + }; + +public: + DotDumper(const ir::Graph &graph, Level level) + : _lowered_graph{nullptr}, _graph(graph), _level{level} + { + } + DotDumper(const ir::LoweredGraph *lowered_graph, Level level) + : _lowered_graph{lowered_graph}, _graph(_lowered_graph->graph()), _level{level} + { + } + +public: + /** + * @brief Dump to dot file as tag name if "GRAPH_DOT_DUMP" is set + * + * @param[in] tag The name of dot file that would be created + * @return N/A + */ + void dump(const std::string &tag); + +private: + const ir::LoweredGraph *_lowered_graph; + const ir::Graph &_graph; + Level _level; +}; + +} // namespace dot +} // namespace dumper +} // namespace onert + +#endif // __ONERT_DUMPER_DOT_DOT_DUMPER_H__ diff --git a/runtime/onert/core/src/dumper/dot/DotOpSequenceInfo.cc b/runtime/onert/core/src/dumper/dot/DotOpSequenceInfo.cc new file mode 100644 index 000000000..48dafc834 --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/DotOpSequenceInfo.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DotOpSequenceInfo.h" + +#include + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +DotOpSequenceInfo::DotOpSequenceInfo(const ir::OpSequenceIndex &index, const ir::OpSequence &op_seq, + const util::Set &shown_operands) + : _index{index} +{ + for (const auto &element : op_seq.operations()) + { + _operations.insert(element.index); + for (auto o : element.node->getInputs()) + { + // Must be a shown operand, not op_seq's inputs + if (shown_operands.contains(o) && !op_seq.getInputs().contains(o)) + { + _operands.insert(o); + } + } + for (auto o : element.node->getOutputs()) + { + // Must be a shown operand, not op_seq's inputs + if (shown_operands.contains(o) && !op_seq.getOutputs().contains(o)) + { + _operands.insert(o); + } + } + } +} + +} // namespace dot +} // namespace dumper +} // namespace onert diff --git a/runtime/onert/core/src/dumper/dot/DotOpSequenceInfo.h b/runtime/onert/core/src/dumper/dot/DotOpSequenceInfo.h new file mode 100644 index 000000000..c30626cbf --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/DotOpSequenceInfo.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_CORE_DUMPER_DOT_DOT_SUBGRAPH_INFO_H__ +#define __ONERT_CORE_DUMPER_DOT_DOT_SUBGRAPH_INFO_H__ + +#include + +#include "ir/Index.h" +#include "ir/OpSequence.h" +#include "util/Set.h" + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +class DotOpSequenceInfo +{ +public: + DotOpSequenceInfo(const ir::OpSequenceIndex &index, const ir::OpSequence &op_seq, + const util::Set &shown_operands); + + ir::OpSequenceIndex index() const { return _index; } + std::string label() const { return _label; } + void label(const std::string &val) { _label = val; } + std::string fillcolor() const { return _fillcolor; } + void fillcolor(const std::string &val) { _fillcolor = val; } + const std::unordered_set &operations() const { return _operations; } + const std::unordered_set &operands() const { return _operands; } + +private: + ir::OpSequenceIndex _index; + std::string _label; + std::string _fillcolor; + std::unordered_set _operations; + std::unordered_set _operands; +}; + +} // namespace dot +} // namespace dumper +} // namespace onert + +#endif // __ONERT_CORE_DUMPER_DOT_DOT_SUBGRAPH_INFO_H__ diff --git a/runtime/onert/core/src/dumper/dot/Node.cc b/runtime/onert/core/src/dumper/dot/Node.cc new file mode 100644 index 000000000..85d6e67a4 --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/Node.cc @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Node.h" + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +const std::string Node::DEFAULT_COLORSCHEME = "x11"; +const std::string Node::DEFAULT_FILLCOLOR = "white"; +// RED, BLUE, GREEN, PURPLE, ORANGE, YELLOW, BROWN, PINK +const std::string Node::BG_COLORS[8] = {"1", "2", "3", "4", "5", "6", "7", "8"}; + +Node::Node(const std::string &id) : _id{id} +{ + // Set default values + _attributes["style"] = "filled"; + _attributes["colorscheme"] = DEFAULT_COLORSCHEME; + _attributes["fillcolor"] = DEFAULT_FILLCOLOR; +} + +void Node::setAttribute(const std::string &key, const std::string &val) { _attributes[key] = val; } + +std::string Node::getAttribute(const std::string &key) +{ + auto itr = _attributes.find(key); + if (itr == _attributes.end()) + { + return ""; + } + else + { + return itr->second; + } +} + +} // namespace dot +} // namespace dumper +} // namespace onert diff --git a/runtime/onert/core/src/dumper/dot/Node.h b/runtime/onert/core/src/dumper/dot/Node.h new file mode 100644 index 000000000..a5d1d51a4 --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/Node.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Node.h + * @brief This file contains Node class + * @ingroup COM_AI_RUNTIME + * + */ + +#ifndef __ONERT_DUMPER_DOT_NODE_H__ +#define __ONERT_DUMPER_DOT_NODE_H__ + +#include +#include +#include +#include + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +enum BGCOLORS : int +{ + RED, + BLUE, + GREEN, + PUPLE, + ORANGE, + YELLOW, + BROWN, + PINK +}; + +/** + * @brief Class that represents a Node in "dot" format + * + */ +class Node +{ +public: + const static std::string DEFAULT_FILLCOLOR; + const static std::string DEFAULT_COLORSCHEME; + const static std::string BG_COLORS[8]; + +public: + /** + * @brief Destroy the Node object + * + */ + virtual ~Node() = default; + + /** + * @brief Construct a new Node object + * + * @param id + */ + Node(const std::string &id); + + /** + * @brief return id + * + * @return id + */ + std::string id() const { return _id; } + + /** + * @brief return attributes + * + * @return const reference of attributes object + */ + const std::unordered_map &attributes() const { return _attributes; } + /** + * @brief Store an attribute with key-value pair + * + * @param[in] key attribute's key + * @param[in] val attribute's value that is associated with the key + */ + void setAttribute(const std::string &key, const std::string &val); + /** + * @brief Get the attributte value that is associated with key + * + * @param[in] key key of the attribute + * @return value that is associated with the key + */ + std::string getAttribute(const std::string &key); + + /** + * @brief Add an edge in the graph, which is an outgoing edge + * + * @param[in] dotinfo A node that the new edge will be connected to + */ + void addEdge(std::shared_ptr dotinfo) { _children.emplace_back(dotinfo); } + /** + * @brief Return list of edges + * + * @return Edges + */ + const std::vector> &edges() const { return _children; } + +private: + std::string _id; + std::unordered_map _attributes; + std::vector> _children; +}; + +} // namespace dot +} // namespace dumper +} // namespace onert + +#endif // __ONERT_DUMPER_DOT_NODE_H__ diff --git a/runtime/onert/core/src/dumper/dot/OperandNode.cc b/runtime/onert/core/src/dumper/dot/OperandNode.cc new file mode 100644 index 000000000..5a6015ca9 --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/OperandNode.cc @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperandNode.h" +#include "ir/Graph.h" +#include "ir/operand/LowerInfo.h" + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +const std::string Operand::INPUT_SHAPE = "doublecircle"; +const std::string Operand::OUTPUT_SHAPE = "doublecircle"; +const std::string Operand::OPERAND_SHAPE = "ellipse"; +const std::string Operand::BG_COLOR_SCHEME = "set18"; + +Operand::Operand(const ir::OperandIndex &index, Type type) + : Node{"operand" + std::to_string(index.value())} +{ + { + auto type_to_shape = [](Type type) { + switch (type) + { + case Type::MODEL_INPUT: + return INPUT_SHAPE; + case Type::MODEL_OUTPUT: + return OUTPUT_SHAPE; + case Type::UNDEFINED: + case Type::INTERNAL: + default: + return OPERAND_SHAPE; + } + }; + setAttribute("shape", type_to_shape(type)); + } + + setAttribute("colorscheme", BG_COLOR_SCHEME); +} + +} // namespace dot +} // namespace dumper +} // namespace onert diff --git a/runtime/onert/core/src/dumper/dot/OperandNode.h b/runtime/onert/core/src/dumper/dot/OperandNode.h new file mode 100644 index 000000000..2e7cc5861 --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/OperandNode.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Operand.h + * @brief This file contains Operand + * @ingroup COM_AI_RUNTIME + * + */ + +#ifndef __ONERT_DUMPER_DOT_DOT_OPERAND_INFO_H__ +#define __ONERT_DUMPER_DOT_DOT_OPERAND_INFO_H__ + +#include + +#include "Node.h" +#include "ir/Operand.h" +#include "ir/Index.h" + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +/** + * @brief Class that represents an Operand + * + */ +class Operand : public Node +{ +public: + enum class Type + { + UNDEFINED, + MODEL_INPUT, + MODEL_OUTPUT, + INTERNAL + }; + +public: + static const std::string INPUT_SHAPE; + static const std::string OUTPUT_SHAPE; + static const std::string OPERAND_SHAPE; + static const std::string BG_COLOR_SCHEME; + +public: + /** + * @brief Construct a new Operand Node object + * + * @param[in] index Operand index + * @param[in] type Operand type + * @param[in] lower_info Operand LowerInfo + */ + Operand(const ir::OperandIndex &index, Type type); + +private: + void addBackendLabel(); +}; + +} // namespace dot +} // namespace dumper +} // namespace onert + +#endif // __ONERT_DUMPER_DOT_DOT_OPERAND_INFO_H__ diff --git a/runtime/onert/core/src/dumper/dot/OperationNode.cc b/runtime/onert/core/src/dumper/dot/OperationNode.cc new file mode 100644 index 000000000..bee137e7c --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/OperationNode.cc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationNode.h" +#include "ir/Graph.h" +#include "ir/operation/LowerInfo.h" +#include "backend/IConfig.h" +#include "backend/Backend.h" + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +const std::string Operation::OPERATION_SHAPE = "rect"; +const std::string Operation::BG_COLOR_SCHEME = "pastel18"; + +Operation::Operation(const ir::OperationIndex &index, const ir::Operation &node) + : Node{"operation" + std::to_string(index.value())} +{ + setAttribute("label", std::to_string(index.value()) + " : " + node.name()); + setAttribute("shape", OPERATION_SHAPE); + setAttribute("colorscheme", BG_COLOR_SCHEME); + setAttribute("fillcolor", DEFAULT_FILLCOLOR); +} + +} // namespace dot +} // namespace dumper +} // namespace onert diff --git a/runtime/onert/core/src/dumper/dot/OperationNode.h b/runtime/onert/core/src/dumper/dot/OperationNode.h new file mode 100644 index 000000000..74a37d3fb --- /dev/null +++ b/runtime/onert/core/src/dumper/dot/OperationNode.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Operation.h + * @brief This file contains Operation + * @ingroup COM_AI_RUNTIME + * + */ + +#ifndef __ONERT_DUMPER_DOT_DOT_NODE_INFO_H__ +#define __ONERT_DUMPER_DOT_DOT_NODE_INFO_H__ + +#include "Node.h" +#include "ir/Operation.h" +#include "ir/Index.h" + +namespace onert +{ +namespace dumper +{ +namespace dot +{ + +/** + * @brief Class that represents an Operation + * + */ +class Operation : public Node +{ +public: + static const std::string OPERATION_SHAPE; + static const std::string BG_COLOR_SCHEME; + +public: + /** + * @brief Construct a new Operation Node object + * + * @param[in] index operation index + * @param[in] node operation object + */ + Operation(const ir::OperationIndex &index, const ir::Operation &node); +}; + +} // namespace dot +} // namespace dumper +} // namespace onert + +#endif // __ONERT_DUMPER_DOT_DOT_NODE_INFO_H__ diff --git a/runtime/onert/core/src/exec/DataflowExecutor.cc b/runtime/onert/core/src/exec/DataflowExecutor.cc new file mode 100644 index 000000000..fbd76d3c5 --- /dev/null +++ b/runtime/onert/core/src/exec/DataflowExecutor.cc @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DataflowExecutor.h" + +#include + +#include "util/logging.h" + +namespace onert +{ +namespace exec +{ + +int64_t DataflowExecutor::calculateRank(const std::vector &operations) +{ + int64_t rank = 0; + if (!_indexed_ranks) + { + return rank; + } + for (const auto &element : operations) + { + auto it = _indexed_ranks->find(element.index); + if (it == _indexed_ranks->end()) + { + assert(element.node->opcode() == ir::OpCode::Permute && operations.size() == 1); + // run Permute ASAP for next operations to be ready for other backends + return std::numeric_limits::max(); + } + else + { + rank += it->second; + } + } + return rank; +} + +void DataflowExecutor::emplaceToReadyJobs(const uint32_t &id) +{ + auto &job = _waiting_jobs[id]; + assert(job != nullptr); + auto &op_seq = _lowered_graph->op_seqs().at(_job_to_op_seq[job->index()]); + auto rank = calculateRank(op_seq.operations()); + _ready_jobs.emplace(rank, std::move(job)); +} + +void DataflowExecutor::notify(uint32_t finished_job_id) +{ + for (auto id : _output_info[finished_job_id]) + { + assert(_input_info[id] > 0); + auto count = --_input_info[id]; + if (count == 0) // No dependent jobs left, ready for execution + { + emplaceToReadyJobs(id); + } + } +} +bool DataflowExecutor::noWaitingJobs() +{ + return std::all_of(_waiting_jobs.begin(), _waiting_jobs.end(), + [](const std::unique_ptr &job) { return job == nullptr; }); +} + +DataflowExecutor::DataflowExecutor(std::unique_ptr lowered_graph, + const backend::TensorBuilderSet &tensor_builders, + compiler::CodeMap &&code_map) + : ExecutorBase{std::move(lowered_graph), tensor_builders}, _code_map{std::move(code_map)}, + _profiling{false} +{ + VERBOSE(DataflowExecutor) << "Constructing Dataflow Executor" << std::endl; + + const auto &op_seqs = _lowered_graph->op_seqs(); + // Assign jobs convert OpSequenceIndex to job index(uint32_t) + uint32_t next_job_index = 0; + std::unordered_map op_seq_to_job; + op_seqs.iterate([&](const ir::OpSequenceIndex &op_seq_index, const ir::OpSequence &) { + VERBOSE(DataflowExecutor) << "Create a job #" << next_job_index << " with OpSequenceIndex " + << op_seq_index.value() << std::endl; + _finished_jobs.emplace_back( + std::make_unique(next_job_index, _code_map.at(op_seq_index).fn_seq.get())); + op_seq_to_job[op_seq_index] = next_job_index++; + }); + + _waiting_jobs.resize(next_job_index); + _output_info.resize(next_job_index); + _initial_input_info.resize(next_job_index, 0); + + op_seqs.iterate([&](const ir::OpSequenceIndex &op_seq_index, const ir::OpSequence &op_seq) { + auto job_index = op_seq_to_job[op_seq_index]; + for (auto output : op_seq.getOutputs()) + { + // Update output and input info + op_seqs.iterate( + [&](const ir::OpSequenceIndex &op_seq_cur_index, const ir::OpSequence &op_seq_cur) { + if (op_seq_cur.getInputs().contains(output)) + { + auto dep_index = op_seq_to_job[op_seq_cur_index]; + ++_initial_input_info[dep_index]; + _output_info[job_index].push_back(dep_index); + } + }); + } + }); + for (const auto &s : op_seq_to_job) + _job_to_op_seq.emplace(s.second, s.first); + + _input_info = _initial_input_info; +} + +void DataflowExecutor::executeImpl() +{ + assert(noWaitingJobs()); + + // Execution setup + _waiting_jobs.swap(_finished_jobs); // Move finished jobs to waiting jobs + + for (uint32_t i = 0; i < _waiting_jobs.size(); ++i) + { + if (_input_info[i] == 0) + { + emplaceToReadyJobs(i); + } + } + assert(!_ready_jobs.empty()); // Cannot begin if there is no initial jobs + + _subject.notifyModelBegin(this); + + while (!_ready_jobs.empty()) + { + auto job = std::move((_ready_jobs.begin())->second); + _ready_jobs.erase(_ready_jobs.begin()); + auto job_index = job->index(); + VERBOSE(DataflowExecutor) << "Run job #" << job_index << std::endl; + + auto op_seq_index = _job_to_op_seq[job_index]; + auto op_seq = &_lowered_graph->op_seqs().at(op_seq_index); + const backend::Backend *backend = + _lowered_graph->getLowerInfo()->operation.at(op_seq_index)->backend(); + + _subject.notifyJobBegin(this, op_seq, backend); + + if (_profiling) + job->fn()->runSync(); + else + job->run(); + + _subject.notifyJobEnd(this, op_seq, backend); + notify(job_index); + _finished_jobs[job_index] = std::move(job); + } + assert(noWaitingJobs()); + + _subject.notifyModelEnd(this); + + // Reset input info for the next execution + _input_info = _initial_input_info; +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/DataflowExecutor.h b/runtime/onert/core/src/exec/DataflowExecutor.h new file mode 100644 index 000000000..b49df4386 --- /dev/null +++ b/runtime/onert/core/src/exec/DataflowExecutor.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_DATAFLOW_EXECUTOR_H__ +#define __ONERT_EXEC_DATAFLOW_EXECUTOR_H__ + +#include +#include +#include + +#include "exec/FunctionSequence.h" +#include "Job.h" +#include "ir/OperandIndexSequence.h" +#include "ir/Index.h" +#include +#include "exec/ExecutorBase.h" +#include "compiler/CodeMap.h" + +namespace onert +{ +namespace exec +{ + +class DataflowExecutor : public ExecutorBase +{ + +protected: + virtual void notify(uint32_t finished_job_id); + bool noWaitingJobs(); + +public: + /** + * @brief Constructs a DataflowExecutor object + * + * @param lowered_graph LoweredGraph object + * @param tensor_builders Tensor builders that are currently used + * @param code_map OpSequence and its code map + */ + DataflowExecutor(std::unique_ptr lowered_graph, + const backend::TensorBuilderSet &tensor_builders, compiler::CodeMap &&code_map); + + void executeImpl() override; + void setProfilingMode(bool profiling) { _profiling = profiling; } + +protected: + int64_t calculateRank(const std::vector &operations); + void emplaceToReadyJobs(const uint32_t &id); + +protected: + compiler::CodeMap _code_map; + /** + * @brief A vector of finished jobs for current execution + * After a run it has all the jobs of this execution for the next run + */ + std::vector> _finished_jobs; + /** + * @brief A vector of waiting jobs for current execution + * All the jobs are moved from #_finished_jobs to it when start a run + */ + std::vector> _waiting_jobs; + /** + * @brief Jobs' output info + * Used for notifying after finishing a job + */ + std::vector> _output_info; + std::vector _initial_input_info; + std::vector _input_info; + /** + * @brief A collection of jobs that are ready for execution + * Jobs in it are ready to be scheduled. + * Ordered by priority from `_indexed_ranks` + */ + std::multimap, std::greater> _ready_jobs; + + /// @brief Which job runs which op and function. + std::unordered_map _job_to_op_seq; + bool _profiling; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_DATAFLOW_EXECUTOR_H__ diff --git a/runtime/onert/core/src/exec/ExecTime.cc b/runtime/onert/core/src/exec/ExecTime.cc new file mode 100644 index 000000000..6bf2744a9 --- /dev/null +++ b/runtime/onert/core/src/exec/ExecTime.cc @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "exec/ExecTime.h" + +#include +#include +#include +#include + +namespace onert +{ +namespace exec +{ + +int64_t ExecTime::getOperationExecTime(const backend::Backend *backend, + const std::string &operation, bool quant, + uint32_t op_size) const +{ + auto found_backend = _measurements.find(backend); + if (found_backend == _measurements.end()) + return NOT_FOUND; // no execution time for this backend + + auto found_operation_with_type = found_backend->second.find(operation); + if (found_operation_with_type == found_backend->second.end()) + // no execution time for this operation + return NOT_FOUND; + + auto found_operation = found_operation_with_type->second.find(quant); + if (found_operation == found_operation_with_type->second.end()) + // no execution time for this operation + return NOT_FOUND; + + auto found_size = found_operation->second.find(op_size); + if (found_size != found_operation->second.end()) + return found_size->second; // found execution time + + // Try to interpolate + if (found_operation->second.size() < 2) + // not possible to do linear interpolation + return found_operation->second.begin()->second; + + // if we reach here, then this means, that there is no record, that is equal to op_size + auto upper_bound = found_operation->second.upper_bound(op_size); // > op_size + auto lower_bound = upper_bound; + + if (upper_bound == found_operation->second.end()) // all values <= op_size + { + upper_bound--; + lower_bound = upper_bound; + lower_bound--; + } + else if (upper_bound == found_operation->second.begin()) // all values > op_size + { + upper_bound++; + } + else // op_size between + { + lower_bound--; + } + + // Linear interpolation + const auto x0 = static_cast(lower_bound->first); // size + const auto x1 = static_cast(upper_bound->first); // size + const int64_t y0 = lower_bound->second; // time + const int64_t y1 = upper_bound->second; // time + const auto x = static_cast(op_size); + + int64_t interpolated_value = y0 + (x - x0) * (y1 - y0) / (x1 - x0); + + // In some cases ops with smaller inputs is executed slower than the one + // with larger inputs, more likely because of a backend's load difference + if (interpolated_value < 0 && x > x1) + { + return y0; + } + // It must be non-positive ONLY if it's lesser than both of them + assert(interpolated_value > 0 || x < x0); + + // execution time must be non-negative + return std::max(interpolated_value, 1); +} + +void ExecTime::updateOperationExecTime(const backend::Backend *backend, + const std::string &operation, bool quant, uint32_t op_size, + int64_t time) +{ + // If the op is not implemented for some input, it should not be scheduled + const auto &recs = _measurements[backend][operation][quant]; + if (time == getMax() || + std::any_of(recs.begin(), recs.end(), + [](std::pair p) { return p.second == getMax(); })) + { + _measurements[backend][operation][quant].clear(); + _measurements[backend][operation][quant].emplace(op_size, getMax()); + } + else + { + auto it = _measurements[backend][operation][quant].emplace(op_size, time); + if (!it.second) + { + // affect of the last measurement is bigger than the previous ones: + // this prefers new metrics than older once, so will adapt backend changes + it.first->second = (it.first->second + time) / 2; + } + } +} + +void ExecTime::updatePermuteTime(const backend::Backend *from_backend, + const backend::Backend *to_backend, bool quant, uint32_t op_size, + int64_t time) +{ + updateOperationExecTime(from_backend, to_backend->config()->id(), quant, op_size, time); +} + +int64_t ExecTime::getPermuteTime(const backend::Backend *from_backend, + const backend::Backend *to_backend, bool quant, + uint32_t op_size) const +{ + return getOperationExecTime(from_backend, to_backend->config()->id(), quant, op_size); +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/Execution.cc b/runtime/onert/core/src/exec/Execution.cc new file mode 100644 index 000000000..9c66e51e4 --- /dev/null +++ b/runtime/onert/core/src/exec/Execution.cc @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "exec/Execution.h" + +#include "util/logging.h" + +namespace onert +{ +namespace exec +{ + +Execution::Execution(const std::shared_ptr &executor) : _executor{executor} +{ + _io_desc.inputs.resize(_executor->graph().getInputs().size()); + _io_desc.outputs.resize(_executor->graph().getOutputs().size()); +} + +// TODO Remove default parameter +void Execution::setInput(const ir::IOIndex &index, const void *buffer, size_t length, + ir::Layout layout) +{ + const auto input_index = graph().getInputs().at(index); + const auto info = graph().operands().at(input_index).info(); + + if (length < info.total_size()) + { + throw std::runtime_error{"Too small length"}; + } + + _io_desc.inputs.at(index.value()) = std::make_unique(info, buffer, length, layout); +} + +// TODO Remove default parameter +void Execution::setInput(const ir::IOIndex &index, const ir::TypeInfo &type, const ir::Shape &shape, + const void *buffer, size_t length, ir::Layout layout) +{ + const ir::OperandInfo info{shape, type}; + + if (length < info.total_size()) + { + throw std::runtime_error{"Too small length"}; + } + + _io_desc.inputs.at(index.value()) = std::make_unique(info, buffer, length, layout); +} + +// TODO Remove default parameter +void Execution::setOutput(const ir::IOIndex &index, void *buffer, size_t length, ir::Layout layout) +{ + const auto output_index = graph().getOutputs().at(index); + const auto info = graph().operands().at(output_index).info(); + + if (length < info.total_size()) + { + throw std::runtime_error{"Too small length"}; + } + + _io_desc.outputs.at(index.value()) = std::make_unique(info, buffer, length, layout); +} + +// TODO Remove default parameter +void Execution::setOutput(const ir::IOIndex &index, const ir::TypeInfo &type, + const ir::Shape &shape, void *buffer, size_t length, ir::Layout layout) +{ + const ir::OperandInfo info{shape, type}; + + if (length < info.total_size()) + { + throw std::runtime_error{"Too small length"}; + } + + _io_desc.outputs.at(index.value()) = std::make_unique(info, buffer, length, layout); +} + +void Execution::setInputLayout(const ir::IOIndex &index, ir::Layout layout) +{ + const auto &input_desc = _io_desc.inputs.at(index.value()); + _io_desc.inputs.at(index.value()) = + std::make_unique(input_desc->info, input_desc->buffer, input_desc->size, layout); +} + +void Execution::setOutputLayout(const ir::IOIndex &index, ir::Layout layout) +{ + const auto &output_desc = _io_desc.outputs.at(index.value()); + _io_desc.outputs.at(index.value()) = std::make_unique( + output_desc->info, output_desc->buffer, output_desc->size, layout); +} + +void Execution::execute() +{ + VERBOSE(Execution) << "Start execution" << std::endl; + + _executor->execute(_io_desc); + finished = true; + + VERBOSE(Execution) << "Execution finished" << std::endl; +} + +void Execution::startExecute() +{ + VERBOSE(Execution) << "Create asynchronous execution thread" << std::endl; + + _exec_thread = std::make_unique(&Execution::execute, this); +} + +void Execution::waitFinish() +{ + VERBOSE(Execution) << "Wait to finish execution" << std::endl; + + _exec_thread->join(); + finished = true; +} + +bool Execution::isFinished(void) const { return finished; } + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/ExecutionObservee.cc b/runtime/onert/core/src/exec/ExecutionObservee.cc new file mode 100644 index 000000000..ddb1fb6a0 --- /dev/null +++ b/runtime/onert/core/src/exec/ExecutionObservee.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ExecutionObservee.h" + +namespace onert +{ +namespace exec +{ + +void ExecutionObservee::add(std::unique_ptr observer) +{ + _observers.emplace_back(std::move(observer)); +} + +void ExecutionObservee::notifyModelBegin(IExecutor *executor) +{ + for (auto &o : _observers) + { + o->handleBegin(executor); + } +} + +void ExecutionObservee::notifyModelEnd(IExecutor *executor) +{ + for (auto &o : _observers) + { + o->handleEnd(executor); + } +} + +void ExecutionObservee::notifyJobBegin(IExecutor *executor, const ir::OpSequence *op_seq, + const backend::Backend *backend) +{ + for (auto &o : _observers) + { + o->handleBegin(executor, op_seq, backend); + } +} + +void ExecutionObservee::notifyJobEnd(IExecutor *executor, const ir::OpSequence *op_seq, + const backend::Backend *backend) +{ + for (auto &o : _observers) + { + o->handleEnd(executor, op_seq, backend); + } +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/ExecutionObservee.h b/runtime/onert/core/src/exec/ExecutionObservee.h new file mode 100644 index 000000000..49d409a3a --- /dev/null +++ b/runtime/onert/core/src/exec/ExecutionObservee.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_EXECUTION_OBSERVEE_H__ +#define __ONERT_EXEC_EXECUTION_OBSERVEE_H__ + +#include + +#include "exec/ExecutionObservers.h" + +namespace onert +{ +namespace exec +{ + +/** + * @brief Class that + * + */ +class ExecutionObservee +{ +public: + /** + * @brief Register an observer + * + * @param observer Observer to be added + */ + void add(std::unique_ptr observer); + void notifyModelBegin(IExecutor *executor); + void notifyModelEnd(IExecutor *executor); + void notifyJobBegin(IExecutor *executor, const ir::OpSequence *op_seq, + const backend::Backend *backend); + void notifyJobEnd(IExecutor *executor, const ir::OpSequence *op_seq, + const backend::Backend *backend); + +private: + std::list> _observers; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_EXECUTION_OBSERVEE__ diff --git a/runtime/onert/core/src/exec/ExecutionObservers.cc b/runtime/onert/core/src/exec/ExecutionObservers.cc new file mode 100644 index 000000000..e8fcafa2b --- /dev/null +++ b/runtime/onert/core/src/exec/ExecutionObservers.cc @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "exec/ExecutionObservers.h" + +#include + +#include "util/logging.h" +#include "ir/operation/Permute.h" +#include "exec/IExecutor.h" +#include "misc/polymorphic_downcast.h" +#include "ir/OpSequence.h" + +namespace onert +{ + +namespace exec +{ + +void ProfileObserver::handleBegin(onert::exec::IExecutor *, const ir::OpSequence *, + const onert::backend::Backend *backend) +{ + _timer = backend->config()->timer(); + if (_timer == nullptr) + throw std::runtime_error("To profile backend timer() method must be implemented"); + _timer->handleBegin(); +} + +void ProfileObserver::handleEnd(IExecutor *exec, const ir::OpSequence *op_seq, + const backend::Backend *backend) +{ + _timer->handleEnd(); + const auto timer_res = _timer->getTime(); + + // NOTE This assumes there is just one operation in a op_seq + auto node = op_seq->operations().at(0).node; + auto node_name = node->name(); + VERBOSE(ProfileInfo) << "Time for " << node_name << " : " << timer_res << std::endl; + + // fill ExecTime: + bool is_quantized = exec->graph().operands().at(node->getInputs().at(0)).typeInfo().type() == + ir::DataType::QUANT8_ASYMM; + + uint32_t size = 0; + for (const auto &ind : node->getInputs() + node->getOutputs()) + { + size += exec->graph().operands().at(ind).info().total_size(); + } + if (node_name == "Permute") + { + auto *permute_node = nnfw::misc::polymorphic_downcast(node); + assert(permute_node != nullptr); + _et->updatePermuteTime(permute_node->param().input_backend_ctx->backend(), + permute_node->param().output_backend_ctx->backend(), is_quantized, size, + timer_res); + } + else + { + _et->updateOperationExecTime(backend, node_name, is_quantized, size, timer_res); + } +}; + +ChromeTracingObserver::ChromeTracingObserver(const std::string &filepath) + : _ofs{filepath, std::ofstream::out}, _recorder{}, _collector{&_recorder} +{ +} + +ChromeTracingObserver::~ChromeTracingObserver() { _recorder.writeToFile(_ofs); } + +void ChromeTracingObserver::handleBegin(IExecutor *) +{ + _collector.onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "runtime", "Graph"}); +} + +void ChromeTracingObserver::handleBegin(IExecutor *, const ir::OpSequence *op_seq, + const backend::Backend *backend) +{ + std::string backend_id = backend->config()->id(); + _collector.onEvent( + EventCollector::Event{EventCollector::Edge::BEGIN, backend_id, opSequenceTag(op_seq)}); +} + +void ChromeTracingObserver::handleEnd(IExecutor *, const ir::OpSequence *op_seq, + const backend::Backend *backend) +{ + std::string backend_id = backend->config()->id(); + _collector.onEvent( + EventCollector::Event{EventCollector::Edge::END, backend_id, opSequenceTag(op_seq)}); +} + +void ChromeTracingObserver::handleEnd(IExecutor *) +{ + _collector.onEvent(EventCollector::Event{EventCollector::Edge::END, "runtime", "Graph"}); +} + +std::string ChromeTracingObserver::opSequenceTag(const ir::OpSequence *op_seq) +{ + if (op_seq->size() == 0) + return "Empty OpSequence"; + + auto first_op = op_seq->operations().at(0); + std::string tag = "$" + std::to_string(first_op.index.value()); + tag += " " + first_op.node->name(); + if (op_seq->size() > 1) + { + tag += " (+" + std::to_string(op_seq->size() - 1) + ")"; + } + return tag; +} + +} // namespace exec + +} // namespace onert diff --git a/runtime/onert/core/src/exec/ExecutorBase.cc b/runtime/onert/core/src/exec/ExecutorBase.cc new file mode 100644 index 000000000..dd7e84af8 --- /dev/null +++ b/runtime/onert/core/src/exec/ExecutorBase.cc @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ExecutorBase.h" +#include "util/logging.h" + +namespace onert +{ +namespace exec +{ + +ExecutorBase::ExecutorBase(std::unique_ptr &&lowered_graph, + const backend::TensorBuilderSet &tensor_builders) + : _lowered_graph{std::move(lowered_graph)}, _graph{_lowered_graph->graph()}, _mutex() +{ + auto build_itensor_list = [&](const onert::ir::OperandIndexSequence &ind_seq) { + std::vector> list; + for (auto ind : ind_seq) + { + std::shared_ptr tensor; + for (auto &tensor_builder : tensor_builders) + { + tensor = tensor_builder->tensorAt(ind); + if (tensor != nullptr) + break; + } + assert(tensor != nullptr); + list.push_back(tensor); + } + return list; + }; + + _input_tensors = build_itensor_list(_graph.getInputs()); + _output_tensors = build_itensor_list(_graph.getOutputs()); + + // Prepare each TensorManager on each backend + for (auto &tensor_builder : tensor_builders) + { + auto tensor_manager = tensor_builder->releaseTensorManager(); + assert(tensor_manager != nullptr); + _tensor_mgrs.insert(std::move(tensor_manager)); + } +} + +std::unique_ptr ExecutorBase::source(const ir::IOIndex &index, const ir::TypeInfo &type, + const void *buffer, size_t length, + ir::Layout io_layout) +{ + using ir::DataType; + switch (type.type()) + { + case DataType::FLOAT32: + return source(index, buffer, length, io_layout); + case DataType::INT32: + return source(index, buffer, length, io_layout); + case DataType::UINT32: + return source(index, buffer, length, io_layout); + case DataType::BOOL8: + case DataType::QUANT8_ASYMM: + case DataType::UINT8: + return source(index, buffer, length, io_layout); + case DataType::QUANT8_SYMM: + return source(index, buffer, length, io_layout); + default: + throw std::runtime_error("Not supported yet"); + } +} + +std::unique_ptr ExecutorBase::sink(const ir::IOIndex &index, const ir::TypeInfo &type, + void *buffer, size_t length, ir::Layout io_layout) +{ + using ir::DataType; + switch (type.type()) + { + case DataType::FLOAT32: + return sink(index, buffer, length, io_layout); + case DataType::INT32: + return sink(index, buffer, length, io_layout); + case DataType::UINT32: + return sink(index, buffer, length, io_layout); + case DataType::BOOL8: + case DataType::QUANT8_ASYMM: + case DataType::UINT8: + return sink(index, buffer, length, io_layout); + case DataType::QUANT8_SYMM: + return sink(index, buffer, length, io_layout); + default: + throw std::runtime_error("Not supported yet"); + } +} + +void ExecutorBase::execute(const IODescription &desc) +{ + // For thread-safe, use mutex + // TODO: if all used backends on this executor are thread-safe, + // do not need to use mutex (otherwise, use mutex) + std::lock_guard lock(_mutex); + + std::vector> sources{_graph.getInputs().size()}; + std::vector> sinks{_graph.getOutputs().size()}; + + // Set input(s) + for (uint32_t n = 0; n < _graph.getInputs().size(); ++n) + { + ir::IOIndex input_index{n}; + ir::OperandIndex index{_graph.getInputs().at(input_index)}; + + if (desc.inputs.at(n) == nullptr) + { + // Optional input + continue; + } + + const auto operand_li = _lowered_graph->getLowerInfo()->operand.at(index).get(); + if (operand_li->def_factors().empty()) + { + // This input is not used (i.e. constant, EX. reshape's axis) + continue; + } + + const auto &input = *desc.inputs.at(n); + sources.at(n) = + source(input_index, input.info.typeInfo(), input.buffer, input.size, input.layout); + + auto setter = [&](::onert::backend::ITensor &tensor) { sources.at(n)->push(tensor); }; + + _input_tensors[n]->access(setter); + } + + executeImpl(); + + // Get output(s) + for (uint32_t n = 0; n < _graph.getOutputs().size(); ++n) + { + ir::IOIndex output_index{n}; + // Optional output + if (desc.outputs.at(n) == nullptr) + { + continue; + } + const auto &output = *desc.outputs.at(n); + sinks.at(n) = + sink(output_index, output.info.typeInfo(), output.buffer, output.size, output.layout); + + auto getter = [&](::onert::backend::ITensor &tensor) { sinks.at(n)->pull(tensor); }; + + _output_tensors[n]->access(getter); + } +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/ExecutorBase.h b/runtime/onert/core/src/exec/ExecutorBase.h new file mode 100644 index 000000000..cb5dde8eb --- /dev/null +++ b/runtime/onert/core/src/exec/ExecutorBase.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_EXECUTOR_BASE_H__ +#define __ONERT_EXEC_EXECUTOR_BASE_H__ + +#include + +#include "Source.h" +#include "exec/ExecutionObservers.h" +#include "Sink.h" +#include "exec/IExecutor.h" +#include "ir/LoweredGraph.h" +#include "ir/LowerInfoMap.h" +#include "backend/IConfig.h" +#include "backend/Backend.h" +#include "compiler/OperandContext.h" +#include "exec/ExecTime.h" +#include "exec/IFunction.h" +#include "backend/ITensorManager.h" +#include "backend/ITensorBuilder.h" +#include "exec/ExecutionObservee.h" +#include + +namespace onert +{ +namespace exec +{ + +class ExecutorBase : public IExecutor +{ +public: + /** + * @brief Construct a new ExecutorBase object + * @param graph Graph object + * @param tensor_builders Tensor builders that are currently used + */ + ExecutorBase(std::unique_ptr &&lowered_graph, + const backend::TensorBuilderSet &tensor_builders); + + virtual ~ExecutorBase() = default; + + const ir::Graph &graph() final { return _graph; } + + void execute(const IODescription &desc) final; + + // Used only in Dataflow and Parallel Executors + void setIndexedRanks(std::shared_ptr> ranks) final + { + _indexed_ranks = std::move(ranks); + }; + + virtual void executeImpl(void) = 0; + + void addObserver(std::unique_ptr ref) { _subject.add(std::move(ref)); }; + +private: + std::unique_ptr source(const ir::IOIndex &index, const ir::TypeInfo &type, + const void *buffer, size_t length, ir::Layout io_layout); + std::unique_ptr sink(const ir::IOIndex &index, const ir::TypeInfo &type, void *buffer, + size_t length, ir::Layout io_layout); + + template + std::unique_ptr source(const ir::IOIndex &index, const void *buffer, size_t length, + ir::Layout io_layout) + { + const auto operand_index = _graph.getInputs().at(index); + const auto &operand = _graph.operands().at(operand_index); + + const auto tensor = _input_tensors[index.value()]; + const auto tensor_layout = tensor->layout(); + + if (((io_layout == ir::Layout::NHWC) && (tensor_layout == ir::Layout::NCHW)) || + ((io_layout == ir::Layout::NCHW) && (tensor_layout == ir::Layout::NHWC))) + { + return std::make_unique>(buffer, length, operand.shape(), io_layout); + } + // TODO Change this to return error + assert(io_layout != ir::Layout::UNKNOWN || + (tensor_layout != ir::Layout::NCHW && tensor_layout != ir::Layout::NCHW)); + + return std::make_unique>(buffer, length, operand.shape()); + } + + template + std::unique_ptr sink(const ir::IOIndex &index, void *buffer, size_t length, + ir::Layout io_layout) + { + const auto operand_index = _graph.getOutputs().at(index); + const auto &operand = _graph.operands().at(operand_index); + const auto tensor = _output_tensors[index.value()]; + const auto tensor_layout = tensor->layout(); + + if (((tensor_layout == ir::Layout::NCHW) && (io_layout == ir::Layout::NHWC)) || + ((tensor_layout == ir::Layout::NHWC) && (io_layout == ir::Layout::NCHW))) + { + return std::make_unique>(buffer, length, operand.shape(), io_layout); + } + // TODO Change this to return error + assert(io_layout != ir::Layout::UNKNOWN || + (tensor_layout != ir::Layout::NCHW && tensor_layout != ir::Layout::NCHW)); + + return std::make_unique>(buffer, length, operand.shape()); + } + +protected: + ExecutionObservee _subject; + std::shared_ptr> _indexed_ranks; + std::unique_ptr _lowered_graph; + const ir::Graph &_graph; + std::vector> _input_tensors; + std::vector> _output_tensors; + backend::TensorManagerSet _tensor_mgrs; + std::mutex _mutex; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_EXECUTOR_BASE_H__ diff --git a/runtime/onert/core/src/exec/FunctionSequence.cc b/runtime/onert/core/src/exec/FunctionSequence.cc new file mode 100644 index 000000000..bf205af80 --- /dev/null +++ b/runtime/onert/core/src/exec/FunctionSequence.cc @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "exec/FunctionSequence.h" + +namespace onert +{ +namespace exec +{ + +void FunctionSequence::run() +{ + for (const auto &function : _functions) + { + function->run(); + } +} + +void FunctionSequence::runSync() +{ + for (const auto &function : _functions) + { + function->runSync(); + } +} + +void FunctionSequence::prepare() +{ + for (const auto &function : _functions) + { + function->prepare(); + } +} + +void FunctionSequence::append(std::unique_ptr &&function) +{ + _functions.push_back(std::move(function)); +} + +void FunctionSequence::iterate(const std::function &fn) +{ + for (const auto &func : _functions) + { + fn(*func); + } +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/JSONExecTime.cc b/runtime/onert/core/src/exec/JSONExecTime.cc new file mode 100644 index 000000000..72a18def1 --- /dev/null +++ b/runtime/onert/core/src/exec/JSONExecTime.cc @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "exec/JSONExecTime.h" +#include "backend/IConfig.h" +#include + +namespace onert +{ +namespace exec +{ +/** + * @brief Helper function for reading string from stream + * + * @param str Output string + * @param stream File stream + */ +void readString(std::string &str, std::ifstream &stream) +{ + str.clear(); + char buf; + while (stream.good()) + { + stream.get(buf); + if (buf == '"') + break; + str.push_back(buf); + } +} + +/** + * @brief Helper function for reading bool from stream + * + * @param quant Output bool + * @param stream File stream + */ +void readBool(bool &quant, std::ifstream &stream) +{ + char buf; + stream.get(buf); + quant = (buf == '1'); + stream.get(buf); +} + +void printString(const std::string &str, std::ofstream &stream) { stream << "\"" << str << "\""; } + +void printBool(bool quant, std::ofstream &stream) { stream << "\"" << quant << "\""; } + +void JSON::readOperation(const std::string &backend, const std::string &operation, bool quant, + std::ifstream &stream) +{ + uint32_t size = 0; + int64_t time = 0; + + std::string int_buf; + char buf; + int number_of_closed_braces = 0; + int number_of_commas = 0; + + while (stream.good()) + { + stream.get(buf); + + switch (buf) + { + case ']': + { + number_of_closed_braces++; + break; + } + case '[': + { + number_of_closed_braces--; + break; + } + default: + { + if (std::isdigit(buf)) + { + int_buf.push_back(buf); + } + break; + } + } + + if (number_of_closed_braces == 1) + break; + + if ((buf == ']' && number_of_closed_braces == 0) || + (buf == ',' && number_of_closed_braces == -1)) + { + switch (number_of_commas % 2) + { + case 0: + { + size = static_cast(std::atoi(int_buf.c_str())); + break; + } + case 1: + { + time = static_cast(std::atol(int_buf.c_str())); + auto bf = _backends.find(backend); + if (bf != _backends.end()) + { + _measurements[bf->second][operation][quant][size] = time; + } // we ignore the records for unsupported backends + break; + } + } + number_of_commas++; + int_buf.clear(); + } + } +} +void JSON::printOperation(const std::map &operation_info, + std::ofstream &stream) const +{ + for (const auto &items : operation_info) + { + stream << "[" << items.first << ", " << items.second << "], "; + } + stream.seekp(-2, std::ofstream::end); +} + +void JSON::uploadOperationsExecTime() const +{ + std::ofstream stream(_measurement_file); + if (!stream.is_open()) + { + throw std::runtime_error("Failed to save backend config file"); + } + else + { + stream << "{"; + for (const auto &backend : _measurements) + { + printString(backend.first->config()->id(), stream); + stream << ": {"; + for (const auto &operation : backend.second) + { + printString(operation.first, stream); + stream << ": {"; + for (const auto &type : operation.second) + { + printBool(type.first, stream); + stream << ": ["; + printOperation(type.second, stream); + stream << "], "; + } + stream.seekp(-2, std::ofstream::end); + stream << "}, "; + } + stream.seekp(-2, std::ofstream::end); + stream << "}, "; + } + stream.seekp(-2, std::ofstream::end); + stream << "}"; + stream.close(); + } +} + +void JSON::loadOperationsExecTime() +{ + std::ifstream stream(_measurement_file); + if (stream.is_open()) + { + std::string backend; + std::string operation; + bool quant = false; + char buf; + int number_of_open_braces = 0; + + while (stream.good()) + { + stream.get(buf); + switch (buf) + { + case '{': + number_of_open_braces++; + break; + case '}': + number_of_open_braces--; + break; + case '"': + { + if (number_of_open_braces == 1) + { + // read backend string + readString(backend, stream); + } + if (number_of_open_braces == 2) + { + // read operation string + readString(operation, stream); + } + if (number_of_open_braces == 3) + { + // read operation string + readBool(quant, stream); + } + break; + } + case '[': + { + // reading and creating all info for operation + readOperation(backend, operation, quant, stream); + break; + } + default: + break; + } + } + stream.close(); + } +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/Job.cc b/runtime/onert/core/src/exec/Job.cc new file mode 100644 index 000000000..dc0d140f0 --- /dev/null +++ b/runtime/onert/core/src/exec/Job.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Job.h" + +#include + +#include "util/logging.h" + +namespace onert +{ +namespace exec +{ + +Job::Job(uint32_t index, IFunction *fn) : _index{index}, _fn{fn} {} + +void Job::run() { _fn->run(); } + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/Job.h b/runtime/onert/core/src/exec/Job.h new file mode 100644 index 000000000..ff08ec8ce --- /dev/null +++ b/runtime/onert/core/src/exec/Job.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_JOB_H__ +#define __ONERT_EXEC_JOB_H__ + +#include + +#include "exec/IFunction.h" +#include "ir/Index.h" +#include "ir/OperandIndexSequence.h" +#include "backend/Backend.h" + +namespace onert +{ +namespace exec +{ + +class Job +{ +public: + /** + * @brief Constructs a Job object + * + * @param index Operation index for this job + * @param fn compiled code to run this job + * @param inputs Input operand list + * @param outputs Output operand list + */ + Job(uint32_t index, IFunction *fn); + /** + * @brief Execute the compiled code + */ + void run(); + /** + * @brief Return job index + * + * @return Job index + */ + uint32_t index() const { return _index; } + /** + * @brief Return the function to be executed + * + * @return Pointer of the function + */ + IFunction *fn() { return _fn; } + +private: + uint32_t _index; + IFunction *_fn; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_JOB_H__ diff --git a/runtime/onert/core/src/exec/LinearExecutor.cc b/runtime/onert/core/src/exec/LinearExecutor.cc new file mode 100644 index 000000000..188282d4d --- /dev/null +++ b/runtime/onert/core/src/exec/LinearExecutor.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LinearExecutor.h" + +namespace onert +{ +namespace exec +{ + +void LinearExecutor::executeImpl() +{ + _subject.notifyModelBegin(this); + for (auto &&code : _code) + { + const auto op_seq = code.op_seq; + const auto backend = code.lower_info->backend(); + _subject.notifyJobBegin(this, op_seq, backend); + code.fn_seq->run(); + _subject.notifyJobEnd(this, op_seq, backend); + } + _subject.notifyModelEnd(this); +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/LinearExecutor.h b/runtime/onert/core/src/exec/LinearExecutor.h new file mode 100644 index 000000000..f49f51e3e --- /dev/null +++ b/runtime/onert/core/src/exec/LinearExecutor.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file LinearExecutor.h + * @brief This file contains LinearExecutor class to define and run execution phase + */ + +#ifndef __ONERT_EXEC_EXECUTOR_H_ +#define __ONERT_EXEC_EXECUTOR_H_ + +#include "ir/Index.h" +#include "ExecutorBase.h" +#include "compiler/Linear.h" +#include "exec/FunctionSequence.h" +#include "compiler/CodeMap.h" + +namespace onert +{ +namespace exec +{ + +/** + * @brief Class to handle execution phase. Simple run the sequence of operations that is sorted in + * topological order + */ +class LinearExecutor final : public ExecutorBase +{ +public: + /** + * @brief Construct a new LinearExecutor object + * @param lowered_graph LoweredGraph object + * @param tensor_builders Tensor builders that are currently used + * @param code_map OpSequence and its code map + */ + LinearExecutor(std::unique_ptr lowered_graph, + const backend::TensorBuilderSet &tensor_builders, compiler::CodeMap &&code_map, + const std::vector &order) + : ExecutorBase{std::move(lowered_graph), tensor_builders} + { + for (auto index : order) + { + _code.emplace_back(std::move(code_map.at(index))); + } + } + +public: + void executeImpl(void) override; + +private: + std::vector _code; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_EXECUTOR_H_ diff --git a/runtime/onert/core/src/exec/ParallelExecutor.cc b/runtime/onert/core/src/exec/ParallelExecutor.cc new file mode 100644 index 000000000..f7e5de67d --- /dev/null +++ b/runtime/onert/core/src/exec/ParallelExecutor.cc @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ParallelExecutor.h" + +#include + +#include "util/logging.h" +#include "exec/IFunction.h" + +namespace onert +{ +namespace exec +{ + +class HookFunction : public IFunction +{ +public: + HookFunction(IFunction *fn, const std::function &setup, + const std::function &teardown) + : _fn{fn}, _setup{setup}, _teardown{teardown} + { + } + +public: + void run() override + { + _setup(); + _fn->run(); + _teardown(); + } + void runSync() override { throw("runSync is needed just for profiling in Dataflow executor"); } + +private: + IFunction *_fn; + std::function _setup; + std::function _teardown; +}; + +void ParallelExecutor::notify(uint32_t finished_job_id) +{ + std::unique_lock lock{_mu_jobs}; + + DataflowExecutor::notify(finished_job_id); + + lock.unlock(); + _cv_jobs.notify_all(); +} + +ParallelExecutor::ParallelExecutor(std::unique_ptr lowered_graph, + const backend::TensorBuilderSet &tensor_builders, + compiler::CodeMap &&code_map) + : DataflowExecutor{std::move(lowered_graph), tensor_builders, std::move(code_map)} +{ + VERBOSE(ParallelExecutor) << "Constructing Parallel Executor" << std::endl; +} + +void ParallelExecutor::executeImpl() +{ + // Init scheduler + // TODO Consider to have distinct backend set in LowerInfoMap + ir::BackendSet backends; + for (auto &itr : _lowered_graph->getLowerInfo()->operation) + { + backends.add(itr.second->backend()); + } + _scheduler = std::make_unique(backends); + + assert(noWaitingJobs()); + + // Execution setup + _waiting_jobs.swap(_finished_jobs); // Move finished jobs to waiting jobs + + for (uint32_t i = 0; i < _waiting_jobs.size(); ++i) + { + VERBOSE(ParallelExecutor) << i << ": " << _input_info[i] << std::endl; + if (_input_info[i] == 0) + { + emplaceToReadyJobs(i); + } + } + assert(!_ready_jobs.empty()); // Cannot begin if there is no initial jobs + + VERBOSE(ParallelExecutor) << "INITIAL JOBS : " << _ready_jobs.size() << std::endl; + + _subject.notifyModelBegin(this); + while (true) + { + std::unique_lock lock{_mu_jobs}; + + if (_ready_jobs.empty()) + { + _cv_jobs.wait(lock, [this] { return !_ready_jobs.empty() || noWaitingJobs(); }); + // Check finish condition + if (_ready_jobs.empty() && noWaitingJobs()) + { + break; + } + } + + auto job = std::move(_ready_jobs.begin()->second); + _ready_jobs.erase(_ready_jobs.begin()); + + lock.unlock(); + + VERBOSE(ParallelExecutor) << "Assigning fn #" << job->index() << std::endl; + + auto job_index = job->index(); + auto op_sequence_index = _job_to_op_seq[job_index]; + auto op_seq = &_lowered_graph->op_seqs().at(op_sequence_index); + auto backend = _lowered_graph->getLowerInfo()->operation.at(op_sequence_index)->backend(); + auto setup = [&, op_seq, backend]() { _subject.notifyJobBegin(this, op_seq, backend); }; + auto teardown = [&, job_index, op_seq, backend]() { + _subject.notifyJobEnd(this, op_seq, backend); + notify(job_index); + }; + + _scheduler->assign(std::make_unique(job->fn(), setup, teardown), backend); + _finished_jobs[job_index] = std::move(job); + } + + assert(noWaitingJobs()); + + // Wait for all the jobs done + _scheduler->finish(); + _subject.notifyModelEnd(this); + + // Reset input info for the next execution + _input_info = _initial_input_info; +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/ParallelExecutor.h b/runtime/onert/core/src/exec/ParallelExecutor.h new file mode 100644 index 000000000..d9387db5c --- /dev/null +++ b/runtime/onert/core/src/exec/ParallelExecutor.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_PARALLEL_EXECUTOR_H__ +#define __ONERT_EXEC_PARALLEL_EXECUTOR_H__ + +#include +#include +#include + +#include "exec/FunctionSequence.h" +#include "Job.h" +#include "ir/OperandIndexSequence.h" +#include "ir/Index.h" +#include +#include "exec/DataflowExecutor.h" +#include "ParallelScheduler.h" + +namespace onert +{ +namespace exec +{ + +/** + * @brief Class to execute Graph in parallel + */ +class ParallelExecutor : public DataflowExecutor +{ +protected: + void notify(uint32_t finished_job_id) override; + +public: + /** + * @brief Constructs a ParallelExecutor object + * + * @param lowered_graph LoweredGraph object + * @param tensor_builders Tensor builders that are currently used + * @param code_map OpSequence and its code map + */ + ParallelExecutor(std::unique_ptr lowered_graph, + const backend::TensorBuilderSet &tensor_builders, compiler::CodeMap &&code_map); + + void executeImpl() override; + +private: + std::condition_variable _cv_jobs; + std::mutex _mu_jobs; + std::unique_ptr _scheduler; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_PARALLEL_EXECUTOR_H__ diff --git a/runtime/onert/core/src/exec/ParallelScheduler.cc b/runtime/onert/core/src/exec/ParallelScheduler.cc new file mode 100644 index 000000000..1b2cf80bc --- /dev/null +++ b/runtime/onert/core/src/exec/ParallelScheduler.cc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ParallelScheduler.h" + +#include + +#include +#include "util/logging.h" + +namespace onert +{ +namespace exec +{ + +ParallelScheduler::ParallelScheduler(const ir::BackendSet &backends) +{ + assert(!backends.empty()); + + for (auto backend : backends) + { + _thread_pools[backend] = std::make_unique(); + } +} + +void ParallelScheduler::assign(std::unique_ptr &&fn, const backend::Backend *backend) +{ + assert(!_thread_pools.empty()); + + _thread_pools.at(backend)->enqueue(std::move(fn)); +} + +void ParallelScheduler::finish() +{ + for (auto &itr : _thread_pools) + { + itr.second->finish(); + } +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/ParallelScheduler.h b/runtime/onert/core/src/exec/ParallelScheduler.h new file mode 100644 index 000000000..3a53b6c7f --- /dev/null +++ b/runtime/onert/core/src/exec/ParallelScheduler.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_PARALLEL_SCHEDULER_H__ +#define __ONERT_EXEC_PARALLEL_SCHEDULER_H__ + +#include +#include + +#include "exec/IFunction.h" +#include "ir/BackendSet.h" +#include "ThreadPool.h" + +namespace onert +{ +namespace exec +{ + +class ParallelScheduler +{ +public: + /** + * @brief Constructs ParallelScheduler object + * + * @param backends Backend set + */ + ParallelScheduler(const ir::BackendSet &backends); + /** + * @brief Assign a task to the given backend + * + * @param[in] fn Function to be assigned + * @param[in] fn Target backend + */ + void assign(std::unique_ptr &&fn, const backend::Backend *backend); + /** + * @brief Block until all jobs are finished + */ + void finish(); + +private: + std::unordered_map> _thread_pools; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_PARALLEL_SCHEDULER_H__ diff --git a/runtime/onert/core/src/exec/Sink.h b/runtime/onert/core/src/exec/Sink.h new file mode 100644 index 000000000..238b0eddd --- /dev/null +++ b/runtime/onert/core/src/exec/Sink.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_SINK_H__ +#define __ONERT_EXEC_SINK_H__ + +#include + +#include +#include "util/feature/nchw/Reader.h" +#include "util/feature/nchw/View.h" +#include "util/feature/nhwc/Reader.h" +#include "util/feature/nhwc/View.h" +#include "util/Utils.h" +#include + +namespace onert +{ +namespace exec +{ +struct ISink +{ + virtual ~ISink() = default; + + virtual void pull(::onert::backend::ITensor &tensor) const = 0; +}; + +// Create second lever inheritance: the first lever is used as a reference type in use-case places +template class ITemplSink : public ISink +{ +public: + ITemplSink(void *output_buffer, const size_t &output_size, const ir::Shape &shape, + const bool copy, ir::Layout io_layout) + : _output_buffer{reinterpret_cast(output_buffer)}, _output_size{output_size}, + _shape{shape}, _copy{copy}, _io_layout{io_layout} + { + } + +protected: + void pullUnif(onert::backend::ITensor &tensor) const + { + assert(((_io_layout == ir::Layout::NHWC && tensor.layout() == ir::Layout::NCHW) || + (_io_layout == ir::Layout::NCHW && tensor.layout() == ir::Layout::NHWC)) || + _copy); + auto input_buffer = tensor.buffer(); + auto rank = _shape.rank(); + + if (!tensor.has_padding() && rank < 4 + _copy) + { + memcpy(_output_buffer, input_buffer, _output_size); + return; + } + + switch (rank) + { + case 0: + case 1: + { + memcpy(_output_buffer, input_buffer, _output_size); + break; + } + case 2: + { + const int32_t copy_len = _shape.dim(1); + + for (auto i = 0; i < _shape.dim(0); ++i) + { + ir::Coordinates coords{i, 0}; + memcpy(_output_buffer + i * copy_len, input_buffer + tensor.calcOffset(coords), + copy_len * sizeof(T)); + } + break; + } + case 3: + { + const int32_t dim1 = _shape.dim(1); + const int32_t dim2 = _shape.dim(2); + + for (auto i = 0; i < _shape.dim(0); ++i) + { + for (auto j = 0; j < _shape.dim(1); ++j) + { + ir::Coordinates coords{i, j, 0}; + memcpy(_output_buffer + i * dim1 * dim2 + j * dim2, + input_buffer + tensor.calcOffset(coords), dim2 * sizeof(T)); + } + } + break; + } + case 4: + { + if (_copy) + { + const int32_t dim1 = _shape.dim(1); + const int32_t dim2 = _shape.dim(2); + const int32_t dim3 = _shape.dim(3); + + for (auto i = 0; i < _shape.dim(0); ++i) + { + for (auto j = 0; j < _shape.dim(1); ++j) + { + for (auto k = 0; k < _shape.dim(2); ++k) + { + ir::Coordinates coords{i, j, k, 0}; + memcpy(_output_buffer + i * dim1 * dim2 * dim3 + j * dim2 * dim3 + k * dim3, + input_buffer + tensor.calcOffset(coords), dim3 * sizeof(T)); + } + } + } + } + else + { + const auto shape = _shape.asFeature(_io_layout); + + if (_io_layout == ir::Layout::NHWC) + { + const util::feature::nchw::Reader from(&tensor); + util::feature::nhwc::View into(shape, _output_buffer, _output_size); + ::nnfw::misc::feature::iterate(shape) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, ch, row, col); + into.at(batch, row, col, ch) = value; + }; + } + else if (_io_layout == ir::Layout::NCHW) + { + const util::feature::nhwc::Reader from(&tensor); + util::feature::nchw::View into(shape, _output_buffer, _output_size); + ::nnfw::misc::feature::iterate(shape) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, row, col, ch); + into.at(batch, ch, row, col) = value; + }; + } + else + { + throw std::runtime_error("Wrong Layout"); + } + } + break; + } + default: + throw std::runtime_error("NYI: rank > 4"); + break; + } + } + +private: + T *_output_buffer; + const size_t _output_size; + const ir::Shape _shape; + const bool _copy; + const ir::Layout _io_layout; +}; + +template class PermutateSink final : public ITemplSink +{ +public: + PermutateSink(void *output_buffer, const size_t &output_size, const ir::Shape &shape, + ir::Layout io_layout) + : ITemplSink(output_buffer, output_size, shape, false, io_layout) + { + } + +public: + void pull(onert::backend::ITensor &tensor) const override { ITemplSink::pullUnif(tensor); } +}; + +// Only supports NHWC format front-end(NNAPI) now +template class CopySink final : public ITemplSink +{ +public: + CopySink(void *output_buffer, const size_t &output_size, const ir::Shape &shape, + ir::Layout io_layout = ir::Layout::UNKNOWN) + : ITemplSink(output_buffer, output_size, shape, true, io_layout) + { + } + +public: + void pull(onert::backend::ITensor &tensor) const override { ITemplSink::pullUnif(tensor); } +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_SINK_H__ diff --git a/runtime/onert/core/src/exec/Source.h b/runtime/onert/core/src/exec/Source.h new file mode 100644 index 000000000..5792d8f2e --- /dev/null +++ b/runtime/onert/core/src/exec/Source.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_SOURCE_H__ +#define __ONERT_EXEC_SOURCE_H__ + +#include + +#include +#include "util/feature/nchw/Reader.h" +#include "util/feature/nchw/View.h" +#include "util/feature/nhwc/Reader.h" +#include "util/feature/nhwc/View.h" +#include "util/Utils.h" +#include +#include +#include "ir/Shape.h" + +namespace onert +{ +namespace exec +{ + +struct ISource +{ + virtual ~ISource() = default; + + virtual void push(::onert::backend::ITensor &tensor) const = 0; +}; + +// Create second lever inheritance: the first lever is used as a reference type in use-case places +template class ITemplSource : public ISource +{ +public: + ITemplSource(const void *input_buffer, const size_t &input_size, const ir::Shape &shape, + const bool copy, ir::Layout io_layout) + : _input_buffer{reinterpret_cast(input_buffer)}, _input_size{input_size}, + _shape{shape}, _copy(copy), _io_layout{io_layout} + { + } + + virtual void push(::onert::backend::ITensor &tensor) const = 0; + +protected: + void pushUnif(onert::backend::ITensor &tensor) const + { + assert(((_io_layout == ir::Layout::NHWC && tensor.layout() == ir::Layout::NCHW) || + (_io_layout == ir::Layout::NCHW && tensor.layout() == ir::Layout::NHWC)) || + _copy); + auto output_buffer = tensor.buffer(); + auto rank = _shape.rank(); + + if (!tensor.has_padding() && rank < 4 + _copy) + { + memcpy(output_buffer, _input_buffer, _input_size); + return; + } + + switch (rank) + { + case 0: + case 1: + { + memcpy(output_buffer, _input_buffer, _input_size); + break; + } + case 2: + { + const int32_t copy_len = _shape.dim(1); + + for (auto i = 0; i < _shape.dim(0); ++i) + { + ir::Coordinates coords{i, 0}; + memcpy(output_buffer + tensor.calcOffset(coords), _input_buffer + i * copy_len, + copy_len * sizeof(T)); + } + break; + } + case 3: + { + const int32_t dim1 = _shape.dim(1); + const int32_t dim2 = _shape.dim(2); + + for (auto i = 0; i < _shape.dim(0); ++i) + { + for (auto j = 0; j < _shape.dim(1); ++j) + { + ir::Coordinates coords{i, j, 0}; + memcpy(output_buffer + tensor.calcOffset(coords), + _input_buffer + i * dim1 * dim2 + j * dim2, dim2 * sizeof(T)); + } + } + break; + } + case 4: + { + if (_copy) + { + const int32_t dim1 = _shape.dim(1); + const int32_t dim2 = _shape.dim(2); + const int32_t dim3 = _shape.dim(3); + for (auto i = 0; i < _shape.dim(0); ++i) + { + for (auto j = 0; j < _shape.dim(1); ++j) + { + for (auto k = 0; k < _shape.dim(2); ++k) + { + ir::Coordinates coords{i, j, k, 0}; + memcpy(output_buffer + tensor.calcOffset(coords), + _input_buffer + i * dim1 * dim2 * dim3 + j * dim2 * dim3 + k * dim3, + dim3 * sizeof(T)); + } + } + } + } + else + { + const auto shape = _shape.asFeature(_io_layout); + + if (_io_layout == ir::Layout::NCHW) + { + const util::feature::nchw::Reader from(shape, _input_buffer, _input_size); + util::feature::nhwc::View into(&tensor); + ::nnfw::misc::feature::iterate(shape) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, ch, row, col); + into.at(batch, row, col, ch) = value; + }; + } + else if (_io_layout == ir::Layout::NHWC) + { + const util::feature::nhwc::Reader from(shape, _input_buffer, _input_size); + util::feature::nchw::View into(&tensor); + ::nnfw::misc::feature::iterate(shape) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, row, col, ch); + into.at(batch, ch, row, col) = value; + }; + } + else + { + throw std::runtime_error("Wrong Layout"); + } + } + + break; + } + default: + throw std::runtime_error("NYI: rank > 4"); + break; + } + } + +private: + const T *_input_buffer; + const size_t _input_size; + const ir::Shape _shape; + const bool _copy; + const ir::Layout _io_layout; +}; + +template class PermutateSource final : public ITemplSource +{ +public: + PermutateSource(const void *input_buffer, const size_t &input_size, const ir::Shape &shape, + ir::Layout io_layout) + : ITemplSource(input_buffer, input_size, shape, false, io_layout) + { + } + +public: + void push(onert::backend::ITensor &tensor) const override + { + // do NHWC_TO_NCHW or NCHW_TO_NHWC permutation + ITemplSource::pushUnif(tensor); + } +}; + +template class CopySource final : public ITemplSource +{ +public: + CopySource(const void *input_buffer, const size_t &input_size, const ir::Shape &shape, + ir::Layout io_layout = ir::Layout::UNKNOWN) + : ITemplSource(input_buffer, input_size, shape, true, io_layout) + { + } + +public: + void push(onert::backend::ITensor &tensor) const override { ITemplSource::pushUnif(tensor); } +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_SOURCE_H__ diff --git a/runtime/onert/core/src/exec/ThreadPool.cc b/runtime/onert/core/src/exec/ThreadPool.cc new file mode 100644 index 000000000..c8e0e3265 --- /dev/null +++ b/runtime/onert/core/src/exec/ThreadPool.cc @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ThreadPool.h" + +#include + +namespace onert +{ +namespace exec +{ + +ThreadPool::ThreadPool(uint32_t num_threads) +{ + assert(num_threads >= 1); + + for (uint32_t i = 0; i < num_threads; i++) + { + _threads.emplace_back(std::ref(_worker)); + } +} + +ThreadPool::~ThreadPool() +{ + if (!_threads.empty()) + { + _worker.terminate(); + join(); + } +} + +void ThreadPool::enqueue(std::unique_ptr &&fn) { _worker.enqueue(std::move(fn)); } + +uint32_t ThreadPool::numJobsInQueue() { return _worker.numJobsInQueue(); } + +void ThreadPool::join() +{ + for (auto &thread : _threads) + { + thread.join(); + } + _threads.clear(); +} + +void ThreadPool::finish() +{ + _worker.finish(); + join(); +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/ThreadPool.h b/runtime/onert/core/src/exec/ThreadPool.h new file mode 100644 index 000000000..b638bd94c --- /dev/null +++ b/runtime/onert/core/src/exec/ThreadPool.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_THREAD_POOL_H__ +#define __ONERT_EXEC_THREAD_POOL_H__ + +#include +#include +#include + +#include "WorkQueue.h" + +namespace onert +{ +namespace exec +{ + +class ThreadPool +{ +public: + /** + * @brief Coustruct ThreadPool object + * + * @param num_threads Number of threads + */ + ThreadPool(uint32_t num_threads = 1); + /** + * @brief Destroy ThreadPool object + */ + ~ThreadPool(); + /** + * @brief Enqueue a function + * + * @param fn A function to be queued + */ + void enqueue(std::unique_ptr &&fn); + /** + * @brief Get number of jobs in worker's queue + * + * @return Number of jobs + */ + uint32_t numJobsInQueue(); + + /** + * @brief Block until all jobs are finished + */ + void finish(); + +private: + void join(); + +private: + WorkQueue _worker; + std::vector _threads; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_THREAD_POOL_H__ diff --git a/runtime/onert/core/src/exec/WorkQueue.cc b/runtime/onert/core/src/exec/WorkQueue.cc new file mode 100644 index 000000000..b37f6a387 --- /dev/null +++ b/runtime/onert/core/src/exec/WorkQueue.cc @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "WorkQueue.h" + +#include + +namespace onert +{ +namespace exec +{ + +WorkQueue::~WorkQueue() +{ + { + std::unique_lock lock(_mu); + _state = State::FORCE_FINISHING; + } + _cv.notify_all(); +} + +void WorkQueue::operator()() +{ + while (true) + { + std::unique_ptr fn = nullptr; + + { + std::unique_lock lock{_mu}; + _cv.wait(lock, [this] { + return (_state == State::FORCE_FINISHING) || (_state == State::FINISHING) || + (_state == State::ONLINE && !_functions.empty()); + }); + + if (_state == State::FORCE_FINISHING) + { + assert(_functions.empty() && "Terminating with unfinished jobs"); + return; + } + else if (_state == State::FINISHING && _functions.empty()) + { + return; + } + else + { + assert(((_state == State::FINISHING) || (_state == State::ONLINE)) && !_functions.empty()); + fn = std::move(_functions.front()); + _functions.pop(); + } + } + + assert(fn); + fn->run(); + } +} + +void WorkQueue::enqueue(std::unique_ptr &&fn) +{ + { + std::unique_lock lock{_mu}; + _functions.emplace(std::move(fn)); + } + _cv.notify_one(); +} + +void WorkQueue::terminate() +{ + { + std::unique_lock lock{_mu}; + _state = State::FORCE_FINISHING; + } + _cv.notify_all(); +} + +void WorkQueue::finish() +{ + { + std::unique_lock lock{_mu}; + _state = State::FINISHING; + } + _cv.notify_all(); +} + +uint32_t WorkQueue::numJobsInQueue() +{ + std::unique_lock lock{_mu}; + return _functions.size(); +} + +} // namespace exec +} // namespace onert diff --git a/runtime/onert/core/src/exec/WorkQueue.h b/runtime/onert/core/src/exec/WorkQueue.h new file mode 100644 index 000000000..2e56d85e8 --- /dev/null +++ b/runtime/onert/core/src/exec/WorkQueue.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_EXEC_WORK_QUEUE_H__ +#define __ONERT_EXEC_WORK_QUEUE_H__ + +#include +#include +#include +#include + +#include "exec/IFunction.h" + +namespace onert +{ +namespace exec +{ + +class WorkQueue +{ +public: + enum class State + { + ONLINE, + FINISHING, + FORCE_FINISHING + }; + +public: + /** + * @brief Create WorkQueue object + */ + WorkQueue() = default; + /** + * @brief Destroy WorkQueue object + */ + ~WorkQueue(); + /** + * @brief Thread entry function + */ + void operator()(); + /** + * @brief Push the given Task to the job queue + * + * @param fn Function to be executed(a job) + */ + void enqueue(std::unique_ptr &&fn); + /** + * @brief Flag as terminating so all the worker threads can terminate + */ + void terminate(); + /** + * @brief Flag as terminating so all the worker threads can terminate + */ + void finish(); + /** + * @brief Check if it has pending jobs. Even if this returns fals, WorkQueue threads may be still + * running + * + * @return true if the job queue not empty otherwise false + */ + uint32_t numJobsInQueue(); + +private: + State _state{State::ONLINE}; + std::queue> _functions; + std::mutex _mu; + std::condition_variable _cv; +}; + +} // namespace exec +} // namespace onert + +#endif // __ONERT_EXEC_WORK_QUEUE_H__ diff --git a/runtime/onert/core/src/interp/Buffer.h b/runtime/onert/core/src/interp/Buffer.h new file mode 100644 index 000000000..24938f74f --- /dev/null +++ b/runtime/onert/core/src/interp/Buffer.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Buffer.h + * @brief This file contains Buffer interface and InternalBuffer, ExternalBuffer class + */ +#ifndef __ONERT_INTERP_BUFFER_H__ +#define __ONERT_INTERP_BUFFER_H__ + +#include + +#include "ir/Data.h" + +namespace onert +{ +namespace interp +{ + +/** + * @brief Interface for writable data area + */ +class Buffer : public ir::Data +{ +public: + /** + * @brief Return writable pointer for data area + * @return Writable pointer + */ + virtual uint8_t *baseWritable(void) const = 0; +}; + +/** + * @brief Class for internally allocated data area + */ +class InternalBuffer final : public Buffer +{ +public: + InternalBuffer(size_t size) : _base{std::make_unique(size)}, _size{size} + { + // DO NOTHING + } + +public: + size_t size(void) const override { return _size; } + const uint8_t *base(void) const override { return _base.get(); } + uint8_t *baseWritable(void) const override { return _base.get(); } + +private: + std::unique_ptr _base; + size_t _size; +}; + +/** + * @brief Class for data area from outside + */ +class ExternalBuffer final : public Buffer +{ +public: + ExternalBuffer(uint8_t *base, size_t size) : _base{base}, _size{size} + { + // DO NOTHING + } + +public: + size_t size(void) const override { return _size; } + const uint8_t *base(void) const override { return _base; } + uint8_t *baseWritable(void) const override { return _base; } + +private: + uint8_t *_base; + size_t _size; +}; + +} // namespace interp +} // namespace onert + +#endif // __ONERT_INTERP_BUFFER_H__ diff --git a/runtime/onert/core/src/interp/ExecEnv.h b/runtime/onert/core/src/interp/ExecEnv.h new file mode 100644 index 000000000..20805f1b3 --- /dev/null +++ b/runtime/onert/core/src/interp/ExecEnv.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file ExecEnv.h + * @brief This file contains ExecEnv to access interpreter tensor and execution status + */ +#ifndef __ONERT_INTERP_EXEC_ENV_H_ +#define __ONERT_INTERP_EXEC_ENV_H_ + +#include + +#include "ir/Graph.h" +#include "Tensor.h" + +namespace onert +{ +namespace interp +{ + +/** + * @brief Class to gather interpreter execution environment + * Each interpreter instance own execution environment + */ +class ExecEnv +{ +public: + /** + * @brief Construct a new Exec Env object (deleted) + */ + ExecEnv(void) = delete; + /** + * @brief Construct a new ExecEnv object + * @param[in] graph Graph to execute by interpreter + */ + explicit ExecEnv(const ir::Graph &graph) : _graph(graph) + { + // DO NOTHING + } + +public: + /** + * @brief Return graph to execute + * @return Graph + */ + const ir::Graph &graph(void) const { return _graph; } + /** + * @brief Assign tensor to environment which have allocated or assigned buffer + * @param[in] index Tensor index + * @param[in] tensor Tensor + */ + void assignTensor(const ir::OperandIndex index, std::shared_ptr tensor) + { + assert(tensor->bufferRO() != nullptr); + _tensors.emplace(index, tensor); + } + + /** + * @brief Return tensor pointer in environment + * @param[in] index Tensor index + * @return Tensor pointer + */ + const ITensor *tensorAt(const ir::OperandIndex index) const { return _tensors.at(index).get(); } + + /** + * @brief Check environment contains tensor + * @param[in] index Tensor index + * @return @c true if environment contain tensor, otherwise @c false + */ + bool contains(const ir::OperandIndex index) const + { + return (_tensors.find(index) != _tensors.end()); + } + + /** + * @brief Allocate tensor using operand info + * @param[in] index Tensor index + * @param[in] info Operand info + * @note If already allocated, just return + * @TODO More smart allocation policy + */ + void allocateIfNeeded(const ir::OperandIndex index, const ir::OperandInfo &info) + { + // already allocated, or constant + if (contains(index)) + { + return; + } + + auto tensor = std::make_shared(info); + tensor->setBuffer(std::make_shared(tensor->total_size())); + assignTensor(index, tensor); + _buffers.insert(index); + } + + /** + * @brief Allocate read-only tensor and share data with other tensor + * @param[in] index Tensor index + * @param[in] info Operand info + * @param[in] index_to_share Tensor index that have data to share + */ + void allocateAndShareIfNeeded(const ir::OperandIndex index, const ir::OperandInfo &info, + const ir::OperandIndex index_to_share) + { + if (!contains(index_to_share)) + { + throw std::runtime_error{"Cannot find tensor to share data"}; + } + + // already allocated + if (contains(index)) + { + return; + } + else + { + auto tensor = std::make_shared(info); + tensor->setData(tensorAt(index_to_share)->shareData()); + assignTensor(index, tensor); + _buffers.insert(index); + } + } + + /** + * @brief Free buffer if allocated by allocateIfNeed + * @param[in] index Tensor index + * @note If allocated by outside, just return + */ + void freeIfAllocated(const ir::OperandIndex index) + { + if (_buffers.find(index) != _buffers.end()) + { + _tensors.at(index)->releaseData(); + } + } + +private: + const ir::Graph &_graph; + // Tensor map to use in interpreter + // It should map tensors that have allocated or assigned buffer pointer + std::unordered_map> _tensors; + // Tensors allocated by allocateIfNeed (buffer) + std::unordered_set _buffers; +}; + +} // namespace interp +} // namespace onert + +#endif // __ONERT_INTERP_EXEC_ENV_H_ diff --git a/runtime/onert/core/src/interp/InterpExecutor.cc b/runtime/onert/core/src/interp/InterpExecutor.cc new file mode 100644 index 000000000..7a848412f --- /dev/null +++ b/runtime/onert/core/src/interp/InterpExecutor.cc @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "interp/InterpExecutor.h" +#include "interp/ExecEnv.h" +#include "interp/Interpreter.h" + +#include "util/logging.h" + +#include + +namespace onert +{ +namespace interp +{ + +void InterpExecutor::execute(const exec::IODescription &desc) +{ + /************************************************************************ + * Prepare execution model (submodel) + It may execute divided model + but now consider model inference is done at interpreter + ***********************************************************************/ + ir::OperandIndexMap> tensor_map; + + for (uint32_t n = 0; n < _graph.getInputs().size(); n++) + { + ir::IOIndex index{n}; + const auto input_index = _graph.getInputs().at(index); + const auto &input = *desc.inputs.at(n); + + auto input_tensor = std::make_shared(input.info); + input_tensor->setData(std::make_shared( + reinterpret_cast(input.buffer), input.size)); + tensor_map[input_index] = input_tensor; + } + + for (uint32_t n = 0; n < _graph.getOutputs().size(); n++) + { + ir::IOIndex index{n}; + const auto output_index = _graph.getOutputs().at(index); + const auto &output = *desc.outputs.at(n); + + auto output_tensor = std::make_shared(output.info); + output_tensor->setBuffer( + std::make_shared(reinterpret_cast(output.buffer), output.size)); + tensor_map[output_index] = output_tensor; + } + + /************************************************************************ + * Prepare execution environment + Execution environment will be assigned to invoked interpreter instance + ***********************************************************************/ + + std::unique_ptr interp_env = std::make_unique(_graph); + + // Assign input/output tensor into interpreter execution environment + for (auto index : _graph.getInputs() + _graph.getOutputs()) + { + if (tensor_map.find(index) != tensor_map.end()) + { + VERBOSE(INTERPRETER) << "Assign input/output tensor. operand index:" << index.value() + << std::endl; + interp_env->assignTensor(index, tensor_map.at(index)); + } + } + + // Allocate constant tensor + _graph.operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) { + if (obj.isConstant()) + { + VERBOSE(INTERPRETER) << "Allocate and assign constant tensor. operand index:" << ind.value() + << std::endl; + + assert(obj.data()); + auto const_tensor = std::make_shared(obj.info()); + // Assume that interpreter's tensor layout is same with model (NHWC) + const_tensor->setData( + std::make_shared(obj.data()->base(), obj.info().total_size())); + interp_env->assignTensor(ind, const_tensor); + } + }); + + /***************************************************************************** + * Invoke interpreter + ****************************************************************************/ + + interp::Interpreter interp(std::move(interp_env)); + interp.run(); + + /***************************************************************************** + * Invoked interpreter run is finished + ****************************************************************************/ + + // If interpreter execute submodel + // 1. Get tensor output of submodel into tensor_map to save result + // 2. Generate new ExecEnv for next interpretation +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/InterpOps.lst b/runtime/onert/core/src/interp/InterpOps.lst new file mode 100644 index 000000000..7b0c33232 --- /dev/null +++ b/runtime/onert/core/src/interp/InterpOps.lst @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERP_OP +#error Define INTERP_OP before including this file +#endif + +// Supported operation name in interpreter +// +// Same list with Operations.lst +// Make comment out if operation is not supported in interpreter +INTERP_OP(Add) +INTERP_OP(Sub) +//INTERP_OP(BatchToSpaceND) +//INTERP_OP(Cast) +INTERP_OP(Conv2D) +INTERP_OP(DepthwiseConv2D) +INTERP_OP(AvgPool2D) +INTERP_OP(MaxPool2D) +INTERP_OP(Concat) +INTERP_OP(FullyConnected) +//INTERP_OP(ReduceSum) +INTERP_OP(Reshape) +INTERP_OP(Mul) +INTERP_OP(Softmax) +//INTERP_OP(Squeeze) +//INTERP_OP(Slice) +//INTERP_OP(StridedSlice) +INTERP_OP(Tanh) +INTERP_OP(Logistic) +//INTERP_OP(Div) +//INTERP_OP(Transpose) +//INTERP_OP(Exp) +//INTERP_OP(ReduceMax) +//INTERP_OP(Comparison) +//INTERP_OP(LogicalAnd) +//INTERP_OP(LogicalOr) +//INTERP_OP(LogicalNot) +//INTERP_OP(LSTM) +//INTERP_OP(RSQRT) +INTERP_OP(ReLU) +//INTERP_OP(ResizeBilinear) +INTERP_OP(ReLU1) +INTERP_OP(ReLU6) +//INTERP_OP(RNN) +//INTERP_OP(Floor) +//INTERP_OP(SpaceToBatchND) +//INTERP_OP(SpaceToDepth) +//INTERP_OP(L2Pool2D) +//INTERP_OP(EmbeddingLookup) +//INTERP_OP(L2Normalization) +//INTERP_OP(HashtableLookup) +INTERP_OP(InstanceNorm) +//INTERP_OP(PReLU) +INTERP_OP(TransposeConv) +//INTERP_OP(SQRT) +//INTERP_OP(SquaredDifference) +//INTERP_OP(TopKV2) +INTERP_OP(Gather) +//INTERP_OP(Neg) +//INTERP_OP(Abs) +//INTERP_OP(ArgMax) +//INTERP_OP(Dequantize) +//INTERP_OP(Mean) +//INTERP_OP(LocalResponseNormalization) +//INTERP_OP(DepthToSpace) +//INTERP_OP(Pack) +//INTERP_OP(ReduceMin) +//INTERP_OP(Split) +//INTERP_OP(Unpack) +INTERP_OP(Pad) +//INTERP_OP(Custom) +//INTERP_OP(Permute) +//INTERP_OP(Min) +//INTERP_OP(Max) +//INTERP_OP(OneHot) diff --git a/runtime/onert/core/src/interp/Interpreter.cc b/runtime/onert/core/src/interp/Interpreter.cc new file mode 100644 index 000000000..e0cb8ce41 --- /dev/null +++ b/runtime/onert/core/src/interp/Interpreter.cc @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Interpreter.h" + +#include +#include + +#include "Registration.h" + +#include "ir/OperandIndexMap.h" +#include "util/logging.h" +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace interp +{ + +// TODO more structured execution kernel implementation +// TODO use cker for execution +// TODO divide tensor prepare and execution +// TODO introduce memory manager (buffer allocate and free) +class OperationExecutor +{ +public: + OperationExecutor(ExecEnv *env) : _env{env} + { +#define INTERP_OP(InternalName) _kernels[ir::OpCode::InternalName] = get##InternalName(); +#include "InterpOps.lst" +#undef INTERP_OP + } + + void execute(const ir::OperationIndex &idx) + { + const ir::Operation &node = _env->graph().operations().at(idx); + const auto nodeName = node.name(); + VERBOSE(INTERPRETER) << "Prepare output operands and execute " << nodeName + << " operation (id: " << idx.value() << ")" << std::endl; + + const auto nodeOpCode = node.opcode(); + if (_kernels[nodeOpCode]->prepare != nullptr) + { + _kernels[nodeOpCode]->prepare(_env, node); + } + _kernels[nodeOpCode]->invoke(_env, node); + } + +private: + ExecEnv *_env; + std::unordered_map _kernels; +}; + +void Interpreter::run() +{ + VERBOSE(INTERPRETER) << "Interpreter is invoked " << std::endl; + + // operand_stack: save operands prepared to use + std::stack operand_stack; + + // Note: We should push input first, then constant. + // We use use-def for find operators ready to execution, + // but Use-Def cannot handle parameters (maybe constant, but not always) + // Note: If all model inputs are constant, it may not work (depend on tensors' order). + // But that scenario may not exist + for (auto ind : _env->graph().getInputs()) + { + VERBOSE(INTERPRETER) << "Input: Push to operand stack " << ind.value() << std::endl; + + operand_stack.push(ind); + } + + _env->graph().operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) { + if (obj.isConstant()) + { + VERBOSE(INTERPRETER) << "Constant: Push to operand stack " << ind.value() << std::endl; + + operand_stack.push(ind); + } + }); + + // Execution + std::unordered_set ready_check; + std::unordered_set executed; + OperationExecutor executor{_env.get()}; + while (!operand_stack.empty()) + { + const auto current_operand_index = operand_stack.top(); + operand_stack.pop(); + VERBOSE(INTERPRETER) << "Poped operand " << current_operand_index.value() + << " is checked ready to use" << std::endl; + + assert(ready_check.find(current_operand_index) == ready_check.end()); + ready_check.insert(current_operand_index); + + // Find prepared operations by scan use of current operand + std::stack operation_stack; + auto use_operators = std::list( + _env->graph().operands().at(current_operand_index).getUses().list()); + // Remove operation index duplication + // If one operation uses same operand tensor for multiple input, + // use-list have duplicated operation index + use_operators.unique(); + for (auto use_operator : use_operators) + { + // Assumption: all parameters are ready to use + bool operator_ready = true; + for (auto input_index : _env->graph().operations().at(use_operator).getInputs()) + { + if (ready_check.find(input_index) == ready_check.end()) + { + operator_ready = false; + break; + } + } + + if (operator_ready) + { + VERBOSE(INTERPRETER) << "Ready to execute operation " << use_operator.value() << std::endl; + operation_stack.push(use_operator); + } + } + + while (!operation_stack.empty()) + { + const auto current_operation_index = operation_stack.top(); + operation_stack.pop(); + VERBOSE(INTERPRETER) << "Poped operation: " << current_operation_index.value() << "(" + << _env->graph().operations().at(current_operation_index).name() << ")" + << std::endl; + + // execution + // 1. Prepare output tensor + // 2. Call operation kernel + executor.execute(current_operation_index); + executed.insert(current_operation_index); + + // 3. Push each output into operand stack + const auto def_operands = _env->graph().operations().at(current_operation_index).getOutputs(); + for (auto def_operand : def_operands) + { + VERBOSE(INTERPRETER) << "Buffer: Push to operand stack " << def_operand.value() + << std::endl; + operand_stack.push(def_operand); + } + + // 4. Free if lifetime of buffer operands used by input is finished + for (auto input_index : _env->graph().operations().at(current_operation_index).getInputs()) + { + const auto use_operators = _env->graph().operands().at(input_index).getUses(); + bool dead_buffer = true; + for (auto use_operator : use_operators.list()) + { + if (executed.find(use_operator) == executed.end()) + { + dead_buffer = false; + break; + } + } + + if (dead_buffer) + { + _env->freeIfAllocated(input_index); + } + } + } + } +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/Interpreter.h b/runtime/onert/core/src/interp/Interpreter.h new file mode 100644 index 000000000..d2165f538 --- /dev/null +++ b/runtime/onert/core/src/interp/Interpreter.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Interpreter.h + * @brief This file contains Interpreter class for interpretation + */ +#ifndef __ONERT_INTERP_INTERPRETER_H__ +#define __ONERT_INTERP_INTERPRETER_H__ + +#include "ExecEnv.h" + +namespace onert +{ +namespace interp +{ + +/** + * @brief Class for interpretation + */ +class Interpreter +{ + +public: + /** + * @brief Construct a new Interpreter object (deleted) + */ + Interpreter() = delete; + /** + * @brief Construct a new Interpreter object + * @param[in] env Execution environment variable for interpreter object + */ + Interpreter(std::unique_ptr env) : _env{std::move(env)} + { + // DO NOTHING + } + +public: + /** + * @brief Run interpreter until there is no operation to execute + */ + void run(); + +private: + std::unique_ptr _env; +}; + +} // namespace interp +} // namespace onert + +#endif // __ONERT_INTERP_INTERPRETER_H__ diff --git a/runtime/onert/core/src/interp/Registration.h b/runtime/onert/core/src/interp/Registration.h new file mode 100644 index 000000000..956b92a53 --- /dev/null +++ b/runtime/onert/core/src/interp/Registration.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_INTERP_REGISTRATION_H__ +#define __ONERT_INTERP_REGISTRATION_H__ + +#include "ExecEnv.h" + +#include "ir/Operation.h" + +namespace onert +{ +namespace interp +{ + +struct OpKernel +{ + std::function prepare; + std::function invoke; +}; + +// Defined in operations/ directory +#define INTERP_OP(InternalName) OpKernel *get##InternalName(); +#include "InterpOps.lst" +#undef INTERP_OP + +} // namespace interp +} // namespace onert + +#endif // __ONERT_INTERP_REGISTRATION_H__ diff --git a/runtime/onert/core/src/interp/Tensor.cc b/runtime/onert/core/src/interp/Tensor.cc new file mode 100644 index 000000000..07f8b75dc --- /dev/null +++ b/runtime/onert/core/src/interp/Tensor.cc @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Tensor.h" + +#define NO_USE(a) (void)(a) + +namespace onert +{ +namespace interp +{ + +void ITensor::access(const std::function &fn) { fn(*this); } + +size_t ROTensor::calcOffset(const ir::Coordinates &coords) const +{ + NO_USE(coords); + throw std::runtime_error("offset_element_in_bytes is not supported for cpu::Tensor now."); +} + +size_t Tensor::calcOffset(const ir::Coordinates &coords) const +{ + NO_USE(coords); + throw std::runtime_error("offset_element_in_bytes is not supported for cpu::Tensor now."); +} + +ir::Layout ROTensor::layout() const +{ + // TODO Changes to return frontend layout + return ir::Layout::NHWC; +} + +ir::Layout Tensor::layout() const +{ + // TODO Changes to return frontend layout + return ir::Layout::NHWC; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/Tensor.h b/runtime/onert/core/src/interp/Tensor.h new file mode 100644 index 000000000..d5cb81738 --- /dev/null +++ b/runtime/onert/core/src/interp/Tensor.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Tensor.h + * @brief This file contains ITensor interface, ROTensor class, and Tensor class + */ +#ifndef __ONERT_INTERP_TENSOR_H__ +#define __ONERT_INTERP_TENSOR_H__ + +#include "Buffer.h" + +#include "ir/OperandInfo.h" +#include "backend/ITensor.h" +#include "ir/Layout.h" + +namespace onert +{ +namespace interp +{ + +/** + * @brief Interface to handle Tensor in interpreter + */ +class ITensor : public backend::ITensor +{ +public: + virtual ~ITensor() = default; + +public: + virtual uint8_t *buffer() const = 0; + /** + * @brief Return shared pointer for buffer + * @return Buffer shared pointer + */ + virtual std::shared_ptr shareBuffer() const = 0; + /** + * @brief Return read-only buffer pointer + * @return Read-only buffer pointer + */ + virtual const uint8_t *bufferRO() const = 0; + /** + * @brief Return shared pointer for data + * @return Data shared pointer + */ + virtual std::shared_ptr shareData() const = 0; + /** + * @brief Set internal/external buffer + * @param[in] buffer Buffer pointer + */ + virtual void setBuffer(std::shared_ptr buffer) = 0; + /** + * @brief Set data reference (including constant, input) + * @param[in] data Data pointer + */ + virtual void setData(std::shared_ptr data) = 0; + virtual void releaseData() = 0; + + virtual size_t total_size() const = 0; + virtual size_t dimension(size_t index) const = 0; + virtual size_t num_dimensions() const = 0; + virtual size_t calcOffset(const ir::Coordinates &coords) const = 0; + + virtual bool has_padding() const = 0; + /** + * @brief Return data type of tensor + * @return Data type of tensor + */ + virtual ir::DataType data_type() const = 0; + /** + * @brief Return TensorInfo + * @return TensorInfo + */ + virtual const ir::OperandInfo &tensorInfo() const = 0; + /** + * @brief Return number of elements + * @return Number of elements + */ + virtual uint64_t num_elements() const = 0; + void access(const std::function &fn) final; +}; + +/** + * @brief Class to handle tensor in interpreter as read-only + */ +class ROTensor final : public ITensor +{ +public: + ROTensor() = delete; + ROTensor(const ir::OperandInfo &info) : _info(info) + { + // DO NOTHING + } + +public: + uint8_t *buffer() const override { throw std::runtime_error{"Read only tensor"}; } + std::shared_ptr shareBuffer() const override + { + throw std::runtime_error{"Read only tensor"}; + } + const uint8_t *bufferRO() const override { return _data->base(); } + std::shared_ptr shareData() const override { return _data; } + void setBuffer(std::shared_ptr buffer) override { _data = buffer; } + void setData(std::shared_ptr data) override { _data = data; } + void releaseData() override { _data = nullptr; } + + size_t total_size() const override { return _info.total_size(); } + size_t dimension(size_t index) const override { return _info.shape().dim(index); } + size_t num_dimensions() const override { return _info.shape().rank(); } + size_t calcOffset(const ir::Coordinates &coords) const override; + ir::Layout layout() const override; + bool has_padding() const override { return false; } + ir::DataType data_type() const override { return _info.typeInfo().type(); } + const ir::OperandInfo &tensorInfo() const override { return _info; } + uint64_t num_elements() const override { return _info.shape().num_elements(); }; + +private: + const ir::OperandInfo _info; + std::shared_ptr _data{nullptr}; +}; + +/** + * @brief Class to handle tensor in interpreter as writable + */ +class Tensor final : public ITensor +{ +public: + Tensor() = delete; + Tensor(const ir::OperandInfo &info) : _info(info) + { + // DO NOTHING + } + +public: + uint8_t *buffer() const override { return _buffer->baseWritable(); } + std::shared_ptr shareBuffer() const override { return _buffer; }; + const uint8_t *bufferRO() const override { return _buffer->base(); } + std::shared_ptr shareData() const override { return _buffer; } + void setBuffer(std::shared_ptr buffer) override { _buffer = buffer; } + void setData(std::shared_ptr) override + { + throw std::runtime_error{"Passed data may read-only"}; + } + void releaseData() override { _buffer = nullptr; } + + size_t total_size() const override { return _info.total_size(); } + size_t dimension(size_t index) const override { return _info.shape().dim(index); } + size_t num_dimensions() const override { return _info.shape().rank(); } + size_t calcOffset(const ir::Coordinates &coords) const override; + ir::Layout layout() const override; + bool has_padding() const override { return false; } + ir::DataType data_type() const override { return _info.typeInfo().type(); } + const ir::OperandInfo &tensorInfo() const override { return _info; } + uint64_t num_elements() const override { return _info.shape().num_elements(); }; + +private: + const ir::OperandInfo _info; + std::shared_ptr _buffer{nullptr}; +}; + +} // namespace interp +} // namespace onert + +#endif // __ONERT_INTERP_TENSOR_H__ diff --git a/runtime/onert/core/src/interp/operations/AvgPool2D.cc b/runtime/onert/core/src/interp/operations/AvgPool2D.cc new file mode 100644 index 000000000..ef653fb2a --- /dev/null +++ b/runtime/onert/core/src/interp/operations/AvgPool2D.cc @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/AvgPool2D.h" +#include "util/Utils.h" +#include "util/ShapeInference.h" +#include "misc/polymorphic_downcast.h" + +namespace onert +{ +namespace interp +{ +namespace avgpool2d +{ + +void prepareAvgPool2D(ExecEnv *env, const ir::Operation &node) +{ + const auto in_index = node.getInputs().at(0); + const auto out_index = node.getOutputs().at(0); + + const auto in_tensor = env->tensorAt(in_index); + UNUSED_RELEASE(in_tensor); + + assert(in_tensor->num_dimensions() == 4); + + const auto output_info = env->graph().operands().at(out_index).info(); + if (output_info.total_size() == 0) + { + // Handle unspecified output shape + const auto &avgpool_node = + nnfw::misc::polymorphic_downcast(node); + const auto infered_output_shapes = + shape_inference::inferAvgPoolShape(in_tensor->tensorInfo().shape(), avgpool_node.param()); + env->allocateIfNeeded(out_index, {infered_output_shapes[0], output_info.typeInfo()}); + } + else + { + env->allocateIfNeeded(out_index, output_info); + } + + auto out_tensor = env->tensorAt(out_index); + UNUSED_RELEASE(out_tensor); + + // Handle same ifm & ofm data type only + assert(in_tensor->data_type() == out_tensor->data_type()); + assert(out_tensor->num_dimensions() == 4); +} + +void invoke(const ITensor *in_tensor, const ITensor *out_tensor, + const ir::operation::AvgPool2D::Param ¶m) +{ + // TODO Support NCHW frontend + const auto ifm_shape = in_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + const auto ofm_shape = out_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + const auto padding = + ir::calculatePadding(param.padding, ifm_shape, ofm_shape, param.stride, param.kw, param.kh); + // Calculate + nnfw::cker::PoolParams cker_param; + calculateActivationRange(param.activation, &cker_param.float_activation_min, + &cker_param.float_activation_max); + cker_param.filter_width = param.kw; + cker_param.filter_height = param.kh; + cker_param.padding_values.width = padding.left; + cker_param.padding_values.height = padding.top; + cker_param.stride_width = param.stride.horizontal; + cker_param.stride_height = param.stride.vertical; + + const auto in_shape = convertShape(in_tensor->tensorInfo().shape()); + const auto out_shape = convertShape(out_tensor->tensorInfo().shape()); + const float *in_ptr = reinterpret_cast(in_tensor->bufferRO()); + float *out_ptr = reinterpret_cast(out_tensor->buffer()); + + nnfw::cker::AveragePool(cker_param, in_shape, in_ptr, out_shape, out_ptr); +} + +void invokeAvgPool2D(const ExecEnv *env, const ir::Operation &node) +{ + const auto &avgpool_node = + nnfw::misc::polymorphic_downcast(node); + + const auto in_index = node.getInputs().at(0); + const auto out_index = node.getOutputs().at(0); + + // Check lhs shape is same with rhs (with broadcast) + const auto in_tensor = env->tensorAt(in_index); + const auto out_tensor = env->tensorAt(out_index); + + const auto data_type = in_tensor->data_type(); + if (data_type == ir::DataType::FLOAT32) + { + invoke(in_tensor, out_tensor, avgpool_node.param()); + } + else + { + throw std::runtime_error{"NYI: Support float only"}; + } +} +} // namespace avgpool2d + +OpKernel *getAvgPool2D() +{ + static OpKernel kernel = {avgpool2d::prepareAvgPool2D, avgpool2d::invokeAvgPool2D}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/BinaryArithmeticOps.cc b/runtime/onert/core/src/interp/operations/BinaryArithmeticOps.cc new file mode 100644 index 000000000..8ffc3cd33 --- /dev/null +++ b/runtime/onert/core/src/interp/operations/BinaryArithmeticOps.cc @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/Add.h" +#include "ir/operation/Sub.h" +#include "ir/operation/Mul.h" +#include "misc/polymorphic_downcast.h" + +namespace onert +{ +namespace interp +{ +namespace +{ + +enum class OpType +{ + ADD, + SUB, + MUL +}; + +template void prepareAdd(ExecEnv *env, const ir::Operation &node) +{ + const auto &add_node = nnfw::misc::polymorphic_downcast(node); + + const auto lhs_index = node.getInputs().at(add_node.LHS); + const auto rhs_index = node.getInputs().at(add_node.RHS); + const auto out_index = node.getOutputs().at(0); + + const auto lhs_tensor = env->tensorAt(lhs_index); + const auto rhs_tensor = env->tensorAt(rhs_index); + + // Check shape and type lhs is same with rhs + // TODO Util function to compare TensorInfo + if (lhs_tensor->data_type() != rhs_tensor->data_type()) + { + throw std::runtime_error{"Interp(Add): Different input types"}; + } + + bool try_broadcast = (lhs_tensor->tensorInfo().shape() != rhs_tensor->tensorInfo().shape()); + if (try_broadcast) + { + bool success = true; + auto out_shape = calcBroadcastShape(lhs_tensor->tensorInfo().shape(), + rhs_tensor->tensorInfo().shape(), success); + if (!success) + { + throw std::runtime_error{"Interp(Add): Fail to brodcasting"}; + } + + auto output_info = ir::OperandInfo(out_shape, lhs_tensor->tensorInfo().typeInfo()); + // We can handle already allocated (ex. model output) + env->allocateIfNeeded(out_index, output_info); + } + else + { + // Output's shape and type is same with input + auto output_info = lhs_tensor->tensorInfo(); + // We can handle already allocated (ex. model output) + env->allocateIfNeeded(out_index, output_info); + } + + auto out_tensor = env->tensorAt(out_index); + // Check shape and type lhs is same with output + // TODO Util function to compare TensorInfo + if (lhs_tensor->data_type() != out_tensor->data_type()) + { + throw std::runtime_error{"Interp(Add): Invalid output type"}; + } +} + +inline void setActivationParams(float min, float max, nnfw::cker::BinaryArithmeticOpParam *params) +{ + params->float_activation_min = min; + params->float_activation_max = max; +} + +inline void setActivationParams(int32_t min, int32_t max, + nnfw::cker::BinaryArithmeticOpParam *params) +{ + params->quantized_activation_min = min; + params->quantized_activation_max = max; +} + +template +void invoke(const ITensor *lhs_tensor, const ITensor *rhs_tensor, const ITensor *out_tensor, + const param_type ¶m) +{ + const auto lhs_buffer = lhs_tensor->bufferRO(); + const auto rhs_buffer = rhs_tensor->bufferRO(); + auto out_buffer = out_tensor->buffer(); + + nnfw::cker::BinaryArithmeticOpParam cker_param; + raw_type activation_min, activation_max; + calculateActivationRange(param.activation, &activation_min, &activation_max); + setActivationParams(activation_min, activation_max, &cker_param); + const raw_type *lhs_ptr = reinterpret_cast(lhs_buffer); + const raw_type *rhs_ptr = reinterpret_cast(rhs_buffer); + raw_type *out_ptr = reinterpret_cast(out_buffer); + + cker_param.type = (op_type == OpType::ADD) + ? nnfw::cker::BinaryArithmeticOpType::ADD + : ((op_type == OpType::SUB) ? nnfw::cker::BinaryArithmeticOpType::SUB + : nnfw::cker::BinaryArithmeticOpType::MUL); + + if (lhs_tensor->tensorInfo().shape() != rhs_tensor->tensorInfo().shape()) + { + const auto lhs_shape = convertExtendShape(lhs_tensor->tensorInfo().shape()); + const auto rhs_shape = convertExtendShape(rhs_tensor->tensorInfo().shape()); + const auto out_shape = convertExtendShape(out_tensor->tensorInfo().shape()); + nnfw::cker::BroadcastBinaryArithmeticOpSlow(cker_param, lhs_shape, lhs_ptr, rhs_shape, rhs_ptr, + out_shape, out_ptr); + return; + } + + const auto lhs_shape = convertShape(lhs_tensor->tensorInfo().shape()); + const auto rhs_shape = convertShape(rhs_tensor->tensorInfo().shape()); + const auto out_shape = convertShape(out_tensor->tensorInfo().shape()); + nnfw::cker::BinaryArithmeticOp(cker_param, lhs_shape, lhs_ptr, rhs_shape, rhs_ptr, out_shape, + out_ptr); +} + +template +void invokeAdd(const ExecEnv *env, const ir::Operation &node) +{ + const auto &arithmetic_node = nnfw::misc::polymorphic_downcast(node); + + const auto lhs_index = node.getInputs().at(arithmetic_node.LHS); + const auto rhs_index = node.getInputs().at(arithmetic_node.RHS); + const auto out_index = node.getOutputs().at(0); + const auto lhs_tensor = env->tensorAt(lhs_index); + const auto rhs_tensor = env->tensorAt(rhs_index); + const auto out_tensor = env->tensorAt(out_index); + const auto data_type = lhs_tensor->data_type(); + + if (data_type == ir::DataType::INT32) + { + invoke(lhs_tensor, rhs_tensor, out_tensor, + arithmetic_node.param()); + } + else if (data_type == ir::DataType::FLOAT32) + { + invoke(lhs_tensor, rhs_tensor, out_tensor, arithmetic_node.param()); + } + else + { + throw std::runtime_error{"NYI: Unsupported data type"}; + } +} +} // namespace + +OpKernel *getAdd() +{ + static OpKernel kernel = {prepareAdd, + invokeAdd}; + return &kernel; +} + +OpKernel *getSub() +{ + static OpKernel kernel = {prepareAdd, + invokeAdd}; + return &kernel; +} + +OpKernel *getMul() +{ + static OpKernel kernel = {prepareAdd, + invokeAdd}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/Concat.cc b/runtime/onert/core/src/interp/operations/Concat.cc new file mode 100644 index 000000000..53715e790 --- /dev/null +++ b/runtime/onert/core/src/interp/operations/Concat.cc @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/Concat.h" +#include "misc/polymorphic_downcast.h" + +namespace onert +{ +namespace interp +{ +namespace concat +{ + +void prepareConcat(ExecEnv *env, const ir::Operation &node) +{ + const auto &concat_node = nnfw::misc::polymorphic_downcast(node); + + const auto first_index = node.getInputs().at(0); + const auto out_index = node.getOutputs().at(0); + + const auto first_tensor = env->tensorAt(first_index); + uint32_t out_axis_dimension = 0; + const int32_t axis_raw = concat_node.param().axis; + const uint32_t axis = (axis_raw < 0) ? (axis_raw + first_tensor->num_dimensions()) : axis_raw; + + // All inputs shape should be same except axis dimension + // All inputs type should be same + for (auto input : node.getInputs()) + { + assert(first_tensor->num_dimensions() == env->tensorAt(input)->num_dimensions()); + assert(first_tensor->data_type() == env->tensorAt(input)->data_type()); + for (uint32_t i = 0; i < first_tensor->num_dimensions(); i++) + { + if (i == axis) + { + out_axis_dimension += env->tensorAt(input)->dimension(i); + continue; + } + assert(first_tensor->dimension(i) == env->tensorAt(input)->dimension(i)); + } + } + + // Make output tensor info using first input tensor info, and accumulated axis dimension value + auto out_shape = first_tensor->tensorInfo().shape(); + out_shape.dim(axis) = out_axis_dimension; + env->allocateIfNeeded(out_index, + ir::OperandInfo{out_shape, first_tensor->tensorInfo().typeInfo()}); + + auto out_tensor = env->tensorAt(out_index); + UNUSED_RELEASE(out_tensor); + + // Output shape should be same with input except axis dimension + // Output type should be same with input + assert(first_tensor->data_type() == out_tensor->data_type()); + for (uint32_t i = 0; i < first_tensor->num_dimensions(); i++) + { + if (i == axis) + { + continue; + } + assert(first_tensor->dimension(i) == out_tensor->dimension(i)); + } +} + +void invoke(const std::vector in_tensors, const ITensor *out_tensor, uint32_t axis) +{ + const uint32_t count = in_tensors.size(); + + // Calculate + nnfw::cker::ConcatenationParams cker_param; + cker_param.axis = (int8_t)axis; + cker_param.inputs_count = count; + + const auto out_shape = convertShape(out_tensor->tensorInfo().shape()); + + std::vector in_shapes; + std::vector in_shape_ptrs; + in_shapes.reserve(count); + in_shape_ptrs.reserve(count); + std::vector in_ptrs; + for (uint32_t i = 0; i < count; i++) + { + in_shapes.push_back(convertShape(in_tensors[i]->tensorInfo().shape())); + in_shape_ptrs.push_back(&in_shapes[i]); + in_ptrs.push_back(reinterpret_cast(in_tensors[i]->bufferRO())); + } + + auto out_buffer = out_tensor->buffer(); + float *out_ptr = reinterpret_cast(out_buffer); + + nnfw::cker::Concatenation(cker_param, in_shape_ptrs.data(), in_ptrs.data(), out_shape, + out_ptr); +} + +void invokeConcat(const ExecEnv *env, const ir::Operation &node) +{ + const auto &concat_node = nnfw::misc::polymorphic_downcast(node); + const int32_t axis_raw = concat_node.param().axis; + + std::vector in_tensors; + for (const auto &e : concat_node.getInputs()) + { + in_tensors.emplace_back(env->tensorAt(e)); + } + + const auto out_index = node.getOutputs().at(0); + const auto out_tensor = env->tensorAt(out_index); + const uint32_t axis = (axis_raw < 0) ? (axis_raw + out_tensor->num_dimensions()) : axis_raw; + + const auto data_type = in_tensors[0]->data_type(); + if (data_type == ir::DataType::FLOAT32) + { + invoke(in_tensors, out_tensor, axis); + } + else + { + throw std::runtime_error{"NYI: Support float32 only"}; + } +} +} // namespace concat + +OpKernel *getConcat() +{ + static OpKernel kernel = {concat::prepareConcat, concat::invokeConcat}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/Conv2D.cc b/runtime/onert/core/src/interp/operations/Conv2D.cc new file mode 100644 index 000000000..3c0087a61 --- /dev/null +++ b/runtime/onert/core/src/interp/operations/Conv2D.cc @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/Conv2D.h" +#include "util/Utils.h" +#include "util/ShapeInference.h" +#include "misc/polymorphic_downcast.h" + +namespace onert +{ +namespace interp +{ +namespace conv2d +{ + +void prepareConv2D(ExecEnv *env, const ir::Operation &node) +{ + const auto in_index = node.getInputs().at(ir::operation::Conv2D::INPUT); + const auto kernel_index = node.getInputs().at(ir::operation::Conv2D::KERNEL); + const auto bias_index = node.getInputs().at(ir::operation::Conv2D::BIAS); + const auto out_index = node.getOutputs().at(0); + + const auto in_tensor = env->tensorAt(in_index); + const auto kernel_tensor = env->tensorAt(kernel_index); + const auto bias_tensor = env->tensorAt(bias_index); + + assert(in_tensor->num_dimensions() == 4); + assert(kernel_tensor->num_dimensions() == 4); + assert(bias_tensor->num_dimensions() == 1); + + UNUSED_RELEASE(in_tensor); + UNUSED_RELEASE(kernel_tensor); + UNUSED_RELEASE(bias_tensor); + + const auto output_info = env->graph().operands().at(out_index).info(); + if (output_info.total_size() == 0) + { + // Handle unspecified output shape + const auto &conv_node = nnfw::misc::polymorphic_downcast(node); + const auto infered_output_shapes = shape_inference::inferConv2DShape( + in_tensor->tensorInfo().shape(), kernel_tensor->tensorInfo().shape(), conv_node.param()); + env->allocateIfNeeded(out_index, {infered_output_shapes[0], output_info.typeInfo()}); + } + else + { + env->allocateIfNeeded(out_index, output_info); + } + + auto out_tensor = env->tensorAt(out_index); + UNUSED_RELEASE(out_tensor); + + // Handle same ifm & ofm data type only + assert(in_tensor->data_type() == out_tensor->data_type()); + assert(out_tensor->num_dimensions() == 4); +} + +void invoke(const ITensor *ifm_tensor, const ITensor *ker_tensor, const ITensor *bias_tensor, + const ITensor *ofm_tensor, const ir::operation::Conv2D::Param ¶m) +{ + // TODO Support NCHW frontned + const auto ifm_shape = ifm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + const auto ofm_shape = ofm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in]. + const auto &ker_shape = ker_tensor->tensorInfo().shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + const auto padding = ir::calculatePadding(param.padding, ifm_shape, ofm_shape, param.stride, + ker_width, ker_height); + + // Calculate + float activation_min, activation_max; + calculateActivationRange(param.activation, &activation_min, &activation_max); + + nnfw::cker::ConvParams cker_param; + cker_param.padding_type = convertPaddingType(param.padding.type); + cker_param.padding_values.width = padding.left; + cker_param.padding_values.height = padding.top; + cker_param.stride_width = param.stride.horizontal; + cker_param.stride_height = param.stride.vertical; + cker_param.dilation_width_factor = 1; + cker_param.dilation_height_factor = 1; + cker_param.float_activation_min = activation_min; + cker_param.float_activation_max = activation_max; + + const auto cker_ifm_shape = convertShape(ifm_tensor->tensorInfo().shape()); + const auto cker_ker_shape = convertShape(ker_tensor->tensorInfo().shape()); + const auto cker_bias_shape = convertShape(bias_tensor->tensorInfo().shape()); + const auto cker_ofm_shape = convertShape(ofm_tensor->tensorInfo().shape()); + const float *ifm_ptr = reinterpret_cast(ifm_tensor->bufferRO()); + const float *ker_ptr = reinterpret_cast(ker_tensor->bufferRO()); + const float *bias_ptr = reinterpret_cast(bias_tensor->bufferRO()); + float *ofm_ptr = reinterpret_cast(ofm_tensor->buffer()); + + nnfw::cker::Conv conv_kernel; + conv_kernel(cker_param, cker_ifm_shape, ifm_ptr, cker_ker_shape, ker_ptr, cker_bias_shape, + bias_ptr, cker_ofm_shape, ofm_ptr); +} + +void invokeConv2D(const ExecEnv *env, const ir::Operation &node) +{ + const auto &conv_node = nnfw::misc::polymorphic_downcast(node); + + const auto ifm_index = node.getInputs().at(ir::operation::Conv2D::INPUT); + const auto ker_index = node.getInputs().at(ir::operation::Conv2D::KERNEL); + const auto bias_index = node.getInputs().at(ir::operation::Conv2D::BIAS); + const auto ofm_index = node.getOutputs().at(0); + + const auto ifm_tensor = env->tensorAt(ifm_index); + const auto ker_tensor = env->tensorAt(ker_index); + const auto bias_tensor = env->tensorAt(bias_index); + const auto ofm_tensor = env->tensorAt(ofm_index); + + const auto data_type = ifm_tensor->data_type(); + if (data_type == ir::DataType::FLOAT32) + { + invoke(ifm_tensor, ker_tensor, bias_tensor, ofm_tensor, conv_node.param()); + } + else + { + throw std::runtime_error{"NYI: Support float32 only"}; + } +} +} // namespace conv2d + +OpKernel *getConv2D() +{ + static OpKernel kernel = {conv2d::prepareConv2D, conv2d::invokeConv2D}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/DepthwiseConv2D.cc b/runtime/onert/core/src/interp/operations/DepthwiseConv2D.cc new file mode 100644 index 000000000..2682fbd78 --- /dev/null +++ b/runtime/onert/core/src/interp/operations/DepthwiseConv2D.cc @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/DepthwiseConv2D.h" +#include "util/Utils.h" +#include "util/ShapeInference.h" + +namespace onert +{ +namespace interp +{ + +namespace +{ + +void prepareDepthwiseConv(ExecEnv *env, const ir::Operation &node) +{ + const auto in_index = node.getInputs().at(ir::operation::DepthwiseConv2D::INPUT); + const auto kernel_index = node.getInputs().at(ir::operation::DepthwiseConv2D::KERNEL); + const auto bias_index = node.getInputs().at(ir::operation::DepthwiseConv2D::BIAS); + const auto out_index = node.getOutputs().at(0); + + const auto in_tensor = env->tensorAt(in_index); + const auto kernel_tensor = env->tensorAt(kernel_index); + const auto bias_tensor = env->tensorAt(bias_index); + + assert(in_tensor->num_dimensions() == 4); + assert(kernel_tensor->num_dimensions() == 4); + assert(bias_tensor->num_dimensions() == 1); + + UNUSED_RELEASE(in_tensor); + UNUSED_RELEASE(kernel_tensor); + UNUSED_RELEASE(bias_tensor); + + // TODO handle unspecified output shape: + // calculate output shape using ifm shape, kernel shape, padding, stride + const auto output_info = env->graph().operands().at(out_index).info(); + if (output_info.total_size() == 0) + { + // Handle unspecified output shape + const auto &depth_conv_node = + nnfw::misc::polymorphic_downcast(node); + const auto infered_output_shapes = shape_inference::inferDepthwiseConv2DShape( + in_tensor->tensorInfo().shape(), kernel_tensor->tensorInfo().shape(), + depth_conv_node.param()); + env->allocateIfNeeded(out_index, {infered_output_shapes[0], output_info.typeInfo()}); + } + else + { + env->allocateIfNeeded(out_index, output_info); + } + + auto out_tensor = env->tensorAt(out_index); + UNUSED_RELEASE(out_tensor); + + // Handle same ifm & ofm data type only + assert(in_tensor->data_type() == out_tensor->data_type()); + assert(out_tensor->num_dimensions() == 4); +} + +void invoke(const ITensor *ifm_tensor, const ITensor *ker_tensor, const ITensor *bias_tensor, + const ITensor *ofm_tensor, const ir::operation::DepthwiseConv2D::Param ¶m) +{ + // TODO Support NCHW frontend + const auto ifm_shape = ifm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + const auto ofm_shape = ofm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + // Kernel format is [1, kernel_height, kernel_width, depth_out]. + const auto &ker_shape = ker_tensor->tensorInfo().shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + const auto padding = ir::calculatePadding(param.padding, ifm_shape, ofm_shape, param.stride, + ker_width, ker_height); + + // Calculate + float activation_min, activation_max; + calculateActivationRange(param.activation, &activation_min, &activation_max); + + nnfw::cker::DepthwiseConvParams cker_param; + cker_param.padding_values.width = padding.left; + cker_param.padding_values.height = padding.top; + cker_param.depth_multiplier = param.multiplier; + cker_param.stride_width = param.stride.horizontal; + cker_param.stride_height = param.stride.vertical; + cker_param.dilation_width_factor = 1; + cker_param.dilation_height_factor = 1; + cker_param.float_activation_min = activation_min; + cker_param.float_activation_max = activation_max; + + const auto cker_ifm_shape = convertShape(ifm_tensor->tensorInfo().shape()); + const auto cker_ker_shape = convertShape(ker_tensor->tensorInfo().shape()); + const auto cker_bias_shape = convertShape(bias_tensor->tensorInfo().shape()); + const auto cker_ofm_shape = convertShape(ofm_tensor->tensorInfo().shape()); + const float *ifm_ptr = reinterpret_cast(ifm_tensor->bufferRO()); + const float *ker_ptr = reinterpret_cast(ker_tensor->bufferRO()); + const float *bias_ptr = reinterpret_cast(bias_tensor->bufferRO()); + float *ofm_ptr = reinterpret_cast(ofm_tensor->buffer()); + + nnfw::cker::DepthwiseConv(cker_param, cker_ifm_shape, ifm_ptr, cker_ker_shape, ker_ptr, + cker_bias_shape, bias_ptr, cker_ofm_shape, ofm_ptr); +} + +void invokeDepthwiseConv(const ExecEnv *env, const ir::Operation &node) +{ + const auto &conv_node = static_cast(node); + + const auto ifm_index = node.getInputs().at(ir::operation::DepthwiseConv2D::INPUT); + const auto ker_index = node.getInputs().at(ir::operation::DepthwiseConv2D::KERNEL); + const auto bias_index = node.getInputs().at(ir::operation::DepthwiseConv2D::BIAS); + const auto ofm_index = node.getOutputs().at(0); + + const auto ifm_tensor = env->tensorAt(ifm_index); + const auto ker_tensor = env->tensorAt(ker_index); + const auto bias_tensor = env->tensorAt(bias_index); + const auto ofm_tensor = env->tensorAt(ofm_index); + + const auto data_type = ifm_tensor->data_type(); + if (data_type == ir::DataType::FLOAT32) + { + invoke(ifm_tensor, ker_tensor, bias_tensor, ofm_tensor, conv_node.param()); + } + else + { + throw std::runtime_error{"NYI: Support float32 only"}; + } +} + +} // namespace + +OpKernel *getDepthwiseConv2D() +{ + static OpKernel kernel = {prepareDepthwiseConv, invokeDepthwiseConv}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/FullyConnected.cc b/runtime/onert/core/src/interp/operations/FullyConnected.cc new file mode 100644 index 000000000..8dfac43db --- /dev/null +++ b/runtime/onert/core/src/interp/operations/FullyConnected.cc @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/FullyConnected.h" +#include "misc/polymorphic_downcast.h" + +namespace onert +{ +namespace interp +{ +namespace fc +{ + +void prepareFC(ExecEnv *env, const ir::Operation &node) +{ + const auto in_index = node.getInputs().at(ir::operation::FullyConnected::INPUT); + const auto kernel_index = node.getInputs().at(ir::operation::FullyConnected::WEIGHT); + const auto bias_index = node.getInputs().at(ir::operation::FullyConnected::BIAS); + const auto out_index = node.getOutputs().at(0); + + const auto in_tensor = env->tensorAt(in_index); + const auto kernel_tensor = env->tensorAt(kernel_index); + const auto bias_tensor = env->tensorAt(bias_index); + + UNUSED_RELEASE(in_tensor); + UNUSED_RELEASE(kernel_tensor); + UNUSED_RELEASE(bias_tensor); + + assert(in_tensor->num_dimensions() >= 2); + assert(kernel_tensor->num_dimensions() == 2); + assert(bias_tensor->num_dimensions() == 1); + + const auto input_size_with_batch = in_tensor->num_elements(); + const auto num_units = kernel_tensor->dimension(0); + const auto input_size = kernel_tensor->dimension(1); + const auto batch_size = input_size_with_batch / input_size; + assert(input_size_with_batch % input_size == 0); + assert(num_units == bias_tensor->dimension(0)); + + // Make output tensor info + ir::Shape output_shape(2); + output_shape.dim(0) = batch_size; + output_shape.dim(1) = num_units; + const ir::OperandInfo out_info{output_shape, in_tensor->tensorInfo().typeInfo()}; + env->allocateIfNeeded(out_index, out_info); + + auto out_tensor = env->tensorAt(out_index); + UNUSED_RELEASE(out_tensor); + + // Handle same ifm & ofm data type only + assert(in_tensor->data_type() == out_tensor->data_type()); + assert(out_tensor->num_dimensions() == 2); + assert(out_tensor->dimension(0) == batch_size); + assert(out_tensor->dimension(1) == num_units); +} + +void invoke(const ITensor *ifm_tensor, const ITensor *ker_tensor, const ITensor *bias_tensor, + const ITensor *ofm_tensor, const ir::operation::FullyConnected::Param ¶m) +{ + const auto ifm_buffer = ifm_tensor->bufferRO(); + const auto ker_buffer = ker_tensor->bufferRO(); + const auto bias_buffer = bias_tensor->bufferRO(); + auto ofm_buffer = ofm_tensor->buffer(); + + // Calculate + nnfw::cker::FullyConnectedParams cker_param; + cker_param.activation = convertActivationType(param.activation); + calculateActivationRange(param.activation, &cker_param.float_activation_min, + &cker_param.float_activation_max); + const auto cker_ifm_shape = convertShape(ifm_tensor->tensorInfo().shape()); + const auto cker_ker_shape = convertShape(ker_tensor->tensorInfo().shape()); + const auto cker_bias_shape = convertShape(bias_tensor->tensorInfo().shape()); + const auto cker_ofm_shape = convertShape(ofm_tensor->tensorInfo().shape()); + const float *ifm_ptr = reinterpret_cast(ifm_buffer); + const float *ker_ptr = reinterpret_cast(ker_buffer); + const float *bias_ptr = reinterpret_cast(bias_buffer); + float *ofm_ptr = reinterpret_cast(ofm_buffer); + + nnfw::cker::FullyConnected(cker_param, cker_ifm_shape, ifm_ptr, cker_ker_shape, ker_ptr, + cker_bias_shape, bias_ptr, cker_ofm_shape, ofm_ptr); +} + +void invokeFC(const ExecEnv *env, const ir::Operation &node) +{ + const auto &conv_node = + nnfw::misc::polymorphic_downcast(node); + + const auto ifm_index = node.getInputs().at(ir::operation::FullyConnected::INPUT); + const auto ker_index = node.getInputs().at(ir::operation::FullyConnected::WEIGHT); + const auto bias_index = node.getInputs().at(ir::operation::FullyConnected::BIAS); + const auto ofm_index = node.getOutputs().at(0); + + const auto ifm_tensor = env->tensorAt(ifm_index); + const auto ker_tensor = env->tensorAt(ker_index); + const auto bias_tensor = env->tensorAt(bias_index); + const auto ofm_tensor = env->tensorAt(ofm_index); + + const auto data_type = ifm_tensor->data_type(); + if (data_type == ir::DataType::FLOAT32) + { + invoke(ifm_tensor, ker_tensor, bias_tensor, ofm_tensor, conv_node.param()); + } + else + { + throw std::runtime_error{"NYI: Support float only"}; + } +} +} // namespace fc + +OpKernel *getFullyConnected() +{ + static OpKernel kernel = {fc::prepareFC, fc::invokeFC}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/Gather.cc b/runtime/onert/core/src/interp/operations/Gather.cc new file mode 100644 index 000000000..b63e74886 --- /dev/null +++ b/runtime/onert/core/src/interp/operations/Gather.cc @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/Gather.h" +#include "misc/polymorphic_downcast.h" + +namespace onert +{ +namespace interp +{ +namespace +{ + +void prepareGather(ExecEnv *env, const ir::Operation &node) +{ + const auto input_index = node.getInputs().at(ir::operation::Gather::INPUT); + const auto indices_index = node.getInputs().at(ir::operation::Gather::INDICES); + const auto output_index = node.getOutputs().at(0); + + const auto input_tensor = env->tensorAt(input_index); + const auto indices_tensor = env->tensorAt(indices_index); + + // TODO handle unspecified output shape: + // calculate output shape using ifm shape, kernel shape, padding, stride + const auto output_info = env->graph().operands().at(output_index).info(); + if (output_info.total_size() == 0) + { + throw std::runtime_error{"Interp(Gather): NYI for unspecified output shape"}; + } + else + { + env->allocateIfNeeded(output_index, output_info); + } + + if (indices_tensor->data_type() != ir::DataType::INT32) + { + throw std::runtime_error{"Interp(Gather): Invalid indices data type"}; + } + + auto output_tensor = env->tensorAt(output_index); + auto output_rank = input_tensor->num_dimensions() + indices_tensor->num_dimensions() - 1; + + if (output_rank != output_tensor->num_dimensions()) + { + throw std::runtime_error{"Interp(Gather): Invalid output rank"}; + } + if (output_tensor->data_type() != input_tensor->data_type()) + { + throw std::runtime_error{"Interp(Gather): Invalid output data type"}; + } + + if (input_tensor->data_type() == ir::DataType::QUANT8_ASYMM && + input_tensor->tensorInfo().typeInfo() != output_tensor->tensorInfo().typeInfo()) + { + throw std::runtime_error{ + "Interp(Gather): Cannot handle different I/O QUANT8_ASYMM scale/offset"}; + } +} + +template +void invoke(const ITensor *input_tensors, const ITensor *indices_tensors, + const ITensor *output_tensor, uint32_t axis) +{ + // Calculate + nnfw::cker::GatherParams cker_param; + cker_param.axis = (int8_t)axis; + + const auto cker_input_shapes = convertShape(input_tensors->tensorInfo().shape()); + const auto cker_indices_shape = convertShape(indices_tensors->tensorInfo().shape()); + const auto cker_output_shape = convertShape(output_tensor->tensorInfo().shape()); + const raw_type *input_ptr = reinterpret_cast(input_tensors->bufferRO()); + const int32_t *indices_ptr = reinterpret_cast(indices_tensors->bufferRO()); + raw_type *output_ptr = reinterpret_cast(output_tensor->buffer()); + + nnfw::cker::Gather(cker_param, cker_input_shapes, input_ptr, cker_indices_shape, + indices_ptr, cker_output_shape, output_ptr); +} + +void invokeGather(const ExecEnv *env, const ir::Operation &node) +{ + const auto &gather_node = nnfw::misc::polymorphic_downcast(node); + const int32_t axis_raw = gather_node.param().axis; + + const auto input_index = node.getInputs().at(ir::operation::Gather::INPUT); + const auto indices_index = node.getInputs().at(ir::operation::Gather::INDICES); + const auto output_index = node.getOutputs().at(0); + + const auto input_tensor = env->tensorAt(input_index); + const auto indices_tensor = env->tensorAt(indices_index); + const auto output_tensor = env->tensorAt(output_index); + const uint32_t axis = (axis_raw < 0) ? (axis_raw + input_tensor->num_dimensions()) : axis_raw; + + const auto data_type = input_tensor->data_type(); + + switch (data_type) + { + case ir::DataType::FLOAT32: + invoke(input_tensor, indices_tensor, output_tensor, axis); + break; + case ir::DataType::INT32: + invoke(input_tensor, indices_tensor, output_tensor, axis); + break; + case ir::DataType::QUANT8_ASYMM: + invoke(input_tensor, indices_tensor, output_tensor, axis); + break; + default: + throw std::runtime_error{"Interp(Gather): NYI - Not supported type"}; + } +} + +} // namespace + +OpKernel *getGather() +{ + static OpKernel kernel = {prepareGather, invokeGather}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/InstanceNorm.cc b/runtime/onert/core/src/interp/operations/InstanceNorm.cc new file mode 100644 index 000000000..2538bcc39 --- /dev/null +++ b/runtime/onert/core/src/interp/operations/InstanceNorm.cc @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/InstanceNorm.h" +#include "misc/polymorphic_downcast.h" + +namespace onert +{ +namespace interp +{ +namespace instancenorm +{ + +void prepareInstanceNorm(ExecEnv *env, const ir::Operation &node) +{ + const auto &instancenorm_node = + nnfw::misc::polymorphic_downcast(node); + + const auto input_index = node.getInputs().at(instancenorm_node.INPUT); + const auto output_index = node.getOutputs().at(0); + const auto input_tensor = env->tensorAt(input_index); + + if (input_tensor->num_dimensions() != 4) + { + throw std::runtime_error{"Interp(InstanceNorm): Input should be 4D-tensor"}; + } + + // Output shape should be same with input + env->allocateIfNeeded(output_index, input_tensor->tensorInfo()); + + auto output_tensor = env->tensorAt(output_index); + UNUSED_RELEASE(output_tensor); + + // Handle same ifm & ofm data type only + assert(input_tensor->data_type() == output_tensor->data_type()); + assert(input_tensor->tensorInfo().shape() == output_tensor->tensorInfo().shape()); +} + +inline void setActivationParams(float min, float max, nnfw::cker::InstanceNormParams *params) +{ + params->float_activation_min = min; + params->float_activation_max = max; +} + +void invoke(const ITensor *input_tensor, const ITensor *gamma_tensor, const ITensor *beta_tensor, + const ITensor *output_tensor, const ir::operation::InstanceNorm::Param ¶m) +{ + // Calculate + float activation_min, activation_max; + calculateActivationRange(param.activation, &activation_min, &activation_max); + + nnfw::cker::InstanceNormParams cker_param; + cker_param.epsilon = param.epsilon; + cker_param.float_activation_min = activation_min; + cker_param.float_activation_max = activation_max; + + const auto cker_input_shape = convertShape(input_tensor->tensorInfo().shape()); + const auto cker_gamma_shape = convertShape(gamma_tensor->tensorInfo().shape()); + const auto cker_beta_shape = convertShape(beta_tensor->tensorInfo().shape()); + const auto cker_output_shape = convertShape(output_tensor->tensorInfo().shape()); + const float *input_ptr = reinterpret_cast(input_tensor->bufferRO()); + const float *gamma_ptr = reinterpret_cast(gamma_tensor->bufferRO()); + const float *beta_ptr = reinterpret_cast(beta_tensor->bufferRO()); + float *output_ptr = reinterpret_cast(output_tensor->buffer()); + + nnfw::cker::InstanceNorm(cker_param, cker_input_shape, input_ptr, cker_gamma_shape, gamma_ptr, + cker_beta_shape, beta_ptr, cker_output_shape, output_ptr); +} + +void invokeInstanceNorm(const ExecEnv *env, const ir::Operation &node) +{ + const auto &instancenorm_node = + nnfw::misc::polymorphic_downcast(node); + + const auto input_index = node.getInputs().at(instancenorm_node.INPUT); + const auto gamma_index = node.getInputs().at(instancenorm_node.GAMMA); + const auto beta_index = node.getInputs().at(instancenorm_node.BETA); + const auto out_index = node.getOutputs().at(0); + const auto input_tensor = env->tensorAt(input_index); + const auto gamma_tensor = env->tensorAt(gamma_index); + const auto beta_tensor = env->tensorAt(beta_index); + const auto out_tensor = env->tensorAt(out_index); + const auto data_type = input_tensor->data_type(); + + if (data_type == ir::DataType::FLOAT32) + { + invoke(input_tensor, gamma_tensor, beta_tensor, out_tensor, instancenorm_node.param()); + } + else + { + throw std::runtime_error{"NYI: Unsupported data type"}; + } +} +} // namespace instancenorm + +OpKernel *getInstanceNorm() +{ + static OpKernel kernel = {instancenorm::prepareInstanceNorm, instancenorm::invokeInstanceNorm}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/Logistic.cc b/runtime/onert/core/src/interp/operations/Logistic.cc new file mode 100644 index 000000000..c23cbb782 --- /dev/null +++ b/runtime/onert/core/src/interp/operations/Logistic.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/Logistic.h" + +namespace onert +{ +namespace interp +{ +namespace +{ + +void prepareLogistic(ExecEnv *env, const ir::Operation &node) +{ + const auto input_index = node.getInputs().at(0); + const auto output_index = node.getOutputs().at(0); + + const auto input_tensor = env->tensorAt(input_index); + + const auto output_info = env->graph().operands().at(output_index).info(); + + // Check shape and type lhs is same with rhs + // TODO Util function to compare TensorInfo + if (output_info.total_size() == 0) + { + throw std::runtime_error{"Interp(TConv): NYI unspecified output shape"}; + } + else + { + env->allocateIfNeeded(output_index, output_info); + } + + const auto output_tensor = env->tensorAt(output_index); + if (input_tensor->data_type() != output_tensor->data_type()) + { + throw std::runtime_error{"Interp(Logistic): Invalid output type"}; + } +} + +void invoke(const ITensor *input_tensor, const ITensor *output_tensor) +{ + const auto input_buffer = input_tensor->bufferRO(); + auto output_buffer = output_tensor->buffer(); + + const auto cker_input_shape = convertShape(input_tensor->tensorInfo().shape()); + const auto cker_output_shape = convertShape(output_tensor->tensorInfo().shape()); + const float *input_ptr = reinterpret_cast(input_buffer); + float *output_ptr = reinterpret_cast(output_buffer); + + nnfw::cker::Logistic(cker_input_shape, input_ptr, cker_output_shape, output_ptr); +} + +void invokeLogistic(const ExecEnv *env, const ir::Operation &node) +{ + const auto input_index = node.getInputs().at(0); + const auto output_index = node.getOutputs().at(0); + + const auto input_tensor = env->tensorAt(input_index); + const auto output_tensor = env->tensorAt(output_index); + + const auto data_type = input_tensor->data_type(); + + if (data_type == ir::DataType::FLOAT32) + { + invoke(input_tensor, output_tensor); + } + else + { + throw std::runtime_error{"Interp(Logistic): NYI - Unsupported data type"}; + } +} +} // namespace + +OpKernel *getLogistic() +{ + static OpKernel kernel = {prepareLogistic, invokeLogistic}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/MaxPool2D.cc b/runtime/onert/core/src/interp/operations/MaxPool2D.cc new file mode 100644 index 000000000..d524f356e --- /dev/null +++ b/runtime/onert/core/src/interp/operations/MaxPool2D.cc @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/MaxPool2D.h" +#include "util/Utils.h" +#include "util/ShapeInference.h" +#include "misc/polymorphic_downcast.h" + +namespace onert +{ +namespace interp +{ +namespace +{ + +void prepareMaxPool2D(ExecEnv *env, const ir::Operation &node) +{ + const auto in_index = node.getInputs().at(0); + const auto out_index = node.getOutputs().at(0); + + const auto in_tensor = env->tensorAt(in_index); + + assert(in_tensor->num_dimensions() == 4); + UNUSED_RELEASE(in_tensor); + + const auto output_info = env->graph().operands().at(out_index).info(); + if (output_info.total_size() == 0) + { + // Handle unspecified output shape + const auto &maxpool_node = + nnfw::misc::polymorphic_downcast(node); + const auto infered_output_shapes = + shape_inference::inferMaxPoolShape(in_tensor->tensorInfo().shape(), maxpool_node.param()); + env->allocateIfNeeded(out_index, {infered_output_shapes[0], output_info.typeInfo()}); + } + else + { + env->allocateIfNeeded(out_index, output_info); + } + + auto out_tensor = env->tensorAt(out_index); + UNUSED_RELEASE(out_tensor); + + // Handle same ifm & ofm data type only + assert(in_tensor->data_type() == out_tensor->data_type()); + assert(out_tensor->num_dimensions() == 4); +} + +void invoke(const ITensor *in_tensor, const ITensor *out_tensor, + const ir::operation::MaxPool2D::Param ¶m) +{ + // TODO support NCHW frontend + const auto ifm_shape = in_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + const auto ofm_shape = out_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + const auto padding = + ir::calculatePadding(param.padding, ifm_shape, ofm_shape, param.stride, param.kw, param.kh); + // Calculate + nnfw::cker::PoolParams cker_param; + calculateActivationRange(param.activation, &cker_param.float_activation_min, + &cker_param.float_activation_max); + cker_param.filter_width = param.kw; + cker_param.filter_height = param.kh; + cker_param.padding_values.width = padding.left; + cker_param.padding_values.height = padding.top; + cker_param.stride_width = param.stride.horizontal; + cker_param.stride_height = param.stride.vertical; + + const auto in_shape = convertShape(in_tensor->tensorInfo().shape()); + const auto out_shape = convertShape(out_tensor->tensorInfo().shape()); + const float *in_ptr = reinterpret_cast(in_tensor->bufferRO()); + float *out_ptr = reinterpret_cast(out_tensor->buffer()); + + nnfw::cker::MaxPool(cker_param, in_shape, in_ptr, out_shape, out_ptr); +} + +void invokeMaxPool2D(const ExecEnv *env, const ir::Operation &node) +{ + const auto &maxpool_node = + nnfw::misc::polymorphic_downcast(node); + + const auto in_index = node.getInputs().at(0); + const auto out_index = node.getOutputs().at(0); + + const auto in_tensor = env->tensorAt(in_index); + const auto out_tensor = env->tensorAt(out_index); + + const auto data_type = in_tensor->data_type(); + if (data_type == ir::DataType::FLOAT32) + { + invoke(in_tensor, out_tensor, maxpool_node.param()); + } + else + { + throw std::runtime_error{"NYI: Support float32 only"}; + } +} +} // namespace + +OpKernel *getMaxPool2D() +{ + static OpKernel kernel = {prepareMaxPool2D, invokeMaxPool2D}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/OperationUtil.h b/runtime/onert/core/src/interp/operations/OperationUtil.h new file mode 100644 index 000000000..cdabe508d --- /dev/null +++ b/runtime/onert/core/src/interp/operations/OperationUtil.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_INTERP_OPERATIONS_OPERATION_UTILS_H_ +#define __ONERT_INTERP_OPERATIONS_OPERATION_UTILS_H_ + +#include "ir/Shape.h" +#include "ir/InternalType.h" +#include "ir/Padding.h" + +#include +#include + +namespace onert +{ +namespace interp +{ + +inline nnfw::cker::Shape convertShape(const ir::Shape &shape) +{ + auto dimensions = std::vector(shape.dims().begin(), shape.dims().end()); + + std::vector raw_shape; + raw_shape.resize(4); + + for (uint32_t i = 0; i < 4; ++i) + { + if (i >= dimensions.size()) + { + raw_shape[i] = 1; + } + else + { + raw_shape[i] = dimensions[i]; + } + } + + return nnfw::cker::GetShape(raw_shape); +} + +inline nnfw::cker::Shape convertExtendShape(const ir::Shape &shape) +{ + auto dimensions = std::vector(shape.dims().begin(), shape.dims().end()); + + std::vector raw_shape; + raw_shape.resize(4); + uint32_t start = 4 - dimensions.size(); + + for (uint32_t i = 0; i < 4; ++i) + { + if (i < start) + { + raw_shape[i] = 1; + } + else + { + raw_shape[i] = dimensions[i - start]; + } + } + + return nnfw::cker::GetShape(raw_shape); +} + +inline nnfw::cker::FusedActivationFunctionType +convertActivationType(const ir::Activation activation) +{ + switch (activation) + { + case ir::Activation::NONE: + return nnfw::cker::FusedActivationFunctionType::kNone; + case ir::Activation::RELU: + return nnfw::cker::FusedActivationFunctionType::kRelu; + case ir::Activation::RELU1: + return nnfw::cker::FusedActivationFunctionType::kRelu1; + case ir::Activation::RELU6: + return nnfw::cker::FusedActivationFunctionType::kRelu6; + default: + throw std::runtime_error{"CPU backend: Cannot convert activation type"}; + } +} + +template +void calculateActivationRange(ir::Activation activation, T *activation_min, T *activation_max) +{ + if (activation == ir::Activation::RELU) + { + *activation_min = 0; + *activation_max = std::numeric_limits::max(); + } + else if (activation == ir::Activation::RELU6) + { + *activation_min = 0; + *activation_max = 6; + } + else if (activation == ir::Activation::RELU1) + { + *activation_min = -1; + *activation_max = 1; + } + else if (activation == ir::Activation::NONE) + { + *activation_min = std::numeric_limits::lowest(); + *activation_max = std::numeric_limits::max(); + } + else + { + throw std::runtime_error{"Unsupported activation type"}; + } +} + +inline ir::Shape calcBroadcastShape(const ir::Shape &lhs, const ir::Shape &rhs, bool &success) +{ + int lhs_rank = lhs.rank(); + int rhs_rank = rhs.rank(); + + int out_rank = (lhs_rank > rhs_rank ? lhs_rank : rhs_rank); + ir::Shape out_shape(out_rank); + + int lhs_idim = lhs_rank - 1; + int rhs_idim = rhs_rank - 1; + success = true; + for (int out_idim = out_rank - 1; out_idim >= 0; out_idim--) + { + if (lhs_idim == -1 && rhs_idim == -1) + { + // invalid result + success = false; + break; + } + + if (lhs_idim == -1) + { + out_shape.dim(out_idim) = rhs.dim(rhs_idim); + rhs_idim--; + } + else if (rhs_idim == -1) + { + out_shape.dim(out_idim) = lhs.dim(lhs_idim); + lhs_idim--; + } + else + { + if (lhs.dim(lhs_idim) == rhs.dim(rhs_idim)) + { + out_shape.dim(out_idim) = lhs.dim(lhs_idim); + lhs_idim--; + rhs_idim--; + } + else if (lhs.dim(lhs_idim) == 1) + { + out_shape.dim(out_idim) = rhs.dim(rhs_idim); + lhs_idim--; + rhs_idim--; + } + else if (rhs.dim(rhs_idim) == 1) + { + out_shape.dim(out_idim) = lhs.dim(lhs_idim); + lhs_idim--; + rhs_idim--; + } + else + { + // invalid result + success = false; + break; + } + } + } + + if (lhs_idim != -1 || rhs_idim != -1) + { + // invalid result + success = false; + } + return out_shape; +} + +inline nnfw::cker::PaddingType convertPaddingType(ir::PaddingType ir_padding_type) +{ + switch (ir_padding_type) + { + case ir::PaddingType::EXPLICIT: + return nnfw::cker::PaddingType::kNone; + case ir::PaddingType::SAME: + return nnfw::cker::PaddingType::kSame; + case ir::PaddingType::VALID: + return nnfw::cker::PaddingType::kValid; + default: + throw std::runtime_error("Wrong padding type."); + break; + } +} + +} // namespace interp +} // namespace onert + +#endif // __ONERT_INTERP_OPERATIONS_OPERATION_UTILS_H_ diff --git a/runtime/onert/core/src/interp/operations/Pad.cc b/runtime/onert/core/src/interp/operations/Pad.cc new file mode 100644 index 000000000..d2e3627b4 --- /dev/null +++ b/runtime/onert/core/src/interp/operations/Pad.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/Pad.h" + +namespace onert +{ +namespace interp +{ +namespace +{ + +void preparePad(ExecEnv *env, const ir::Operation &node) +{ + const auto input_index = node.getInputs().at(ir::operation::Pad::INPUT); + const auto output_index = node.getOutputs().at(0); + + const auto input_tensor = env->tensorAt(input_index); + + const auto output_info = env->graph().operands().at(output_index).info(); + + // Check shape and type lhs is same with rhs + // TODO Util function to compare TensorInfo + if (output_info.total_size() == 0) + { + throw std::runtime_error{"Interp(Pad): NYI unspecified output shape"}; + } + else + { + env->allocateIfNeeded(output_index, output_info); + } + + const auto output_tensor = env->tensorAt(output_index); + if (input_tensor->data_type() != output_tensor->data_type()) + { + throw std::runtime_error{"Interp(Pad): Invalid output type"}; + } +} + +void invoke(const ITensor *input_tensor, const ITensor *pad_tensor, const ITensor *output_tensor) +{ + const auto input_buffer = input_tensor->bufferRO(); + const auto pad_buffer = pad_tensor->bufferRO(); + auto output_buffer = output_tensor->buffer(); + + int32_t pad_rank = pad_tensor->dimension(0); + + const auto cker_input_shape = convertShape(input_tensor->tensorInfo().shape()); + const auto cker_output_shape = convertShape(output_tensor->tensorInfo().shape()); + const float *input_ptr = reinterpret_cast(input_buffer); + const int32_t *pad_ptr = reinterpret_cast(pad_buffer); + float *output_ptr = reinterpret_cast(output_buffer); + + nnfw::cker::Pad(pad_ptr, pad_rank, cker_input_shape, input_ptr, cker_output_shape, output_ptr, + nullptr); +} + +void invokePad(const ExecEnv *env, const ir::Operation &node) +{ + const auto input_index = node.getInputs().at(ir::operation::Pad::INPUT); + const auto pad_index = node.getInputs().at(ir::operation::Pad::PAD); + const auto output_index = node.getOutputs().at(0); + + const auto input_tensor = env->tensorAt(input_index); + const auto pad_tensor = env->tensorAt(pad_index); + const auto output_tensor = env->tensorAt(output_index); + + const auto data_type = input_tensor->data_type(); + + if (data_type == ir::DataType::FLOAT32) + { + invoke(input_tensor, pad_tensor, output_tensor); + } + else + { + throw std::runtime_error{"Interp(Pad): NYI - Unsupported data type"}; + } +} +} // namespace + +OpKernel *getPad() +{ + static OpKernel kernel = {preparePad, invokePad}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/Reshape.cc b/runtime/onert/core/src/interp/operations/Reshape.cc new file mode 100644 index 000000000..3a118456b --- /dev/null +++ b/runtime/onert/core/src/interp/operations/Reshape.cc @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "interp/Registration.h" + +namespace onert +{ +namespace interp +{ +namespace +{ + +void prepare(ExecEnv *env, const ir::Operation &node) +{ + const auto in_index = node.getInputs().at(0); + const auto out_index = node.getOutputs().at(0); + + // Unspecified shape is not supported in operation node spec now + const auto output_info = env->graph().operands().at(out_index).info(); + env->allocateAndShareIfNeeded(out_index, output_info, in_index); + + assert(output_info.total_size() == env->graph().operands().at(in_index).info().total_size()); +} + +void invoke(const ExecEnv *env, const ir::Operation &node) +{ + const auto in_index = node.getInputs().at(0); + const auto out_index = node.getOutputs().at(0); + + if (env->tensorAt(in_index)->bufferRO() == env->tensorAt(out_index)->bufferRO()) + { + // Same data + return; + } + + const auto output_info = env->graph().operands().at(out_index).info(); + memcpy(env->tensorAt(out_index)->buffer(), env->tensorAt(in_index)->bufferRO(), + output_info.total_size()); +} + +} // namespace + +OpKernel *getReshape() +{ + static OpKernel kernel = {prepare, invoke}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/Softmax.cc b/runtime/onert/core/src/interp/operations/Softmax.cc new file mode 100644 index 000000000..afc4e81f7 --- /dev/null +++ b/runtime/onert/core/src/interp/operations/Softmax.cc @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/Softmax.h" +#include "misc/polymorphic_downcast.h" + +namespace onert +{ +namespace interp +{ +namespace +{ + +void Softmax2D(const float *in, const int input_size, const int batch_size, const float beta, + float *out) +{ + assert(input_size > 0); + + // For each batch + for (int b = 0; b < batch_size; b++) + { + // Find the max coeff. + float max_coeff = in[0]; + for (int i = 1; i < input_size; i++) + { + if (in[i] > max_coeff) + max_coeff = in[i]; + } + + // Compute the normalized sum of exps. + float exp_sum = 0.0; + for (int i = 0; i < input_size; i++) + { + out[i] = std::exp((in[i] - max_coeff) * beta); + exp_sum += out[i]; + } + + // Divide by the sum of exps. + float reciprocal_sum_exp = 1.f / exp_sum; + for (int i = 0; i < input_size; i++) + { + out[i] *= reciprocal_sum_exp; + } + + // Advance in and out pointers for the next batch. + in += input_size; + out += input_size; + } +} + +void prepareSoftMax(ExecEnv *env, const ir::Operation &node) +{ + const auto in_index = node.getInputs().at(0); + const auto out_index = node.getOutputs().at(0); + + const auto in_tensor = env->tensorAt(in_index); + UNUSED_RELEASE(in_tensor); + + assert((in_tensor->num_dimensions() == 4) || (in_tensor->num_dimensions() == 2)); + + // Output shape should be same with input + // Output type is pre-defined in model + const auto output_shape = env->graph().operands().at(in_index).info().shape(); + const auto output_type = env->graph().operands().at(out_index).info().typeInfo(); + + const ir::OperandInfo output_info{output_shape, output_type}; + env->allocateIfNeeded(out_index, output_info); + + auto out_tensor = env->tensorAt(out_index); + UNUSED_RELEASE(out_tensor); + + // Check output shape is same with input + assert(out_tensor->num_dimensions() == out_tensor->num_dimensions()); + for (uint32_t i = 0; i < in_tensor->num_dimensions(); i++) + { + assert(in_tensor->dimension(i) == out_tensor->dimension(i)); + } +} + +void invoke(const ITensor *in_tensor, const ITensor *out_tensor, + const ir::operation::Softmax::Param ¶m) +{ + const float *in_ptr = reinterpret_cast(in_tensor->bufferRO()); + float *out_ptr = reinterpret_cast(out_tensor->buffer()); + + float beta = param.beta; + + if (in_tensor->num_dimensions() == 2) + { + uint32_t batch_size = in_tensor->dimension(0); + uint32_t input_size = in_tensor->dimension(1); + + Softmax2D(in_ptr, input_size, batch_size, beta, out_ptr); + } + else if (in_tensor->num_dimensions() == 4) + { + const auto in_shape = convertShape(in_tensor->tensorInfo().shape()); + const auto out_shape = convertShape(out_tensor->tensorInfo().shape()); + + nnfw::cker::SoftmaxParams cker_param; + cker_param.beta = beta; + + nnfw::cker::Softmax(cker_param, in_shape, in_ptr, out_shape, out_ptr); + } + else + { + throw std::runtime_error{"Unsuported input dimension: support 2D or 4D"}; + } +} + +void invokeSoftMax(const ExecEnv *env, const ir::Operation &node) +{ + const auto &softmax_node = nnfw::misc::polymorphic_downcast(node); + + const auto in_index = node.getInputs().at(0); + const auto out_index = node.getOutputs().at(0); + + const auto in_tensor = env->tensorAt(in_index); + const auto out_tensor = env->tensorAt(out_index); + + const auto in_data_type = in_tensor->data_type(); + const auto out_data_type = out_tensor->data_type(); + if ((in_data_type == ir::DataType::FLOAT32) && (out_data_type == ir::DataType::FLOAT32)) + { + invoke(in_tensor, out_tensor, softmax_node.param()); + } + else + { + throw std::runtime_error{"NYI: Support float32 only"}; + } +} + +} // namespace + +OpKernel *getSoftmax() +{ + static OpKernel kernel = {prepareSoftMax, invokeSoftMax}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/TransposeConv.cc b/runtime/onert/core/src/interp/operations/TransposeConv.cc new file mode 100644 index 000000000..cc2ced26b --- /dev/null +++ b/runtime/onert/core/src/interp/operations/TransposeConv.cc @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" +#include "ir/operation/TransposeConv.h" + +namespace onert +{ +namespace interp +{ +namespace +{ + +void prepareTransposeConv(ExecEnv *env, const ir::Operation &node) +{ + const auto ifm_index = node.getInputs().at(ir::operation::TransposeConv::INPUT); + const auto ker_index = node.getInputs().at(ir::operation::TransposeConv::KERNEL); + const auto ofm_shape_index = node.getInputs().at(ir::operation::TransposeConv::OUTPUT_SHAPE); + const auto ofm_index = node.getOutputs().at(0); + + const auto ifm_tensor = env->tensorAt(ifm_index); + const auto ker_tensor = env->tensorAt(ker_index); + const auto ofm_shape_tensor = env->tensorAt(ofm_shape_index); + + assert(ifm_tensor->num_dimensions() == 4); + assert(ker_tensor->num_dimensions() == 4); + assert(ofm_shape_tensor->num_dimensions() == 1); + + UNUSED_RELEASE(ifm_tensor); + UNUSED_RELEASE(ker_tensor); + UNUSED_RELEASE(ofm_shape_tensor); + + const auto output_info = env->graph().operands().at(ofm_index).info(); + if (output_info.total_size() == 0) + { + // TODO: Handle unspecified output shape + throw std::runtime_error{"Interp(TConv): NYI unspecified output shape"}; + } + else + { + env->allocateIfNeeded(ofm_index, output_info); + } + + auto ofm_tensor = env->tensorAt(ofm_index); + UNUSED_RELEASE(ofm_tensor); + + // Handle same ifm & ofm data type only + if (ifm_tensor->data_type() != ofm_tensor->data_type()) + { + throw std::runtime_error{"Interp(TConv): Different I/O data dype"}; + } + + if (ofm_tensor->num_dimensions() != 4) + { + throw std::runtime_error{"Interp(TConv): Invalid output rank"}; + } +} + +void invoke(const ITensor *ifm_tensor, const ITensor *ker_tensor, const ITensor *ofm_tensor, + const ir::operation::TransposeConv::Param ¶m) +{ + const auto ifm_shape = ifm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + const auto ofm_shape = ofm_tensor->tensorInfo().shape().asFeature(ir::Layout::NHWC); + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in]. + const auto ker_shape = ker_tensor->tensorInfo().shape(); + const auto ker_height = ker_shape.dim(1); + const auto ker_width = ker_shape.dim(2); + const auto padding = ir::calculatePadding(param.padding, ofm_shape, ifm_shape, param.stride, + ker_width, ker_height); + + nnfw::cker::TransposeConvParams cker_param; + cker_param.padding_values.width = padding.left; + cker_param.padding_values.height = padding.top; + cker_param.stride_width = param.stride.horizontal; + cker_param.stride_height = param.stride.vertical; + cker_param.dilation_width_factor = 1; + cker_param.dilation_height_factor = 1; + + const auto cker_ifm_shape = convertShape(ifm_tensor->tensorInfo().shape()); + const auto cker_ker_shape = convertShape(ker_tensor->tensorInfo().shape()); + const auto cker_ofm_shape = convertShape(ofm_tensor->tensorInfo().shape()); + const float *ifm_ptr = reinterpret_cast(ifm_tensor->bufferRO()); + const float *ker_ptr = reinterpret_cast(ker_tensor->bufferRO()); + float *ofm_ptr = reinterpret_cast(ofm_tensor->buffer()); + + nnfw::cker::TransposeConv(cker_param, cker_ifm_shape, ifm_ptr, cker_ker_shape, ker_ptr, + cker_ofm_shape, ofm_ptr); +} + +void invokeTransposeConv(const ExecEnv *env, const ir::Operation &node) +{ + const auto &tconv_node = + nnfw::misc::polymorphic_downcast(node); + + const auto ifm_index = node.getInputs().at(ir::operation::TransposeConv::INPUT); + const auto ker_index = node.getInputs().at(ir::operation::TransposeConv::KERNEL); + const auto ofm_index = node.getOutputs().at(0); + + const auto ifm_tensor = env->tensorAt(ifm_index); + const auto ker_tensor = env->tensorAt(ker_index); + const auto ofm_tensor = env->tensorAt(ofm_index); + + const auto data_type = ifm_tensor->data_type(); + if (data_type == ir::DataType::FLOAT32) + { + invoke(ifm_tensor, ker_tensor, ofm_tensor, tconv_node.param()); + } + else + { + throw std::runtime_error{"Interp(TConv): Support float32 only"}; + } +} + +} // namespace + +OpKernel *getTransposeConv() +{ + static OpKernel kernel = {prepareTransposeConv, invokeTransposeConv}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/interp/operations/UnaryActivations.cc b/runtime/onert/core/src/interp/operations/UnaryActivations.cc new file mode 100644 index 000000000..ea5e2417b --- /dev/null +++ b/runtime/onert/core/src/interp/operations/UnaryActivations.cc @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "OperationUtil.h" + +#include "interp/Registration.h" + +#include "ir/operation/ReLU.h" +#include "ir/operation/ReLU1.h" +#include "ir/operation/ReLU6.h" +#include "ir/operation/Tanh.h" + +namespace onert +{ +namespace interp +{ +namespace +{ + +enum class ActivationType +{ + ReLU, + ReLU1, + ReLU6, + Tanh +}; + +void prepare(ExecEnv *env, const ir::Operation &node) +{ + const auto input_index = node.getInputs().at(0); + const auto output_index = node.getOutputs().at(0); + + const auto input_tensor = env->tensorAt(input_index); + + const auto output_info = env->graph().operands().at(output_index).info(); + if (output_info.total_size() == 0) + { + // Output's shape and type is same with input + auto input_info = input_tensor->tensorInfo(); + // We can handle already allocated (ex. model output) + env->allocateIfNeeded(output_index, input_info); + } + else + { + env->allocateIfNeeded(output_index, output_info); + } + + const auto output_tensor = env->tensorAt(output_index); + // Check shape and type lhs is same with output + // TODO Util function to compare TensorInfo + if (input_tensor->data_type() != output_tensor->data_type()) + { + throw std::runtime_error{"Interp(Activations): Invalid output type"}; + } +} + +template +void evalFloat(const float *input_ptr, float *output_ptr, uint64_t num_elements) +{ + std::function fn = [](const float &) { return std::nanf(""); }; + switch (act_type) + { + case ActivationType::ReLU: + fn = [](const float &in) { return std::max(0.f, in); }; + break; + case ActivationType::ReLU1: + fn = [](const float &in) { return std::min(std::max(-1.f, in), 1.f); }; + break; + case ActivationType::ReLU6: + fn = [](const float &in) { return std::min(std::max(0.f, in), 6.f); }; + break; + case ActivationType::Tanh: + fn = [](const float &in) { return std::tanh(in); }; + break; + default: + throw std::runtime_error{"Interp(Activations): NYI - Unsupported activation"}; + break; + } + + const float *input_end = input_ptr + num_elements; + for (; input_ptr < input_end; input_ptr++, output_ptr++) + { + *output_ptr = fn(*input_ptr); + } +} + +template void invoke(const ExecEnv *env, const ir::Operation &node) +{ + const auto input_index = node.getInputs().at(0); + const auto output_index = node.getOutputs().at(0); + + // Check lhs shape is same with rhs (with broadcast) + const auto input_tensor = env->tensorAt(input_index); + const auto output_tensor = env->tensorAt(output_index); + + const auto data_type = input_tensor->data_type(); + if (data_type == ir::DataType::FLOAT32) + { + uint64_t elements = input_tensor->num_elements(); + const float *input_start = reinterpret_cast(input_tensor->bufferRO()); + float *out = reinterpret_cast(output_tensor->buffer()); + + evalFloat(input_start, out, elements); + } + else + { + throw std::runtime_error{"Interp(ReLU6): NYI - Support float only"}; + } +} + +} // namespace + +OpKernel *getReLU() +{ + static OpKernel kernel = {prepare, invoke}; + return &kernel; +} + +OpKernel *getReLU1() +{ + static OpKernel kernel = {prepare, invoke}; + return &kernel; +} + +OpKernel *getReLU6() +{ + static OpKernel kernel = {prepare, invoke}; + return &kernel; +} + +OpKernel *getTanh() +{ + static OpKernel kernel = {prepare, invoke}; + return &kernel; +} + +} // namespace interp +} // namespace onert diff --git a/runtime/onert/core/src/ir/Coordinates.cc b/runtime/onert/core/src/ir/Coordinates.cc new file mode 100644 index 000000000..a02a56567 --- /dev/null +++ b/runtime/onert/core/src/ir/Coordinates.cc @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Coordinates.h" + +#include + +namespace onert +{ +namespace ir +{ + +Coordinates convertCoordinates(const Coordinates &from_coordinates, Layout from_layout, + Layout to_layout) +{ + assert(from_coordinates.size() == 4); + Coordinates to{from_coordinates}; + if (from_layout == Layout::NHWC && to_layout == Layout::NCHW) + { + to.set(0, from_coordinates[0]); + to.set(1, from_coordinates[3]); + to.set(2, from_coordinates[1]); + to.set(3, from_coordinates[2]); + } + else if (from_layout == Layout::NCHW && to_layout == Layout::NHWC) + { + to.set(0, from_coordinates[0]); + to.set(1, from_coordinates[2]); + to.set(2, from_coordinates[3]); + to.set(3, from_coordinates[1]); + } + + return to; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/Graph.cc b/runtime/onert/core/src/ir/Graph.cc new file mode 100644 index 000000000..837a88a6b --- /dev/null +++ b/runtime/onert/core/src/ir/Graph.cc @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Graph.h" + +#include +#include +#include + +#include "util/logging.h" +#include "verifier/Verifier.h" +#include "ir/operation/LowerInfo.h" +#include "ir/operand/LowerInfo.h" +#include "ir/operand/PermuteFactor.h" +#include "ir/GraphIterator.h" +#include "backend/IConfig.h" + +namespace onert +{ +namespace ir +{ + +Graph::Graph() = default; + +Graph::~Graph(void) = default; + +OperandIndex Graph::addOperand(const Shape &shape, const TypeInfo &type) +{ + return _operands.emplace(shape, type); +} + +OperationIndex Graph::addOperation(std::unique_ptr &&node) +{ + assert(isBuildingPhase()); + return _operations.push(std::move(node)); +} + +void Graph::setOperandValue(const OperandIndex &ind, std::shared_ptr data) +{ + assert(isBuildingPhase()); + assert(_operands.exist(ind)); + _operands.at(ind).data(std::move(data)); +} + +void Graph::addInput(const OperandIndex &ind) +{ + assert(isBuildingPhase()); + _inputs.append(ind); +} + +void Graph::addOutput(const OperandIndex &ind) +{ + assert(isBuildingPhase()); + _outputs.append(ind); +} + +void Graph::finishBuilding(void) +{ + assert(isBuildingPhase()); + _phase = Phase::MODEL; + + // Initialize operand use-def + initializeUseDef(); + + // Call graph verifications for the MODEL phase + { + assert(verifier::DAGChecker().verify(*this)); + assert(verifier::EdgeConsistencyChecker().verify(*this)); + } +} + +void Graph::initializeUseDef() +{ + operations().iterate([&](const OperationIndex &index, const Operation &node) -> void { + auto outputs = node.getOutputs(); + for (auto output : outputs) + { + operands().at(output).appendDef(index); + } + + auto inputs = node.getInputs(); + for (auto input : inputs) + { + operands().at(input).appendUse(index); + } + }); +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/GraphIterator.cc b/runtime/onert/core/src/ir/GraphIterator.cc new file mode 100644 index 000000000..9e8b3e533 --- /dev/null +++ b/runtime/onert/core/src/ir/GraphIterator.cc @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "GraphIterator.h" + +#include "ir/OperationIndexMap.h" +#include "ir/Graph.h" + +namespace onert +{ +namespace ir +{ + +// Explicit instantiations to have implementation in the source file. + +template class DefaultIterator; +template class DefaultIterator; + +template class PostDfsIterator; +template class PostDfsIterator; + +// +// Graph::DefaultIterator +// + +template +void DefaultIterator::iterate(GraphRef graph, const IterFn &fn) const +{ + graph.operations().iterate( + [&](const OperationIndex &index, NodeRef node) -> void { fn(index, node); }); +} + +// +// Graph::PostDfsIterator +// + +template +void PostDfsIterator::iterate(GraphRef graph, const IterFn &fn) const +{ + assert(!graph.isBuildingPhase()); // Restrict iteration condition + + OperationIndexMap visited; + graph.operations().iterate([&](const OperationIndex &index, NodeRef) { visited[index] = false; }); + + std::function dfs_recursive = + [&](const OperationIndex &index, NodeRef node) -> void { + if (visited[index]) + return; + visited[index] = true; + + for (auto output : node.getOutputs()) + { + const auto &operand = graph.operands().at(output); + for (const auto &use : operand.getUses().list()) + { + dfs_recursive(use, graph.operations().at(use)); + } + } + + fn(index, node); + }; + + graph.operations().iterate(dfs_recursive); + + // All of the operations(nodes) must have been visited. + assert(std::all_of(visited.begin(), visited.end(), + [](const std::pair &v) { return v.second; })); +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/GraphIterator.h b/runtime/onert/core/src/ir/GraphIterator.h new file mode 100644 index 000000000..42c851895 --- /dev/null +++ b/runtime/onert/core/src/ir/GraphIterator.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_GRAPH_ITERATOR_H__ +#define __ONERT_IR_GRAPH_ITERATOR_H__ + +#include + +#include "ir/Index.h" + +namespace onert +{ +namespace ir +{ + +class Graph; +class Operation; + +template class Iterator +{ +public: + using GraphRef = typename std::conditional::type; + using IndexRef = const OperationIndex &; + using NodeRef = typename std::conditional::type; + using IterFn = std::function; + +public: + virtual ~Iterator() = default; + virtual void iterate(GraphRef graph, const IterFn &fn) const = 0; +}; + +template class DefaultIterator final : public Iterator +{ +public: + using GraphRef = typename Iterator::GraphRef; + using IndexRef = typename Iterator::IndexRef; + using NodeRef = typename Iterator::NodeRef; + using IterFn = typename Iterator::IterFn; + +public: + void iterate(GraphRef graph, const IterFn &fn) const; +}; +using DefaultConstIterator = DefaultIterator; + +template class PostDfsIterator final : public Iterator +{ +public: + using GraphRef = typename Iterator::GraphRef; + using IndexRef = typename Iterator::IndexRef; + using NodeRef = typename Iterator::NodeRef; + using IterFn = typename Iterator::IterFn; + +public: + void iterate(GraphRef graph, const IterFn &fn) const; +}; +using PostDfsConstIterator = PostDfsIterator; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_GRAPH_ITERATOR_H__ diff --git a/runtime/onert/core/src/ir/LayoutSet.cc b/runtime/onert/core/src/ir/LayoutSet.cc new file mode 100644 index 000000000..bd3f438ad --- /dev/null +++ b/runtime/onert/core/src/ir/LayoutSet.cc @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LayoutSet.h" + +namespace onert +{ +namespace ir +{ + +LayoutSet::LayoutSet(std::initializer_list layouts) +{ + for (auto layout : layouts) + { + _set.insert(layout); + } +} + +LayoutSet LayoutSet::operator|(const LayoutSet &other) const +{ + auto ret = *this; + for (auto layout : other) + { + ret.add(layout); + } + return ret; +} + +LayoutSet LayoutSet::operator&(const LayoutSet &other) const +{ + LayoutSet ret; + for (auto layout : other) + { + if (contains(layout)) + { + ret.add(layout); + } + } + return ret; +} + +LayoutSet LayoutSet::operator-(const LayoutSet &other) const +{ + auto ret = *this; + for (auto layout : other) + { + ret.remove(layout); + } + return ret; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/LayoutSet.h b/runtime/onert/core/src/ir/LayoutSet.h new file mode 100644 index 000000000..6ce4e38c6 --- /dev/null +++ b/runtime/onert/core/src/ir/LayoutSet.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_LAYOUT_SET_H__ +#define __ONERT_IR_LAYOUT_SET_H__ + +#include +#include + +#include "ir/Layout.h" + +namespace onert +{ +namespace ir +{ + +class LayoutSet +{ +public: + LayoutSet() = default; + LayoutSet(std::initializer_list layouts); + +public: + void add(const Layout &layout) { _set.insert(layout); } + void remove(const Layout &layout) { _set.erase(layout); } + uint32_t size() const { return static_cast(_set.size()); } + bool contains(const Layout &layout) const { return _set.find(layout) != _set.end(); } + +public: + LayoutSet operator|(const LayoutSet &other) const; // Union + LayoutSet operator&(const LayoutSet &other) const; // Intersect + LayoutSet operator-(const LayoutSet &other) const; // Minus + +public: + std::unordered_set::const_iterator begin() const { return _set.begin(); } + std::unordered_set::const_iterator end() const { return _set.end(); } + +private: + std::unordered_set _set; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_LAYOUT_SET_H__ diff --git a/runtime/onert/core/src/ir/LoweredGraph.cc b/runtime/onert/core/src/ir/LoweredGraph.cc new file mode 100644 index 000000000..0018650e2 --- /dev/null +++ b/runtime/onert/core/src/ir/LoweredGraph.cc @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/LoweredGraph.h" + +#include +#include +#include "util/logging.h" +#include "pass/ConstantInsertionPass.h" +#include "pass/PermutationOperationPass.h" +#include "pass/PermutationInsertionPass.h" +#include "ir/GraphIterator.h" +#include "verifier/Verifier.h" +#include "backend/Backend.h" +#include "backend/IConfig.h" +#include "compiler/BackendResolver.h" +#include "compiler/ManualScheduler.h" +#include "compiler/HEScheduler.h" + +namespace onert +{ +namespace ir +{ + +LoweredGraph::LoweredGraph(const Graph &graph, const compiler::CompilerOptions &options) + : _graph{graph} +{ + // Build backend contexts + auto &backend_manager = compiler::BackendManager::get(); + for (auto backend_str : options.backend_list) + { + backend_manager.loadBackend(backend_str); + auto backend = backend_manager.get(backend_str); + + // TODO As the default value of backend list contains "cpu", "acl_cl" and "acl_neon", and some + // are not available on x64 or some other platforms. So this may be a workaround for x64 and + // we should change it back(throw if backend is not loaded) later. + if (!backend) + { + VERBOSE(LoweredGraph) << "Cannot load backend - " << backend_str; + continue; + } + + _backend_contexts.emplace(backend, backend->newContext(_graph, _graph.getKernelBuilder(), + options.executor == "Linear")); + } + if (backend_manager.getAll().size() == 0) + throw std::runtime_error{"No available backends loaded."}; + + // TODO Move "schedule" phase out of here + // Schedule + if (options.he_scheduler) + { + auto scheduler = compiler::HEScheduler(_backend_contexts, options); + _backend_resolver = scheduler.schedule(_graph); + _indexed_ranks = scheduler.getIndexedRanks(); + } + else + { + auto scheduler = compiler::ManualScheduler(options.manual_scheduler_options); + _backend_resolver = scheduler.schedule(_graph); + } + + { + // operand::LowerInfo holder + OperandIndexMap> operands_lower_info; + + _graph.operands().iterate([&](const OperandIndex &index, const Operand &) { + operands_lower_info[index] = std::make_unique(); + }); + + // Make op_seqs while checking whether a node can be merged into a op_seq. + makeOpSequences(operands_lower_info, options); + + _op_seqs.iterate([&](const OpSequenceIndex &, OpSequence &op_seq) { + assert(op_seq.operations().size() > 0); + std::reverse(std::begin(op_seq.operations()), std::end(op_seq.operations())); + }); + + _op_seqs.dump("merged and sorted operations without permutation"); + + pass::ConstantInsertionPass ci_pass(*this); + ci_pass.run(); + + // Set LowerInfo for each operand from the operand::LowerInfo holder + manipulateLowerInfo(operands_lower_info); + + dumpLowerInfo(); + } + + // Run Permutation Passes + { + pass::PermutationOperationPass po_pass(*this); + po_pass.run(); + + pass::PermutationInsertionPass pi_pass(*this); + pi_pass.run(); + // Implemented code no longer works. + // pass::PermutationEliminationPass pe_pass(*this); + // pe_pass.run(); + + // TODO merge perm op_seqs if possible + _op_seqs.dump("merged and sorted operations with permutation"); + } + + // Graph verifications + { + assert(verifier::DAGChecker().verify(_graph)); + assert(verifier::EdgeConsistencyChecker().verify(_graph)); + } +} + +const operation::LowerInfo *LoweredGraph::getLowerInfo(const OpSequenceIndex &op_seq_index) const +{ + auto itr = _lower_info_map.operation.find(op_seq_index); + if (itr == _lower_info_map.operation.end()) + return nullptr; + return itr->second.get(); +} + +void LoweredGraph::setLowerInfo(const OpSequenceIndex &op_seq_index, + std::unique_ptr &&lower_info) +{ + _lower_info_map.operation.insert(std::make_pair(op_seq_index, std::move(lower_info))); +} + +void LoweredGraph::removeLowerInfo(const OpSequenceIndex &op_seq_index) +{ + auto &op_seq_lower_info = _lower_info_map.operation; + assert(op_seq_lower_info.find(op_seq_index) != op_seq_lower_info.end()); + for (auto it = op_seq_lower_info.begin(); it != op_seq_lower_info.end(); ++it) + { + if (it->first == op_seq_index) + { + op_seq_lower_info.erase(it); + break; + } + } +} + +const operand::LowerInfo *LoweredGraph::getLowerInfo(const OperandIndex &index) const +{ + auto itr = _lower_info_map.operand.find(index); + if (itr == _lower_info_map.operand.end()) + return nullptr; + return itr->second.get(); +} + +operand::LowerInfo *LoweredGraph::getLowerInfo(const OperandIndex &index) +{ + auto itr = _lower_info_map.operand.find(index); + if (itr == _lower_info_map.operand.end()) + return nullptr; + return itr->second.get(); +} + +void LoweredGraph::setLowerInfo(const OperandIndex &index, + std::unique_ptr &&lower_info) +{ + _lower_info_map.operand.insert(std::make_pair(index, std::move(lower_info))); +} + +void LoweredGraph::removeLowerInfo(const OperandIndex &index) +{ + _lower_info_map.operand.erase(index); +} + +OpSequenceIndex LoweredGraph::appendFreshSingleOpSequence(const OperationIndex &node_index, + const Operation &node) +{ + // Create a fresh op_seq with one operation, and append it to op_seqs + // Create a fresh op_seq + auto op_seq = std::make_unique(_graph.layout()); + + // Add an operation + op_seq->appendOperation(node_index, node); + + // Update input/output + op_seq->setOutputs(node.getOutputs()); + op_seq->setInputs(node.getInputs()); + + return _op_seqs.emplace(std::move(op_seq)); +} + +void LoweredGraph::makeOpSequences( + OperandIndexMap> &operands_lower_info, + const compiler::CompilerOptions &options) +{ + // if SUBG_MAX_NODE == 0, no limit on nodes of a op_seq + const int op_seq_max_node = options.op_seq_max_node; + assert(op_seq_max_node >= 0); + + bool is_profiling = options.he_profiling_mode; + OpSequence *op_seq = nullptr; + OpSequenceIndex op_seq_index; + + // NOTE: The below method appends nodes while making one op_seq if needed. If something better + // ways, happy to update this code. + PostDfsConstIterator{}.iterate( + _graph, [&](const OperationIndex &node_index, const Operation &node) { + // LowerInfo for in/output operands + auto backend = _backend_resolver->getBackend(node_index); + + // Set backend's layout to frontend layout + auto backend_layout = _graph.layout(); + + // The layout of each backend should be set at another place + // TODO Change setting layout of each backend at another place + // TODO Remove getting id of backend + if (backend->config()->id() == "acl_cl" || backend->config()->id() == "acl_neon") + { + const std::string acl_layout_str = util::getConfigString(util::config::ACL_LAYOUT); + if (acl_layout_str == "NHWC") + { + backend_layout = Layout::NHWC; + } + else if (acl_layout_str == "NCHW") + { + backend_layout = Layout::NCHW; + } + } + else if (backend->config()->id() == "srcn") + { + const std::string ncnn_layout_str = util::getConfigString(util::config::NCNN_LAYOUT); + if (ncnn_layout_str == "NHWC") + { + backend_layout = Layout::NHWC; + } + else if (ncnn_layout_str == "NCHW") + { + backend_layout = Layout::NCHW; + } + } + else if (backend->config()->id() == "cpu") + { + backend_layout = Layout::NHWC; + } + + for (auto operand : node.getInputs()) + { + auto &&lower_info = operands_lower_info.at(operand); + lower_info->addUsePermuteFactor(operand::PermuteFactor{backend, backend_layout}); + } + for (auto operand : node.getOutputs()) + { + auto &&lower_info = operands_lower_info.at(operand); + lower_info->addDefPermuteFactor(operand::PermuteFactor{backend, backend_layout}); + } + + bool new_op_seq = (op_seq == nullptr || + (op_seq_max_node != 0 && + op_seq->operations().size() >= static_cast(op_seq_max_node))); + + // for profiling each op_seq must contain just one node, + // so that we can measure a node separately + if (new_op_seq || is_profiling || !mergeable(op_seq_index, node_index, backend_layout)) + { + auto new_op_seq_index = appendFreshSingleOpSequence(node_index, node); + + // OpSequence LowerInfo + setLowerInfo(new_op_seq_index, + std::make_unique(backend, backend_layout)); + + op_seq_index = new_op_seq_index; + op_seq = &(_op_seqs.at(new_op_seq_index)); + + VERBOSE(Lower) << "SUBG#" << op_seq_index.value() << " is created for " + << "NODE#" << node_index.value() << "(" << node.name() << ")" << std::endl; + } + else + { + op_seq->appendOperation(node_index, node); + op_seq->setInputs(node.getInputs()); + + VERBOSE(Lower) << "SUBG#" << op_seq_index.value() << " merges " + << "NODE#" << node_index.value() << "(" << node.name() << ")" << std::endl; + } + }); +} + +void LoweredGraph::manipulateLowerInfo( + OperandIndexMap> &operands_lower_info) +{ + const auto default_backend = compiler::BackendManager::get().getDefault(); + for (auto index : _graph.getInputs()) + { + // Pick just any one from the uses, here the first one is chosen + // For the other uses, Permute operations will be inserted later + auto &&lower_info = operands_lower_info.at(index); + assert(lower_info->use_factors().size() > 0); + lower_info->addDefPermuteFactor(*lower_info->use_factors().begin()); + } + for (auto index : _graph.getOutputs()) + { + auto &&lower_info = operands_lower_info.at(index); + if (_graph.operands().at(index).isConstant()) + { + lower_info->addDefPermuteFactor(operand::PermuteFactor{ + default_backend, + Layout::NHWC // TODO Get frontend layout of this node from IR + }); + } + } + + // Set LowerInfo for each operand from the operand::LowerInfo holder + _graph.operands().iterate([&](const OperandIndex &index, Operand &) { + setLowerInfo(index, std::move(operands_lower_info[index])); + }); +} + +void LoweredGraph::dumpLowerInfo() +{ + if (::onert::util::logging::ctx.enabled() == false) + return; + + std::map dumps; + + _graph.operands().iterate([&](const OperandIndex &index, Operand &object) { + std::stringstream sstream; + if (!getLowerInfo(index)->def_factors().empty() || !getLowerInfo(index)->use_factors().empty()) + { + auto factors_to_string = [](const operand::PermuteFactorSet &factors) { + std::string str; + for (auto factor : factors) + { + str += factor.backend()->config()->id(); + str += "(" + to_string(factor.layout()) + ")"; + str += " "; + } + return "{ " + str + "}"; + }; + + auto operation_index_to_string = [](const OperationIndexList &operations) { + std::string str; + for (auto op : operations.list()) + { + str += std::to_string(op.value()); + str += " "; + } + return "{ " + str + "}"; + }; + + const auto lower_info = getLowerInfo(index); + const auto &shape = object.shape(); + std::string def_ops = operation_index_to_string(object.getDef()); + std::string use_ops = operation_index_to_string(object.getUses()); + std::string def_layouts = factors_to_string(lower_info->def_factors()); + std::string use_layouts = factors_to_string(lower_info->use_factors()); + sstream << "Operand #" << index.value() << " LowerInfo" << std::endl; + sstream << " - Shape : { " << (shape.rank() > 0 ? shape.dim(0) : 0) << " " + << (shape.rank() > 1 ? shape.dim(1) : 0) << " " + << (shape.rank() > 2 ? shape.dim(2) : 0) << " " + << (shape.rank() > 3 ? shape.dim(3) : 0) << " " + << "}" << std::endl; + sstream << " - Def Operations : " << def_ops << std::endl; + sstream << " - Use Operations : " << use_ops << std::endl; + sstream << " - Lower Info" << std::endl; + sstream << " - Def Backends : " << def_layouts << std::endl; + sstream << " - Use Backends : " << use_layouts << std::endl; + } + dumps.emplace(index.value(), sstream.str()); + }); + + for (const auto &e : dumps) + { + if (!e.second.empty()) + { + VERBOSE(Lower) << e.second; + } + } +} + +bool LoweredGraph::mergeable(const OpSequenceIndex &op_seq_index, const OperationIndex &node_index, + Layout layout) +{ + // Are they mergeable? + // 1. the same backend id and layout? + // 2. Is op_seq or node branched? + // 3. if 1 is true, the op_seq and a node are connected? + const auto &op_seq = _op_seqs.at(op_seq_index); + const auto &node = _graph.operations().at(node_index); + + // The same backend id and layout? + { + const auto op_seq_backend_layout = getLowerInfo(op_seq_index)->layout(); + const auto &op_seq_backend_id = getLowerInfo(op_seq_index)->backend()->config()->id(); + const auto &node_backend_id = _backend_resolver->getBackend(node_index)->config()->id(); + VERBOSE(Lower) << "SUBG#" << op_seq_index.value() << " { " << op_seq_backend_id << "(" + << to_string(op_seq_backend_layout) << ") } " + << " NODE#" << node_index.value() << " (" << node.name() << ") { " + << node_backend_id << "(" << to_string(layout) << ") } " << std::endl; + if (op_seq_backend_id != node_backend_id || op_seq_backend_layout != layout) + return false; + } + + // Branched? + { + std::unordered_set branched_set; + + // Check for branching up + const auto &inputs = op_seq.getInputs(); + for (const auto &input : inputs) + { + const auto &input_obj = _graph.operands().at(input); + for (const auto &def : input_obj.getDef().list()) + { + branched_set.insert(def); + if (branched_set.size() > 1) + { + return false; + } + } + } + branched_set.clear(); + + // Check for branching down + const auto &outputs = node.getOutputs(); + for (const auto &output : outputs) + { + const auto &output_obj = _graph.operands().at(output); + for (const auto &use : output_obj.getUses().list()) + { + branched_set.insert(use); + if (branched_set.size() > 1) + { + return false; + } + } + } + } + + // Connected? + // an input of one node is an output of the other node? or vice-versa? + { + const auto &node_inputs = node.getInputs(); + const auto &node_outputs = node.getOutputs(); + + // op_seq's operations are in order so that we just check the first and the last + std::vector op_seq_ops{op_seq.operations()[0]}; + if (op_seq.operations().size() > 1) + op_seq_ops.emplace_back(op_seq.operations()[op_seq.operations().size() - 1]); + + for (const auto &elem : op_seq_ops) + { + const auto &n_index = elem.index; + const auto &n = *elem.node; + + // node's output == op_seq's input? + const auto &n_inputs = n.getInputs(); + for (auto input : n_inputs) + { + if (node_outputs.contains(input)) + { + VERBOSE(Lower) << "SUBG#" << op_seq_index.value() << " 's NODE#" << n_index.value() << "(" + << n.name() << ") is connected to NODE#" << node_index.value() << "(" + << node.name() << ")" << std::endl; + return true; + } + } + + // node's input == op_seq's output? + const auto &n_outputs = n.getOutputs(); + for (auto output : n_outputs) + { + if (node_inputs.contains(output)) + { + VERBOSE(Lower) << "SUBG#" << op_seq_index.value() << " 's NODE#" << n_index.value() + << " (" << n.name() << ") is connected to NODE#" << node_index.value() + << std::endl; + return true; + } + } + } + + VERBOSE(Lower) << "SUBG#" << op_seq_index.value() << " is not connected to NODE#" + << node_index.value() << "(" << node.name() << ")" << std::endl; + } + + return false; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/OpCode.cc b/runtime/onert/core/src/ir/OpCode.cc new file mode 100644 index 000000000..3f8182916 --- /dev/null +++ b/runtime/onert/core/src/ir/OpCode.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/OpCode.h" + +#include + +namespace onert +{ +namespace ir +{ + +const char *toString(OpCode opcode) +{ + static const std::unordered_map map{{OpCode::Invalid, "Invalid"}, +#define OP(Name) {OpCode::Name, #Name}, +#include "ir/Operations.lst" +#undef OP + {OpCode::COUNT, "COUNT"}}; + return map.at(opcode); +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/OpSequence.cc b/runtime/onert/core/src/ir/OpSequence.cc new file mode 100644 index 000000000..74c7854e5 --- /dev/null +++ b/runtime/onert/core/src/ir/OpSequence.cc @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/OpSequence.h" +#include "ir/OperationVisitor.h" +#include + +namespace +{ + +std::string getStrFromIndice(const onert::ir::OperandIndexSequence &indice) +{ + std::string str; + for (const auto &ind : indice) + { + str += std::to_string(ind.value()); + str.push_back(','); + } + if (str.back() == ',') + str.pop_back(); + + return str; +} +} + +namespace onert +{ +namespace ir +{ + +OpSequence::OpSequence(Layout layout) : _layout{layout} +{ + // DO NOTHING +} + +void OpSequence::accept(OperationVisitor &v) const { v.visit(*this); } + +// TODO: Impl Dumper instead of this method +std::string OpSequence::getStr() const +{ + // " OpSequence IN(0,1,2) -> { op0(0,1,2:3), op1(3:4), op2(4:5) } -> OUT(5)" + std::stringstream ss; + ss << " OpSequence IN(" << getStrFromIndice(getInputs()) << ") -> {"; + for (const auto &elem : _operations) + { + ss << " " << elem.index.value() << "(" << elem.node->name() << ":" + << getStrFromIndice(elem.node->getInputs()) << ":" + << getStrFromIndice(elem.node->getOutputs()) << ")"; + } + ss << " } -> OUT(" << getStrFromIndice(getOutputs()) << ")"; + return ss.str(); +} + +void OpSequence::remove(const OperationIndex &index) +{ + assert(exist(index)); + for (auto it = _operations.cbegin(); it != _operations.cend(); ++it) + { + if (it->index == index) + { + _operations.erase(it); + break; + } + } +} + +bool OpSequence::exist(const OperationIndex &index) const +{ + for (const auto &element : _operations) + { + if (element.index == index) + { + return true; + } + } + return false; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/OpSequences.cc b/runtime/onert/core/src/ir/OpSequences.cc new file mode 100644 index 000000000..991e96c9d --- /dev/null +++ b/runtime/onert/core/src/ir/OpSequences.cc @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/OpSequences.h" +#include "util/logging.h" +#include + +#include +#include + +namespace onert +{ +namespace ir +{ + +OpSequenceIndex OpSequences::emplace(const OperationIndex &index, const Operation &node, + Layout layout) +{ + std::unique_ptr op_seq = std::make_unique(layout); + op_seq->appendOperation(index, node); + return push(std::move(op_seq)); +} + +OpSequenceIndex OpSequences::emplace(std::unique_ptr &&op_seq) +{ + return push(std::move(op_seq)); +} + +bool OpSequences::containsOperation(const OperationIndex &operation_index) const +{ + return findOperation(operation_index).valid(); +} + +OpSequenceIndex OpSequences::getOperation(const OperationIndex &operation_index) const +{ + OpSequenceIndex ret = findOperation(operation_index); + assert(ret.valid()); + return ret; +} + +// TODO: Extract this into external helper function +void OpSequences::dump(const std::string &msg) const +{ + VERBOSE(OpSequences) << "OpSequences(" << msg << ")" << std::endl; + iterate([&](const OpSequenceIndex &idx, const OpSequence &op_seq) { + VERBOSE(OpSequences) << idx.value() << "] " << op_seq.getStr() << std::endl; + }); +} + +void OpSequences::removeFromOpSequence(const OperationIndex &operation_index) +{ + const auto op_seq_index = findOperation(operation_index); + auto &op_seq = at(op_seq_index); + op_seq.remove(operation_index); + if (op_seq.size() == 0) + { + remove(op_seq_index); + } +} + +OpSequenceIndex OpSequences::findOperation(const OperationIndex &operation_index) const +{ + OpSequenceIndex ret; + iterate([&](const OpSequenceIndex &index, const OpSequence &object) { + for (const auto &elem : object.operations()) + { + if (elem.index == operation_index) + ret = index; + } + }); + return ret; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/Operand.cc b/runtime/onert/core/src/ir/Operand.cc new file mode 100644 index 000000000..39f9d6c90 --- /dev/null +++ b/runtime/onert/core/src/ir/Operand.cc @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Operand.h" + +namespace onert +{ +namespace ir +{ + +size_t Operand::operandSize(void) const +{ + const uint32_t ranks = shape().rank(); + int32_t elements = 1; + + for (uint32_t rank = 0; rank < ranks; rank++) + { + elements *= shape().dim(rank); + } + + DataType type = typeInfo().type(); + size_t element_size = sizeOfDataType(type); + + // Value of type is matched with OperandCode enum in NeuralNetworks.h + return element_size * elements; +} + +void Operand::appendUse(const OperationIndex &idx) { _uses.append(idx); } + +void Operand::removeUse(const OperationIndex &idx) { _uses.remove(idx); } + +void Operand::appendDef(const OperationIndex &idx) +{ + assert(!isConstant()); + assert(_def.size() == 0); + + _def.append(idx); +} + +void Operand::removeDef(const OperationIndex &idx) +{ + assert(_def.contains(idx)); + + _def.remove(idx); +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/OperandIndexSequence.cc b/runtime/onert/core/src/ir/OperandIndexSequence.cc new file mode 100644 index 000000000..2044310e7 --- /dev/null +++ b/runtime/onert/core/src/ir/OperandIndexSequence.cc @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/OperandIndexSequence.h" + +#include + +namespace onert +{ +namespace ir +{ + +OperandIndexSequence::OperandIndexSequence(std::initializer_list list) : _set(list) +{ + // DO NOTHING +} + +OperandIndexSequence::OperandIndexSequence(std::initializer_list list) +{ + for (auto val : list) + { + _set.emplace_back(static_cast(val)); + } +} + +OperandIndexSequence::OperandIndexSequence(std::initializer_list list) +{ + for (auto val : list) + { + _set.emplace_back(val); + } +} + +bool OperandIndexSequence::contains(const OperandIndex &index) const +{ + return std::find(_set.begin(), _set.end(), index) != _set.end(); +} + +void OperandIndexSequence::replace(const OperandIndex &from, const OperandIndex &to) +{ + std::replace(_set.begin(), _set.end(), from, to); +} + +OperandIndexSequence OperandIndexSequence::operator+(const OperandIndexSequence &other) const +{ + OperandIndexSequence ret = *this; + ret.append(other); + return ret; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/Operands.cc b/runtime/onert/core/src/ir/Operands.cc new file mode 100644 index 000000000..ab32e478a --- /dev/null +++ b/runtime/onert/core/src/ir/Operands.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Operands.h" + +#include +#include "util/logging.h" + +namespace onert +{ +namespace ir +{ + +Operands::Operands(const Operands &obj) +{ + obj.iterate([&](const OperandIndex &index, const Operand &operand) { + _objects.emplace(index, std::make_unique(operand)); + }); + _index_count = obj._index_count; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/Operation.cc b/runtime/onert/core/src/ir/Operation.cc new file mode 100644 index 000000000..d2a60747f --- /dev/null +++ b/runtime/onert/core/src/ir/Operation.cc @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Operation.h" + +#include + +namespace onert +{ +namespace ir +{ + +Operation::Operation(OperandConstraint input_constr, const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs) + : _input_constr{input_constr}, _inputs{inputs}, _outputs{outputs} +{ +} + +Operation::Operation(OperandConstraint input_constr) : _input_constr{input_constr} {} + +Operation::~Operation() = default; + +void Operation::setInputs(const OperandIndexSequence &indexes) +{ + assert(_input_constr.check(indexes.size())); + _inputs = indexes; +} + +void Operation::setOutputs(const OperandIndexSequence &indexes) { _outputs = indexes; } + +void Operation::replaceInput(const OperandIndex &from, const OperandIndex &to) +{ + _inputs.replace(from, to); +} + +void Operation::replaceOutput(const OperandIndex &from, const OperandIndex &to) +{ + _outputs.replace(from, to); +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/OperationCloner.cc b/runtime/onert/core/src/ir/OperationCloner.cc new file mode 100644 index 000000000..b4e60f0bc --- /dev/null +++ b/runtime/onert/core/src/ir/OperationCloner.cc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperationCloner.h" + +#include + +namespace onert +{ +namespace ir +{ + +#define OP(Name) \ + void OperationCloner::visit(const operation::Name &o) \ + { \ + assert(!_return_op); \ + _return_op = std::make_unique(o); \ + } +#include "ir/Operations.lst" +#undef OP + +std::unique_ptr OperationCloner::releaseClone() +{ + assert(_return_op); + return std::move(_return_op); +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/OperationCloner.h b/runtime/onert/core/src/ir/OperationCloner.h new file mode 100644 index 000000000..0e8cda2a0 --- /dev/null +++ b/runtime/onert/core/src/ir/OperationCloner.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_OPERATION_CLONER_H__ +#define __ONERT_IR_OPERATION_CLONER_H__ + +#include +#include "ir/OperationVisitor.h" +#include "ir/Operation.h" + +namespace onert +{ +namespace ir +{ + +class OperationCloner : public OperationVisitor +{ +public: +#define OP(Name) void visit(const operation::Name &o) override; +#include "ir/Operations.lst" +#undef OP + +public: + std::unique_ptr releaseClone(); + +private: + std::unique_ptr _return_op; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_OPERATION_CLONER_H__ diff --git a/runtime/onert/core/src/ir/OperationDumper.cc b/runtime/onert/core/src/ir/OperationDumper.cc new file mode 100644 index 000000000..789d2869d --- /dev/null +++ b/runtime/onert/core/src/ir/OperationDumper.cc @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperationDumper.h" + +#include + +#include "util/logging.h" + +namespace onert +{ +namespace ir +{ + +using namespace operation; + +void OperationDumper::visit(const Abs &node) +{ + VERBOSE(LIR) << "* Abs" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Abs::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Add &node) +{ + VERBOSE(LIR) << "* Add" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Add::Input::LHS).value() << ", " + << node.getInputs().at(Add::Input::RHS).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const ArgMax &node) +{ + VERBOSE(LIR) << "* ArgMax" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ArgMax::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const AvgPool2D &node) +{ + VERBOSE(LIR) << "* AvgPool2D(Implicit)" << std::endl; + VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(AvgPool2D::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Cast &node) +{ + VERBOSE(LIR) << "* Cast" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Cast::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Comparison &node) +{ + VERBOSE(LIR) << "* Comparison" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Comparison::Input::INPUT0).value() + << ", " << node.getInputs().at(Comparison::Input::INPUT1).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Concat &node) +{ + VERBOSE(LIR) << "* Concat" << std::endl; + std::string inputs; + for (auto i : node.getInputs()) + { + inputs += std::to_string(i.value()) + ","; + } + VERBOSE(LIR) << " - Inputs : IFM(" << inputs << ")" << std::endl; + VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Conv2D &node) +{ + std::string padding_type = + node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit"; + VERBOSE(LIR) << "* Conv2D(" << padding_type << ")" << std::endl; + VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(Conv2D::Input::INPUT).value() + << ") Kernel(" << node.getInputs().at(Conv2D::Input::KERNEL).value() << ") Bias(" + << node.getInputs().at(Conv2D::Input::BIAS).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const DepthToSpace &node) +{ + VERBOSE(LIR) << "* DepthToSpace" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(DepthToSpace::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const DepthwiseConv2D &node) +{ + std::string padding_type = + node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit"; + VERBOSE(LIR) << "* DepthwiseConv2D(" << padding_type << ")" << std::endl; + VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(DepthwiseConv2D::Input::INPUT).value() + << ") Kernel(" << node.getInputs().at(DepthwiseConv2D::Input::KERNEL).value() + << ") Bias(" << node.getInputs().at(DepthwiseConv2D::Input::BIAS).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Dequantize &node) +{ + VERBOSE(LIR) << "* Dequantize" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Dequantize::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Div &node) +{ + VERBOSE(LIR) << "* Div" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Div::Input::LHS).value() << ", " + << node.getInputs().at(Div::Input::RHS).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const EmbeddingLookup &node) +{ + VERBOSE(LIR) << "* EmbeddingLookup" << std::endl; + VERBOSE(LIR) << " - Inputs : Lookups(" + << node.getInputs().at(EmbeddingLookup::Input::LOOKUPS).value() << ") VALUES(" + << node.getInputs().at(EmbeddingLookup::Input::VALUES).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Exp &node) +{ + VERBOSE(LIR) << "* Exp" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Exp::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Floor &node) +{ + VERBOSE(LIR) << "* Floor" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Floor::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const FullyConnected &node) +{ + VERBOSE(LIR) << "* FullyConnected" << std::endl; + VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(FullyConnected::Input::INPUT).value() + << ") Weight(" << node.getInputs().at(FullyConnected::Input::WEIGHT).value() + << ") Bias(" << node.getInputs().at(FullyConnected::Input::BIAS).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Gather &node) +{ + VERBOSE(LIR) << "* Gather" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Gather::Input::INPUT).value() + << ") Indices(" << node.getInputs().at(Gather::Input::INDICES).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const HashtableLookup &node) +{ + VERBOSE(LIR) << "* HashTableLookup" << std::endl; + VERBOSE(LIR) << " - Inputs : Lookups(" + << node.getInputs().at(HashtableLookup::Input::LOOKUPS).value() << ") Keys(" + << node.getInputs().at(HashtableLookup::Input::KEYS).value() << ") Values(" + << node.getInputs().at(HashtableLookup::Input::VALUES).value() << ")" << std::endl; + VERBOSE(LIR) << " - Outputs : Output(" + << node.getInputs().at(HashtableLookup::Output::OUTPUT).value() << ") Hits(" + << node.getInputs().at(HashtableLookup::Output::HITS).value() << ")" << std::endl; +} + +void OperationDumper::visit(const InstanceNorm &node) +{ + VERBOSE(LIR) << "* InstanceNorm" << std::endl; + VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(InstanceNorm::Input::INPUT).value() + << ") Gamma(" << node.getInputs().at(InstanceNorm::Input::GAMMA).value() << ") Beta(" + << node.getInputs().at(InstanceNorm::Input::BETA).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const L2Normalization &node) +{ + VERBOSE(LIR) << "* L2Normalization" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" + << node.getInputs().at(L2Normalization::Input::INPUT).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const L2Pool2D &node) +{ + VERBOSE(LIR) << "* L2Pool2D" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(L2Pool2D::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const LocalResponseNormalization &node) +{ + VERBOSE(LIR) << "* LocalResponseNormalization" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" + << node.getInputs().at(LocalResponseNormalization::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const LSTM &node) +{ + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(LSTM::Input::INPUT).value() + << ") Input To Input Weights(" + << node.getInputs().at(LSTM::Input::INPUT_TO_INPUT_WEIGHTS).value() + << ") Input To Forget Weights(" + << node.getInputs().at(LSTM::Input::INPUT_TO_FORGET_WEIGHTS).value() + << ") Input To Cell Weights(" + << node.getInputs().at(LSTM::Input::INPUT_TO_CELL_WEIGHTS).value() + << ") Input To Output Weights(" + << node.getInputs().at(LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS).value() + << ") Recurrent To Input Weights(" + << node.getInputs().at(LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS).value() + << ") Recurrent To Forget Weights(" + << node.getInputs().at(LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS).value() + << ") Recurrent To Cell Weights(" + << node.getInputs().at(LSTM::Input::RECURRENT_TO_CELL_WEIGHTS).value() + << ") Recurrent To Output Weights(" + << node.getInputs().at(LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS).value() + << ") Cell To Input Weights(" + << node.getInputs().at(LSTM::Input::CELL_TO_INPUT_WEIGHTS).value() + << ") Cell To Forget Weights(" + << node.getInputs().at(LSTM::Input::CELL_TO_FORGET_WEIGHTS).value() + << ") Cell To OUTPUT Weights(" + << node.getInputs().at(LSTM::Input::CELL_TO_OUTPUT_WEIGHTS).value() + << ") Input Gate Bias(" << node.getInputs().at(LSTM::Input::INPUT_GATE_BIAS).value() + << ") Forget Gate Bias(" + << node.getInputs().at(LSTM::Input::FORGET_GATE_BIAS).value() << ") Cell Bias(" + << node.getInputs().at(LSTM::Input::CELL_BIAS).value() << ") Output Gate Bias(" + << node.getInputs().at(LSTM::Input::OUTPUT_GATE_BIAS).value() + << ") Projection Weights(" + << node.getInputs().at(LSTM::Input::PROJECTION_WEIGHTS).value() + << ") Projection Bias(" << node.getInputs().at(LSTM::Input::PROJECTION_BIAS).value() + << ") Output State In(" << node.getInputs().at(LSTM::Input::OUTPUT_STATE_IN).value() + << ") Cell State In(" << node.getInputs().at(LSTM::Input::CELL_STATE_IN).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Scratch Buffer(" + << node.getOutputs().at(LSTM::Output::SCRATCH_BUFFER).value() + << ") Output State Out(" + << node.getInputs().at(LSTM::Output::OUTPUT_STATE_OUT).value() << ") Cell State Out(" + << node.getInputs().at(LSTM::Output::CELL_STATE_OUT).value() << ") Output(" + << node.getInputs().at(LSTM::Output::OUTPUT).value() << ")" << std::endl; +} + +void OperationDumper::visit(const LogicalAnd &node) +{ + VERBOSE(LIR) << "* LogicalAnd" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(LogicalAnd::Input::INPUT0).value() + << ", " << node.getInputs().at(LogicalAnd::Input::INPUT1).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const LogicalNot &node) +{ + VERBOSE(LIR) << "* LogicalNot" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(LogicalNot::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const LogicalOr &node) +{ + VERBOSE(LIR) << "* LogicalOr" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(LogicalOr::Input::INPUT0).value() + << ", " << node.getInputs().at(LogicalOr::Input::INPUT1).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Logistic &node) +{ + VERBOSE(LIR) << "* Logistic" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Logistic::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const MaxPool2D &node) +{ + std::string padding_type = + node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit"; + VERBOSE(LIR) << "* MaxPool2D(" << padding_type << ")" << std::endl; + VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(MaxPool2D::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Mean &node) +{ + VERBOSE(LIR) << "* Mean" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Mean::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Mul &node) +{ + VERBOSE(LIR) << "* Mul" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Mul::Input::LHS).value() << ", " + << node.getInputs().at(Mul::Input::RHS).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Neg &node) +{ + VERBOSE(LIR) << "* Neg" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Neg::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Pack &node) +{ + VERBOSE(LIR) << "* Pack" << std::endl; + std::string inputs; + const auto &input_indices = node.getInputs(); + for (auto it = std::begin(input_indices); it != std::end(input_indices); ++it) + { + inputs += std::to_string(it->value()); + if (std::next(it) != std::end(input_indices)) + inputs += ", "; + } + VERBOSE(LIR) << " - Inputs : Inputs(" << inputs << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Permute &node) +{ + std::string permute_type = "Unknown"; + switch (node.getPermuteType()) + { + case Permute::Type::COPY: + permute_type = "Copy"; + break; + case Permute::Type::NHWC_TO_NCHW: + permute_type = "NHWC to NCHW"; + break; + case Permute::Type::NCHW_TO_NHWC: + permute_type = "NCHW to NHWC"; + break; + } + + VERBOSE(LIR) << "* Permute(" + permute_type + ")" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(0).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const PReLU &node) +{ + VERBOSE(LIR) << "* PReLU" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(PReLU::Input::INPUT).value() + << ") Alpha(" << node.getInputs().at(PReLU::Input::ALPHA).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const ReduceMax &node) +{ + VERBOSE(LIR) << "* ReduceMax" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReduceMax::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const ReduceMin &node) +{ + VERBOSE(LIR) << "* ReduceMin" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReduceMin::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const ReduceSum &node) +{ + VERBOSE(LIR) << "* ReduceSum" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReduceSum::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const ReLU &node) +{ + VERBOSE(LIR) << "* ReLU" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReLU::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const ReLU1 &node) +{ + VERBOSE(LIR) << "* ReLU1" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReLU1::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const ReLU6 &node) +{ + VERBOSE(LIR) << "* ReLU6" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ReLU6::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Reshape &node) +{ + VERBOSE(LIR) << "* Reshape" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Reshape::Input::INPUT).value() + << ")"; + // optional param + if (node.getInputs().size() == 2) + { + VERBOSE(LIR) << " Shape(" << node.getInputs().at(Reshape::Input::SHAPE).value() << ")"; + } + else + { + VERBOSE(LIR) << " Shape(not provided)"; + } + VERBOSE(LIR) << std::endl; + + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const ResizeBilinear &node) +{ + VERBOSE(LIR) << "* ResizeBilinear" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(ResizeBilinear::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const RNN &node) +{ + VERBOSE(LIR) << "* RNN" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(RNN::Input::INPUT).value() + << ") Weights" << node.getInputs().at(RNN::Input::WEIGHTS).value() + << ") Recurrent Weights" + << node.getInputs().at(RNN::Input::RECURRENT_WEIGHTS).value() << ") Bias" + << node.getInputs().at(RNN::Input::BIAS).value() << ") Hidden State" + << node.getInputs().at(RNN::Input::HIDDEN_STATE_IN).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(RNN::Output::OUTPUT).value() + << ") Hidden State" << node.getInputs().at(RNN::Output::HIDDEN_STATE_OUT).value() + << ")" << std::endl; +} + +void OperationDumper::visit(const RSQRT &node) +{ + VERBOSE(LIR) << "* RSQRT" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(RSQRT::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Softmax &node) +{ + VERBOSE(LIR) << "* Softmax" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Softmax::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const SpaceToDepth &node) +{ + VERBOSE(LIR) << "* SpaceToDepth" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(SpaceToDepth::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Split &node) +{ + VERBOSE(LIR) << "* Split" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Split::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const SQRT &node) +{ + VERBOSE(LIR) << "* SQRT" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(SQRT::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const SquaredDifference &node) +{ + VERBOSE(LIR) << "* SquaredDifference" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" + << node.getInputs().at(SquaredDifference::Input::LHS).value() << ", " + << node.getInputs().at(SquaredDifference::Input::RHS).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Squeeze &node) +{ + VERBOSE(LIR) << "* Squeeze" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Squeeze::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Slice &node) +{ + VERBOSE(LIR) << "* Slice" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Slice::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const StridedSlice &node) +{ + VERBOSE(LIR) << "* StridedSlice" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(StridedSlice::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Sub &node) +{ + VERBOSE(LIR) << "* Sub" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Sub::Input::LHS).value() << ", " + << node.getInputs().at(Sub::Input::RHS).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Tanh &node) +{ + VERBOSE(LIR) << "* TanH" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Tanh::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const TopKV2 &node) +{ + VERBOSE(LIR) << "* TopKV2" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(TopKV2::Input::INPUT).value() << ")" + << std::endl; + VERBOSE(LIR) << " - Outputs : Values(" + << node.getOutputs().at(TopKV2::Output::OUTPUT_VALUES).value() << ") Indices(" + << node.getOutputs().at(TopKV2::Output::OUTPUT_INDICES).value() << ")" << std::endl; +} + +void OperationDumper::visit(const TransposeConv &node) +{ + std::string padding_type = + node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit"; + VERBOSE(LIR) << "* TransposeConv(" << padding_type << ")" << std::endl; + VERBOSE(LIR) << " - Inputs : Output Shape(" + << node.getInputs().at(TransposeConv::Input::OUTPUT_SHAPE).value() << ") KERNEL(" + << node.getInputs().at(TransposeConv::Input::KERNEL).value() << ") IFM(" + << node.getInputs().at(TransposeConv::Input::INPUT).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Transpose &node) +{ + VERBOSE(LIR) << "* Transpose" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Transpose::Input::INPUT).value() + << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Unpack &node) +{ + VERBOSE(LIR) << "* Unpack" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Unpack::Input::INPUT).value() << ")" + << std::endl; + std::string outputs; + const auto &output_indices = node.getOutputs(); + for (auto it = std::begin(output_indices); it != std::end(output_indices); ++it) + { + outputs += std::to_string(it->value()); + if (std::next(it) != std::end(output_indices)) + outputs += ", "; + } + VERBOSE(LIR) << " - Outputs : Outputs(" << outputs << ")" << std::endl; +} + +void OperationDumper::visit(const Min &node) +{ + VERBOSE(LIR) << "* Min" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Min::Input::LHS).value() << ", " + << node.getInputs().at(Min::Input::RHS).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const Max &node) +{ + VERBOSE(LIR) << "* Max" << std::endl; + VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(Max::Input::LHS).value() << ", " + << node.getInputs().at(Max::Input::RHS).value() << ")" << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +void OperationDumper::visit(const OneHot &node) +{ + VERBOSE(LIR) << "* OneHot" << std::endl; + VERBOSE(LIR) << " - Inputs : " + << "Indices(" << node.getInputs().at(OneHot::Input::INDICES).value() << ") " + << std::endl; + VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/OperationDumper.h b/runtime/onert/core/src/ir/OperationDumper.h new file mode 100644 index 000000000..77d100cee --- /dev/null +++ b/runtime/onert/core/src/ir/OperationDumper.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_OPERATION_DUMPER_H__ +#define __ONERT_OPERATION_DUMPER_H__ + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ + +class OperationDumper : public OperationVisitor +{ +public: + OperationDumper() = default; + +public: + void visit(const operation::Abs &) override; + void visit(const operation::Add &node) override; + void visit(const operation::ArgMax &) override; + void visit(const operation::AvgPool2D &node) override; + void visit(const operation::Cast &) override; + void visit(const operation::Comparison &) override; + void visit(const operation::Concat &node) override; + void visit(const operation::Conv2D &node) override; + void visit(const operation::DepthToSpace &) override; + void visit(const operation::DepthwiseConv2D &node) override; + void visit(const operation::Dequantize &) override; + void visit(const operation::Div &) override; + void visit(const operation::EmbeddingLookup &) override; + void visit(const operation::Exp &) override; + void visit(const operation::Floor &) override; + void visit(const operation::FullyConnected &node) override; + void visit(const operation::Gather &) override; + void visit(const operation::HashtableLookup &) override; + void visit(const operation::InstanceNorm &) override; + void visit(const operation::L2Normalization &) override; + void visit(const operation::L2Pool2D &) override; + void visit(const operation::LocalResponseNormalization &) override; + void visit(const operation::LogicalAnd &) override; + void visit(const operation::LogicalNot &) override; + void visit(const operation::LogicalOr &) override; + void visit(const operation::Logistic &) override; + void visit(const operation::LSTM &) override; + void visit(const operation::MaxPool2D &node) override; + void visit(const operation::Mean &) override; + void visit(const operation::Mul &) override; + void visit(const operation::Neg &) override; + void visit(const operation::Pack &) override; + void visit(const operation::Permute &node) override; + void visit(const operation::PReLU &) override; + void visit(const operation::ReduceMax &) override; + void visit(const operation::ReduceMin &) override; + void visit(const operation::ReduceSum &) override; + void visit(const operation::ReLU &) override; + void visit(const operation::ReLU1 &) override; + void visit(const operation::ReLU6 &) override; + void visit(const operation::Reshape &node) override; + void visit(const operation::ResizeBilinear &) override; + void visit(const operation::RNN &) override; + void visit(const operation::RSQRT &) override; + void visit(const operation::Softmax &node) override; + void visit(const operation::SpaceToDepth &) override; + void visit(const operation::Split &) override; + void visit(const operation::SQRT &) override; + void visit(const operation::SquaredDifference &) override; + void visit(const operation::Squeeze &) override; + void visit(const operation::Slice &) override; + void visit(const operation::StridedSlice &) override; + void visit(const operation::Sub &) override; + void visit(const operation::Tanh &) override; + void visit(const operation::TopKV2 &) override; + void visit(const operation::TransposeConv &) override; + void visit(const operation::Transpose &) override; + void visit(const operation::Unpack &) override; + void visit(const operation::Min &) override; + void visit(const operation::Max &) override; + void visit(const operation::OneHot &) override; +}; + +} // namespace ir +} // namespace onert + +#endif // __ONERT_OPERATION_DUMPER_H__ diff --git a/runtime/onert/core/src/ir/OperationIndexList.cc b/runtime/onert/core/src/ir/OperationIndexList.cc new file mode 100644 index 000000000..bf51f9abb --- /dev/null +++ b/runtime/onert/core/src/ir/OperationIndexList.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/OperationIndexList.h" + +#include + +namespace onert +{ +namespace ir +{ + +OperationIndexList::OperationIndexList(std::initializer_list list) : _list(list) +{ + // DO NOTHING +} + +bool OperationIndexList::contains(const OperationIndex &index) const +{ + return std::find(_list.begin(), _list.end(), index) != _list.end(); +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/Operations.cc b/runtime/onert/core/src/ir/Operations.cc new file mode 100644 index 000000000..64d0bd6f0 --- /dev/null +++ b/runtime/onert/core/src/ir/Operations.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Operations.h" + +#include "OperationCloner.h" + +namespace onert +{ +namespace ir +{ + +Operations::Operations(const Operations &obj) +{ + obj.iterate([&](const OperationIndex &index, const Operation &op) { + OperationCloner cloner; + op.accept(cloner); + _objects.emplace(index, cloner.releaseClone()); + }); + _index_count = obj._index_count; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/Padding.cc b/runtime/onert/core/src/ir/Padding.cc new file mode 100644 index 000000000..31969911f --- /dev/null +++ b/runtime/onert/core/src/ir/Padding.cc @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Padding.h" + +#include "util/Utils.h" + +#include +#include + +namespace onert +{ +namespace ir +{ +namespace +{ + +inline ExplicitPadding validPadding(void) +{ + // + // ANEURALNETWORKS_PADDING_VALID + // + // VALID padding. No padding. + // + // When the input size is not evenly divisible by the filter size, + // the input at the end that could not fill the whole filter tile + // will simply be ignored. + // + ExplicitPadding padding; + + padding.top = 0; + padding.bottom = 0; + padding.left = 0; + padding.right = 0; + + return padding; +} + +inline ExplicitPadding samePaddingUsingIFM(const FeatureShape &ifm_shape, const Stride &stride, + uint32_t kw, uint32_t kh) +{ + ExplicitPadding padding; + + // ANEURALNETWORKS_PADDING_SAME (from NNAPI spec) + // + // SAME padding. Padding on both ends are the "same": + // + // padding_to_beginning = total_padding / 2 + // padding_to_end = (total_padding + 1)/2. + // + const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical; + const int32_t horizontal_expected_output = + (ifm_shape.W + stride.horizontal - 1) / stride.horizontal; + + const int32_t vertical_needed_input = (vertical_expected_output - 1) * stride.vertical + kh; + const int32_t vertical_total_padding = std::max(0, vertical_needed_input - ifm_shape.H); + + const int32_t horizontal_needed_input = (horizontal_expected_output - 1) * stride.horizontal + kw; + const int32_t horizontal_total_padding = std::max(0, horizontal_needed_input - ifm_shape.W); + + padding.top = vertical_total_padding / 2; + padding.bottom = (vertical_total_padding + 1) / 2; + padding.left = horizontal_total_padding / 2; + padding.right = (horizontal_total_padding + 1) / 2; + + return padding; +} + +inline ExplicitPadding samePadding(const FeatureShape &ifm_shape, const FeatureShape &ofm_shape, + const Stride &stride, uint32_t kw, uint32_t kh) +{ + const int32_t vertical_expected_output = (ifm_shape.H + stride.vertical - 1) / stride.vertical; + const int32_t horizontal_expected_output = + (ifm_shape.W + stride.horizontal - 1) / stride.horizontal; + assert(vertical_expected_output == ofm_shape.H); + assert(horizontal_expected_output == ofm_shape.W); + + UNUSED_RELEASE(ofm_shape); + UNUSED_RELEASE(vertical_expected_output); + UNUSED_RELEASE(horizontal_expected_output); + + return samePaddingUsingIFM(ifm_shape, stride, kw, kh); +} + +} // namespace + +inline std::string to_string(const PaddingType type) +{ + switch (type) + { + case PaddingType::EXPLICIT: + return "Padding::EXPLICIT"; + case PaddingType::SAME: + return "Padding::SAME"; + case PaddingType::VALID: + return "Padding::VALID"; + default: + throw std::runtime_error{"Fail to convert string: wrong padding type"}; + } +} + +Padding::Padding(void) : type{PaddingType::EXPLICIT}, param{0, 0, 0, 0} +{ + // DO NOTHING +} + +Padding::Padding(PaddingType paddingType) : type{paddingType}, param{0, 0, 0, 0} +{ + assert(paddingType != PaddingType::EXPLICIT); +} + +Padding::Padding(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) + : type{PaddingType::EXPLICIT}, param{left, right, top, bottom} +{ + // DO NOTHING +} + +const ExplicitPadding calculatePadding(const Padding &padding, const FeatureShape &ifm_shape, + const FeatureShape &ofm_shape, const Stride &stride, + uint32_t kw, uint32_t kh) +{ + if (padding.type == PaddingType::EXPLICIT) + { + return padding.param; + } + else if (padding.type == PaddingType::SAME) + { + return samePadding(ifm_shape, ofm_shape, stride, kw, kh); + } + else if (padding.type == PaddingType::VALID) + { + return validPadding(); + } + else + { + throw std::runtime_error{"Cannot handle padding type"}; + } +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/Shape.cc b/runtime/onert/core/src/ir/Shape.cc new file mode 100644 index 000000000..92999a4fa --- /dev/null +++ b/runtime/onert/core/src/ir/Shape.cc @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/Shape.h" + +#include +#include +#include +#include + +namespace onert +{ +namespace ir +{ + +FeatureShape Shape::asFeature(Layout layout) const +{ + assert(rank() == 4); + + if (layout == Layout::NHWC) + { + // Feature Map in NHWC layout + // - Dimension(0) -> Batch + // - Dimension(1) -> Height + // - Dimension(2) -> Width + // - Dimension(3) -> Depth + const auto batch = dim(0); + const auto depth = dim(3); + const auto height = dim(1); + const auto width = dim(2); + + return {batch, depth, height, width}; + } + else if (layout == Layout::NCHW) + { + // Feature Map in NHWC layout + // - Dimension(0) -> Batch + // - Dimension(1) -> Depth + // - Dimension(2) -> Height + // - Dimension(3) -> Width + const auto batch = dim(0); + const auto depth = dim(1); + const auto height = dim(2); + const auto width = dim(3); + + return {batch, depth, height, width}; + } + else + { + throw std::runtime_error("Wrong Layout"); + } +} + +// Extended dimension is filled with 1. +void Shape::extendRank(int to_rank) +{ + assert(to_rank - rank() >= 0); + _dimensions.insert(_dimensions.cbegin(), to_rank - rank(), 1); +} + +uint64_t Shape::num_elements() const +{ + // All of the nodes must have non-negative dimension + assert(std::all_of(_dimensions.begin(), _dimensions.end(), + [](const int32_t &v) { return (v >= 0); })); + + return std::accumulate(_dimensions.cbegin(), _dimensions.cend(), UINT64_C(1), + std::multiplies()); +} + +Shape permuteShape(const Shape &shape, Layout frontend_layout, Layout backend_layout) +{ + assert(shape.rank() <= 4); + Shape backend_shape{shape}; + if (shape.rank() == 4 && frontend_layout == Layout::NHWC && backend_layout == Layout::NCHW) + { + backend_shape.dim(1) = shape.dim(3); + backend_shape.dim(2) = shape.dim(1); + backend_shape.dim(3) = shape.dim(2); + } + else if (shape.rank() == 4 && frontend_layout == Layout::NCHW && backend_layout == Layout::NHWC) + { + backend_shape.dim(1) = shape.dim(2); + backend_shape.dim(2) = shape.dim(3); + backend_shape.dim(3) = shape.dim(1); + } + return backend_shape; +} + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/TypeInfo.cc b/runtime/onert/core/src/ir/TypeInfo.cc new file mode 100644 index 000000000..ab8af287e --- /dev/null +++ b/runtime/onert/core/src/ir/TypeInfo.cc @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/TypeInfo.h" + +namespace onert +{ +namespace ir +{ + +bool operator==(const TypeInfo &lhs, const TypeInfo &rhs) +{ + if (lhs.type() != rhs.type()) + { + return false; + } + + if (lhs.offset() != rhs.offset()) + { + return false; + } + + if (lhs.scale() != rhs.scale()) + { + return false; + } + + return true; +} + +bool operator!=(const TypeInfo &lhs, const TypeInfo &rhs) { return !(lhs == rhs); } + +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Abs.cc b/runtime/onert/core/src/ir/operation/Abs.cc new file mode 100644 index 000000000..b06705d07 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Abs.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Abs.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Abs::accept(OperationVisitor &v) const { v.visit(*this); } + +Abs::Abs(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Add.cc b/runtime/onert/core/src/ir/operation/Add.cc new file mode 100644 index 000000000..2fa30f8ed --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Add.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Add.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Add::accept(OperationVisitor &v) const { v.visit(*this); } + +Add::Add(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ArgMax.cc b/runtime/onert/core/src/ir/operation/ArgMax.cc new file mode 100644 index 000000000..1275ae43a --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ArgMax.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ArgMax.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ArgMax::accept(OperationVisitor &v) const { v.visit(*this); } + +ArgMax::ArgMax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/AvgPool2D.cc b/runtime/onert/core/src/ir/operation/AvgPool2D.cc new file mode 100644 index 000000000..28d4fcb54 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/AvgPool2D.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/AvgPool2D.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void AvgPool2D::accept(OperationVisitor &v) const { v.visit(*this); } + +AvgPool2D::AvgPool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/BatchToSpaceND.cc b/runtime/onert/core/src/ir/operation/BatchToSpaceND.cc new file mode 100644 index 000000000..0b3955c5c --- /dev/null +++ b/runtime/onert/core/src/ir/operation/BatchToSpaceND.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/BatchToSpaceND.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void BatchToSpaceND::accept(OperationVisitor &v) const { v.visit(*this); } + +BatchToSpaceND::BatchToSpaceND(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(2u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Cast.cc b/runtime/onert/core/src/ir/operation/Cast.cc new file mode 100644 index 000000000..09d9c327e --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Cast.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Cast.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Cast::accept(OperationVisitor &v) const { v.visit(*this); } + +Cast::Cast(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Comparison.cc b/runtime/onert/core/src/ir/operation/Comparison.cc new file mode 100644 index 000000000..2f6775411 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Comparison.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Comparison.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Comparison::accept(OperationVisitor &v) const { v.visit(*this); } + +Comparison::Comparison(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Concat.cc b/runtime/onert/core/src/ir/operation/Concat.cc new file mode 100644 index 000000000..608bc29a6 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Concat.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Concat.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Concat::accept(OperationVisitor &v) const { v.visit(*this); } + +Concat::Concat(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createAtLeast(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Conv2D.cc b/runtime/onert/core/src/ir/operation/Conv2D.cc new file mode 100644 index 000000000..3a2e1d1fe --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Conv2D.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Conv2D.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Conv2D::accept(OperationVisitor &v) const { v.visit(*this); } + +Conv2D::Conv2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ConvertFp16ToFp32.cc b/runtime/onert/core/src/ir/operation/ConvertFp16ToFp32.cc new file mode 100644 index 000000000..676e039fa --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ConvertFp16ToFp32.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ConvertFp16ToFp32.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ConvertFp16ToFp32::accept(OperationVisitor &v) const { v.visit(*this); } + +ConvertFp16ToFp32::ConvertFp16ToFp32(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ConvertFp32ToFp16.cc b/runtime/onert/core/src/ir/operation/ConvertFp32ToFp16.cc new file mode 100644 index 000000000..bcfcbfc04 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ConvertFp32ToFp16.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ConvertFp32ToFp16.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ConvertFp32ToFp16::accept(OperationVisitor &v) const { v.visit(*this); } + +ConvertFp32ToFp16::ConvertFp32ToFp16(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Custom.cc b/runtime/onert/core/src/ir/operation/Custom.cc new file mode 100644 index 000000000..25c53e1ba --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Custom.cc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Custom.h" + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Custom::accept(OperationVisitor &v) const { v.visit(*this); } + +Custom::Custom(OperandConstraint input_constr, const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs, std::string id, const Userdata &userdata) + : Operation{input_constr, inputs, outputs}, _id(std::move(id)), _userdata(userdata) +{ +} + +const std::string &Custom::id() const { return _id; } + +const Custom::Userdata &Custom::userdata() const { return _userdata; } + +std::string Custom::name() const { return id(); } + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/DepthToSpace.cc b/runtime/onert/core/src/ir/operation/DepthToSpace.cc new file mode 100644 index 000000000..f2d6c7c1b --- /dev/null +++ b/runtime/onert/core/src/ir/operation/DepthToSpace.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/DepthToSpace.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void DepthToSpace::accept(OperationVisitor &v) const { v.visit(*this); } + +DepthToSpace::DepthToSpace(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/DepthwiseConv2D.cc b/runtime/onert/core/src/ir/operation/DepthwiseConv2D.cc new file mode 100644 index 000000000..d587a5591 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/DepthwiseConv2D.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/DepthwiseConv2D.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void DepthwiseConv2D::accept(OperationVisitor &v) const { v.visit(*this); } + +DepthwiseConv2D::DepthwiseConv2D(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs, const Param ¶m) + : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Dequantize.cc b/runtime/onert/core/src/ir/operation/Dequantize.cc new file mode 100644 index 000000000..14d6362bd --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Dequantize.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Dequantize.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Dequantize::accept(OperationVisitor &v) const { v.visit(*this); } + +Dequantize::Dequantize(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Div.cc b/runtime/onert/core/src/ir/operation/Div.cc new file mode 100644 index 000000000..b095d9811 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Div.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Div.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Div::accept(OperationVisitor &v) const { v.visit(*this); } + +Div::Div(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/EmbeddingLookup.cc b/runtime/onert/core/src/ir/operation/EmbeddingLookup.cc new file mode 100644 index 000000000..b300b004e --- /dev/null +++ b/runtime/onert/core/src/ir/operation/EmbeddingLookup.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/EmbeddingLookup.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void EmbeddingLookup::accept(OperationVisitor &v) const { v.visit(*this); } + +EmbeddingLookup::EmbeddingLookup(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(2u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Exp.cc b/runtime/onert/core/src/ir/operation/Exp.cc new file mode 100644 index 000000000..0b22e080a --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Exp.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Exp.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Exp::accept(OperationVisitor &v) const { v.visit(*this); } + +Exp::Exp(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Floor.cc b/runtime/onert/core/src/ir/operation/Floor.cc new file mode 100644 index 000000000..dc01535ad --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Floor.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Floor.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Floor::accept(OperationVisitor &v) const { v.visit(*this); } + +Floor::Floor(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/FullyConnected.cc b/runtime/onert/core/src/ir/operation/FullyConnected.cc new file mode 100644 index 000000000..118ae554a --- /dev/null +++ b/runtime/onert/core/src/ir/operation/FullyConnected.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/FullyConnected.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void FullyConnected::accept(OperationVisitor &v) const { v.visit(*this); } + +FullyConnected::FullyConnected(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs, const Param ¶m) + : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Gather.cc b/runtime/onert/core/src/ir/operation/Gather.cc new file mode 100644 index 000000000..11d46e75b --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Gather.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Gather.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Gather::accept(OperationVisitor &v) const { v.visit(*this); } + +Gather::Gather(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/HashtableLookup.cc b/runtime/onert/core/src/ir/operation/HashtableLookup.cc new file mode 100644 index 000000000..e9a7a82ff --- /dev/null +++ b/runtime/onert/core/src/ir/operation/HashtableLookup.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/HashtableLookup.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void HashtableLookup::accept(OperationVisitor &v) const { v.visit(*this); } + +HashtableLookup::HashtableLookup(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(3u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/InstanceNorm.cc b/runtime/onert/core/src/ir/operation/InstanceNorm.cc new file mode 100644 index 000000000..2334560ef --- /dev/null +++ b/runtime/onert/core/src/ir/operation/InstanceNorm.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/InstanceNorm.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void InstanceNorm::accept(OperationVisitor &v) const { v.visit(*this); } + +InstanceNorm::InstanceNorm(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/L2Normalization.cc b/runtime/onert/core/src/ir/operation/L2Normalization.cc new file mode 100644 index 000000000..d1c92fa8b --- /dev/null +++ b/runtime/onert/core/src/ir/operation/L2Normalization.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/L2Normalization.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void L2Normalization::accept(OperationVisitor &v) const { v.visit(*this); } + +L2Normalization::L2Normalization(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs, const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/L2Pool2D.cc b/runtime/onert/core/src/ir/operation/L2Pool2D.cc new file mode 100644 index 000000000..8f21b93e0 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/L2Pool2D.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/L2Pool2D.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void L2Pool2D::accept(OperationVisitor &v) const { v.visit(*this); } + +L2Pool2D::L2Pool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/LSTM.cc b/runtime/onert/core/src/ir/operation/LSTM.cc new file mode 100644 index 000000000..30a865326 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/LSTM.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/LSTM.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void LSTM::accept(OperationVisitor &v) const { v.visit(*this); } + +LSTM::LSTM(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(23u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/LocalResponseNormalization.cc b/runtime/onert/core/src/ir/operation/LocalResponseNormalization.cc new file mode 100644 index 000000000..1ae97c142 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/LocalResponseNormalization.cc @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/LocalResponseNormalization.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void LocalResponseNormalization::accept(OperationVisitor &v) const { v.visit(*this); } + +LocalResponseNormalization::LocalResponseNormalization(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/LogicalAnd.cc b/runtime/onert/core/src/ir/operation/LogicalAnd.cc new file mode 100644 index 000000000..0d50706ca --- /dev/null +++ b/runtime/onert/core/src/ir/operation/LogicalAnd.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/LogicalAnd.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void LogicalAnd::accept(OperationVisitor &v) const { v.visit(*this); } + +LogicalAnd::LogicalAnd(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(2u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/LogicalNot.cc b/runtime/onert/core/src/ir/operation/LogicalNot.cc new file mode 100644 index 000000000..8f1142102 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/LogicalNot.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/LogicalNot.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void LogicalNot::accept(OperationVisitor &v) const { v.visit(*this); } + +LogicalNot::LogicalNot(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/LogicalOr.cc b/runtime/onert/core/src/ir/operation/LogicalOr.cc new file mode 100644 index 000000000..d75207c4a --- /dev/null +++ b/runtime/onert/core/src/ir/operation/LogicalOr.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/LogicalOr.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void LogicalOr::accept(OperationVisitor &v) const { v.visit(*this); } + +LogicalOr::LogicalOr(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(2u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Logistic.cc b/runtime/onert/core/src/ir/operation/Logistic.cc new file mode 100644 index 000000000..77d9d17de --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Logistic.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Logistic.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Logistic::accept(OperationVisitor &v) const { v.visit(*this); } + +Logistic::Logistic(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/LowerInfo.cc b/runtime/onert/core/src/ir/operation/LowerInfo.cc new file mode 100644 index 000000000..249918bd6 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/LowerInfo.cc @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/LowerInfo.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +LowerInfo::LowerInfo(const backend::Backend *backend, Layout layout) + : _permute_factor{backend, layout} +{ + // DO NOTHING +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Max.cc b/runtime/onert/core/src/ir/operation/Max.cc new file mode 100644 index 000000000..281f9d451 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Max.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Max.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Max::accept(OperationVisitor &v) const { v.visit(*this); } + +Max::Max(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(2u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/MaxPool2D.cc b/runtime/onert/core/src/ir/operation/MaxPool2D.cc new file mode 100644 index 000000000..eac53cc5e --- /dev/null +++ b/runtime/onert/core/src/ir/operation/MaxPool2D.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/MaxPool2D.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void MaxPool2D::accept(OperationVisitor &v) const { v.visit(*this); } + +MaxPool2D::MaxPool2D(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Mean.cc b/runtime/onert/core/src/ir/operation/Mean.cc new file mode 100644 index 000000000..5313a4434 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Mean.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Mean.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Mean::accept(OperationVisitor &v) const { v.visit(*this); } + +Mean::Mean(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Min.cc b/runtime/onert/core/src/ir/operation/Min.cc new file mode 100644 index 000000000..8be7f0cc8 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Min.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Min.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Min::accept(OperationVisitor &v) const { v.visit(*this); } + +Min::Min(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(2u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Mul.cc b/runtime/onert/core/src/ir/operation/Mul.cc new file mode 100644 index 000000000..03cdf1b61 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Mul.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Mul.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Mul::accept(OperationVisitor &v) const { v.visit(*this); } + +Mul::Mul(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Neg.cc b/runtime/onert/core/src/ir/operation/Neg.cc new file mode 100644 index 000000000..df623a13b --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Neg.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Neg.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Neg::accept(OperationVisitor &v) const { v.visit(*this); } + +Neg::Neg(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/OneHot.cc b/runtime/onert/core/src/ir/operation/OneHot.cc new file mode 100644 index 000000000..22935e7d6 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/OneHot.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/OneHot.h" +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void OneHot::accept(OperationVisitor &v) const { v.visit(*this); } + +OneHot::OneHot(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(4u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/PReLU.cc b/runtime/onert/core/src/ir/operation/PReLU.cc new file mode 100644 index 000000000..a2e37e0ad --- /dev/null +++ b/runtime/onert/core/src/ir/operation/PReLU.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/PReLU.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void PReLU::accept(OperationVisitor &v) const { v.visit(*this); } + +PReLU::PReLU(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(2u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Pack.cc b/runtime/onert/core/src/ir/operation/Pack.cc new file mode 100644 index 000000000..f0908a2c6 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Pack.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ir/operation/Pack.h" +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ +void Pack::accept(OperationVisitor &v) const { v.visit(*this); } +Pack::Pack(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createAtLeast(3u), inputs, outputs}, _param{param} +{ +} +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Pad.cc b/runtime/onert/core/src/ir/operation/Pad.cc new file mode 100644 index 000000000..a958b5241 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Pad.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Pad.h" + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Pad::accept(OperationVisitor &v) const { v.visit(*this); } + +Pad::Pad(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Permute.cc b/runtime/onert/core/src/ir/operation/Permute.cc new file mode 100644 index 000000000..fd495ed4b --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Permute.cc @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Permute.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Permute::accept(OperationVisitor &v) const { v.visit(*this); } + +Permute::Permute(const OperandIndex &input, const OperandIndex &output, + const backend::BackendContext *input_backend_ctx, + const backend::BackendContext *output_backend_ctx, Type type, DataType data_type) + : Operation{OperandConstraint::createExact(1u)}, _param{input_backend_ctx, output_backend_ctx}, + _type{type}, _dataType{data_type} +{ + setInputs({input}); + setOutputs({output}); +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/RNN.cc b/runtime/onert/core/src/ir/operation/RNN.cc new file mode 100644 index 000000000..298c5e745 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/RNN.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/RNN.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void RNN::accept(OperationVisitor &v) const { v.visit(*this); } + +RNN::RNN(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(5u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/RSQRT.cc b/runtime/onert/core/src/ir/operation/RSQRT.cc new file mode 100644 index 000000000..2bce1fa28 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/RSQRT.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/RSQRT.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void RSQRT::accept(OperationVisitor &v) const { v.visit(*this); } + +RSQRT::RSQRT(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ReLU.cc b/runtime/onert/core/src/ir/operation/ReLU.cc new file mode 100644 index 000000000..f0c88478b --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ReLU.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ReLU.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ReLU::accept(OperationVisitor &v) const { v.visit(*this); } + +ReLU::ReLU(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ReLU1.cc b/runtime/onert/core/src/ir/operation/ReLU1.cc new file mode 100644 index 000000000..734f0b65b --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ReLU1.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ReLU1.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ReLU1::accept(OperationVisitor &v) const { v.visit(*this); } + +ReLU1::ReLU1(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ReLU6.cc b/runtime/onert/core/src/ir/operation/ReLU6.cc new file mode 100644 index 000000000..5972329af --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ReLU6.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ReLU6.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ReLU6::accept(OperationVisitor &v) const { v.visit(*this); } + +ReLU6::ReLU6(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ReduceMax.cc b/runtime/onert/core/src/ir/operation/ReduceMax.cc new file mode 100644 index 000000000..f7faf8744 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ReduceMax.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ReduceMax.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ReduceMax::accept(OperationVisitor &v) const { v.visit(*this); } + +ReduceMax::ReduceMax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ReduceMin.cc b/runtime/onert/core/src/ir/operation/ReduceMin.cc new file mode 100644 index 000000000..83cdccb78 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ReduceMin.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ReduceMin.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ReduceMin::accept(OperationVisitor &v) const { v.visit(*this); } + +ReduceMin::ReduceMin(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ReduceSum.cc b/runtime/onert/core/src/ir/operation/ReduceSum.cc new file mode 100644 index 000000000..c25a5ac5c --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ReduceSum.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ReduceSum.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ReduceSum::accept(OperationVisitor &v) const { v.visit(*this); } + +ReduceSum::ReduceSum(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Reshape.cc b/runtime/onert/core/src/ir/operation/Reshape.cc new file mode 100644 index 000000000..b3a0d30b6 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Reshape.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Reshape.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Reshape::accept(OperationVisitor &v) const { v.visit(*this); } + +Reshape::Reshape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/ResizeBilinear.cc b/runtime/onert/core/src/ir/operation/ResizeBilinear.cc new file mode 100644 index 000000000..d0d89f45f --- /dev/null +++ b/runtime/onert/core/src/ir/operation/ResizeBilinear.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/ResizeBilinear.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void ResizeBilinear::accept(OperationVisitor &v) const { v.visit(*this); } + +ResizeBilinear::ResizeBilinear(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs, const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/SQRT.cc b/runtime/onert/core/src/ir/operation/SQRT.cc new file mode 100644 index 000000000..ad887d89a --- /dev/null +++ b/runtime/onert/core/src/ir/operation/SQRT.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/SQRT.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void SQRT::accept(OperationVisitor &v) const { v.visit(*this); } + +SQRT::SQRT(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Shape.cc b/runtime/onert/core/src/ir/operation/Shape.cc new file mode 100644 index 000000000..2a63d6dcf --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Shape.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Shape.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Shape::accept(OperationVisitor &v) const { v.visit(*this); } + +Shape::Shape(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Sin.cc b/runtime/onert/core/src/ir/operation/Sin.cc new file mode 100644 index 000000000..631505f36 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Sin.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Sin.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Sin::accept(OperationVisitor &v) const { v.visit(*this); } + +Sin::Sin(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Slice.cc b/runtime/onert/core/src/ir/operation/Slice.cc new file mode 100644 index 000000000..674bd7093 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Slice.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Slice.h" +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Slice::accept(OperationVisitor &v) const { v.visit(*this); } + +Slice::Slice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Softmax.cc b/runtime/onert/core/src/ir/operation/Softmax.cc new file mode 100644 index 000000000..3f1aa0af1 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Softmax.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Softmax.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Softmax::accept(OperationVisitor &v) const { v.visit(*this); } + +Softmax::Softmax(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/SpaceToBatchND.cc b/runtime/onert/core/src/ir/operation/SpaceToBatchND.cc new file mode 100644 index 000000000..53fab4fa9 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/SpaceToBatchND.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/SpaceToBatchND.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void SpaceToBatchND::accept(OperationVisitor &v) const { v.visit(*this); } + +SpaceToBatchND::SpaceToBatchND(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(3u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/SpaceToDepth.cc b/runtime/onert/core/src/ir/operation/SpaceToDepth.cc new file mode 100644 index 000000000..d8a45aee5 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/SpaceToDepth.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/SpaceToDepth.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void SpaceToDepth::accept(OperationVisitor &v) const { v.visit(*this); } + +SpaceToDepth::SpaceToDepth(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Split.cc b/runtime/onert/core/src/ir/operation/Split.cc new file mode 100644 index 000000000..244884e41 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Split.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ir/operation/Split.h" +#include +#include "ir/OperationVisitor.h" +namespace onert +{ +namespace ir +{ +namespace operation +{ +void Split::accept(OperationVisitor &v) const { v.visit(*this); } +Split::Split(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/SquaredDifference.cc b/runtime/onert/core/src/ir/operation/SquaredDifference.cc new file mode 100644 index 000000000..49e58aaf2 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/SquaredDifference.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/SquaredDifference.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void SquaredDifference::accept(OperationVisitor &v) const { v.visit(*this); } + +SquaredDifference::SquaredDifference(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(2u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Squeeze.cc b/runtime/onert/core/src/ir/operation/Squeeze.cc new file mode 100644 index 000000000..8cf928fb4 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Squeeze.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Squeeze.h" +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Squeeze::accept(OperationVisitor &v) const { v.visit(*this); } + +Squeeze::Squeeze(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param(param) +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/StridedSlice.cc b/runtime/onert/core/src/ir/operation/StridedSlice.cc new file mode 100644 index 000000000..adc8beaa3 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/StridedSlice.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/StridedSlice.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void StridedSlice::accept(OperationVisitor &v) const { v.visit(*this); } + +StridedSlice::StridedSlice(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Sub.cc b/runtime/onert/core/src/ir/operation/Sub.cc new file mode 100644 index 000000000..d71071686 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Sub.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Sub.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Sub::accept(OperationVisitor &v) const { v.visit(*this); } + +Sub::Sub(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Tanh.cc b/runtime/onert/core/src/ir/operation/Tanh.cc new file mode 100644 index 000000000..8fab0c0f3 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Tanh.cc @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Tanh.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Tanh::accept(OperationVisitor &v) const { v.visit(*this); } + +Tanh::Tanh(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs) + : Operation{OperandConstraint::createExact(1u), inputs, outputs} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/TopKV2.cc b/runtime/onert/core/src/ir/operation/TopKV2.cc new file mode 100644 index 000000000..a5e6c6a85 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/TopKV2.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/TopKV2.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void TopKV2::accept(OperationVisitor &v) const { v.visit(*this); } + +TopKV2::TopKV2(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Transpose.cc b/runtime/onert/core/src/ir/operation/Transpose.cc new file mode 100644 index 000000000..3a663fbce --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Transpose.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/Transpose.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void Transpose::accept(OperationVisitor &v) const { v.visit(*this); } + +Transpose::Transpose(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(2u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/TransposeConv.cc b/runtime/onert/core/src/ir/operation/TransposeConv.cc new file mode 100644 index 000000000..7f29ca44e --- /dev/null +++ b/runtime/onert/core/src/ir/operation/TransposeConv.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ir/operation/TransposeConv.h" + +#include + +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ + +void TransposeConv::accept(OperationVisitor &v) const { v.visit(*this); } + +TransposeConv::TransposeConv(const OperandIndexSequence &inputs, + const OperandIndexSequence &outputs, const Param ¶m) + : Operation{OperandConstraint::createExact(3u), inputs, outputs}, _param{param} +{ +} + +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/operation/Unpack.cc b/runtime/onert/core/src/ir/operation/Unpack.cc new file mode 100644 index 000000000..67aa54ab5 --- /dev/null +++ b/runtime/onert/core/src/ir/operation/Unpack.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "ir/operation/Unpack.h" +#include "ir/OperationVisitor.h" + +namespace onert +{ +namespace ir +{ +namespace operation +{ +void Unpack::accept(OperationVisitor &v) const { v.visit(*this); } +Unpack::Unpack(const OperandIndexSequence &inputs, const OperandIndexSequence &outputs, + const Param ¶m) + : Operation{OperandConstraint::createExact(1u), inputs, outputs}, _param{param} +{ +} +} // namespace operation +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/pass/ConstantInsertionPass.cc b/runtime/onert/core/src/ir/pass/ConstantInsertionPass.cc new file mode 100644 index 000000000..5f4612d35 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/ConstantInsertionPass.cc @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ConstantInsertionPass.h" + +#include "backend/Backend.h" +#include +#include + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +void ConstantInsertionPass::callback(const OperationIndex &node_index, Operation &node) +{ + const auto &op_sequence_index = _lowered_graph.op_seqs().getOperation(node_index); + const auto op_seq_lower_info = _lowered_graph.getLowerInfo(op_sequence_index); + const auto backend = op_seq_lower_info->backend(); + const auto layout = op_seq_lower_info->layout(); + const auto factor = operand::PermuteFactor{backend, layout}; + + for (const auto input : node.getInputs()) + { + auto &object = _graph.operands().at(input); + + if (object.isConstant()) + { + const auto key = ReplaceKey{input, factor}; + if (_replace_operands_map.count(key) == 0) + { + auto new_object = object; + // TODO Remove const_case + const_cast &>(new_object.getDef().list()).clear(); + const_cast &>(new_object.getUses().list()).clear(); + const auto new_index = _graph.operands().emplace(new_object); + _replace_operands_map[key] = new_index; + + _lowered_graph.setLowerInfo(new_index, std::make_unique()); + _lowered_graph.getLowerInfo(new_index)->addDefPermuteFactor(factor); + } + + const auto replaced_input = _replace_operands_map[key]; + // Update op_seq + if (_lowered_graph.op_seqs().at(op_sequence_index).getInputs().contains(input)) + { + _lowered_graph.op_seqs().at(op_sequence_index).replaceInput(input, replaced_input); + } + + // Update node + node.replaceInput(input, replaced_input); + + // Update operand + auto &replaced_object = _graph.operands().at(replaced_input); + replaced_object.appendUse(node_index); + + // Update lower_info + auto replaced_lower_info = _lowered_graph.getLowerInfo(replaced_input); + replaced_lower_info->addUsePermuteFactor(factor); + + // Remove this node from def and uses of origin operand + if (object.getDef().contains(node_index)) + { + object.removeDef(node_index); + } + object.removeUse(node_index); + + // Remove origin operand + if (object.getDef().size() == 0 && object.getUses().size() == 0) + { + _graph.removeOperand(input); + _lowered_graph.removeLowerInfo(input); + } + } + } + + // Now this runtime does not support the node making output as constant + for (const auto &output : node.getOutputs()) + { + UNUSED_RELEASE(output); + assert(!_graph.operands().at(output).isConstant()); + } +} + +} // namespace pass +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/pass/ConstantInsertionPass.h b/runtime/onert/core/src/ir/pass/ConstantInsertionPass.h new file mode 100644 index 000000000..3ea4dc397 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/ConstantInsertionPass.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_GRAPH_PASS_CONSTANT_INSERTION_PASS_H__ +#define __ONERT_GRAPH_PASS_CONSTANT_INSERTION_PASS_H__ + +#include +#include +#include "LoweredOperationPass.h" +#include +#include + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +class ConstantInsertionPass : public LoweredOperationPass +{ +public: + using LoweredOperationPass::LoweredOperationPass; + +public: + std::string id() final { return "ConstantInsertionPass"; } + +public: + void callback(const OperationIndex &index, Operation &node) final; + +private: + struct ReplaceKey + { + OperandIndex index; + operand::PermuteFactor factor; + + bool operator==(const ReplaceKey &other) const + { + return index == other.index && factor == other.factor; + } + }; + + /** + * @brief Structure that provides hash function of ReplaceKey + */ + struct KeyHasher + { + std::size_t operator()(const ReplaceKey &key) const noexcept + { + using std::hash; + return hash()(key.index) ^ (hash()(key.factor) << 1); + } + }; + + std::unordered_map _replace_operands_map; +}; + +} // namespace pass +} // namespace ir +} // namespace onert + +#endif // __ONERT_GRAPH_PASS_CONSTANT_INSERTION_PASS_H__ diff --git a/runtime/onert/core/src/ir/pass/LoweredOperandPass.h b/runtime/onert/core/src/ir/pass/LoweredOperandPass.h new file mode 100644 index 000000000..eefb8ddfb --- /dev/null +++ b/runtime/onert/core/src/ir/pass/LoweredOperandPass.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_PASS_LOWERED_OPERAND_PASS_H__ +#define __ONERT_IR_PASS_LOWERED_OPERAND_PASS_H__ + +#include "OperandPass.h" +#include "ir/LoweredGraph.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +class LoweredOperandPass : public OperandPass +{ +public: + LoweredOperandPass(ir::LoweredGraph &lowered_graph) + : OperandPass{lowered_graph.graph()}, _lowered_graph{lowered_graph} + { + // DO NOTHING + } + + virtual ~LoweredOperandPass() = default; + + std::string id() override = 0; + void callback(const OperandIndex &i, Operand &o) override = 0; + +protected: + ir::LoweredGraph &_lowered_graph; +}; + +} // namespace pass +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_PASS_LOWERED_OPERAND_PASS_H__ diff --git a/runtime/onert/core/src/ir/pass/LoweredOperationPass.h b/runtime/onert/core/src/ir/pass/LoweredOperationPass.h new file mode 100644 index 000000000..0138712d7 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/LoweredOperationPass.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_IR_PASS_LOWERED_OPERATION_PASS_H__ +#define __ONERT_IR_PASS_LOWERED_OPERATION_PASS_H__ + +#include "OperationPass.h" +#include "ir/LoweredGraph.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +class LoweredOperationPass : public OperationPass +{ +public: + LoweredOperationPass(ir::LoweredGraph &lowered_graph) + : OperationPass{lowered_graph.graph()}, _lowered_graph{lowered_graph} + { + // DO NOTHING + } + + virtual ~LoweredOperationPass() = default; + + std::string id() override = 0; + void callback(const OperationIndex &i, Operation &o) override = 0; + +protected: + ir::LoweredGraph &_lowered_graph; +}; + +} // namespace pass +} // namespace ir +} // namespace onert + +#endif // __ONERT_IR_PASS_LOWERED_OPERATION_PASS_H__ diff --git a/runtime/onert/core/src/ir/pass/OperandPass.cc b/runtime/onert/core/src/ir/pass/OperandPass.cc new file mode 100644 index 000000000..693a0f493 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/OperandPass.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperandPass.h" + +#include "ir/Graph.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +void OperandPass::run() +{ + _graph.operands().iterate( + [&](const OperandIndex &index, Operand &object) { callback(index, object); }); +} + +} // namespace pass +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/pass/OperandPass.h b/runtime/onert/core/src/ir/pass/OperandPass.h new file mode 100644 index 000000000..393060741 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/OperandPass.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_GRAPH_PASS_OPERAND_PASS_H__ +#define __ONERT_GRAPH_PASS_OPERAND_PASS_H__ + +#include "Pass.h" +#include "ir/Index.h" + +namespace onert +{ +namespace ir +{ +class Operand; +} // namespace ir +} // namespace onert + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +class OperandPass : public Pass +{ +public: + using Pass::Pass; + virtual ~OperandPass() = default; + +public: + std::string id() override = 0; + void run() override final; + virtual void callback(const OperandIndex &i, Operand &o) = 0; +}; + +} // namespace pass +} // namespace ir +} // namespace onert + +#endif // __ONERT_GRAPH_PASS_OPERAND_PASS_H__ diff --git a/runtime/onert/core/src/ir/pass/OperationPass.cc b/runtime/onert/core/src/ir/pass/OperationPass.cc new file mode 100644 index 000000000..84b1da3ee --- /dev/null +++ b/runtime/onert/core/src/ir/pass/OperationPass.cc @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperationPass.h" + +#include "ir/Index.h" +#include "ir/Operation.h" +#include "ir/Graph.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +void OperationPass::run() +{ + _graph.operations().iterate( + [&](const OperationIndex &index, Operation &node) { callback(index, node); }); +} + +} // namespace pass +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/pass/OperationPass.h b/runtime/onert/core/src/ir/pass/OperationPass.h new file mode 100644 index 000000000..1733f87ed --- /dev/null +++ b/runtime/onert/core/src/ir/pass/OperationPass.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file OperationPass.h + * @brief This file contains OperationPass class + */ + +#ifndef __ONERT_GRAPH_PASS_OPERATION_PASS_H__ +#define __ONERT_GRAPH_PASS_OPERATION_PASS_H__ + +#include "Pass.h" +#include "ir/Index.h" + +namespace onert +{ +namespace ir +{ +class Operation; +} // namespace ir +} // namespace onert + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +/** + * @brief Class to iterate over operations and calls callback() method + */ +class OperationPass : public Pass +{ +public: + using Pass::Pass; + virtual ~OperationPass() = default; + +public: + /** + * @brief Returns string id for this pass. Same with class name. + * + * @return string id + */ + std::string id() override = 0; + + /** + * @brief Be called for all nodes of graph. + * @param index is the index of a node in graph + * @param node is the node in graph + */ + virtual void callback(const OperationIndex &index, Operation &node) = 0; + + /** + * @brief Run the pass + */ + void run() final; +}; + +} // namespace pass +} // namespace ir +} // namespace onert + +#endif // __ONERT_GRAPH_PASS_OPERATION_PASS_H__ diff --git a/runtime/onert/core/src/ir/pass/Pass.h b/runtime/onert/core/src/ir/pass/Pass.h new file mode 100644 index 000000000..1c6628f6f --- /dev/null +++ b/runtime/onert/core/src/ir/pass/Pass.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_GRAPH_PASS_PASS_H__ +#define __ONERT_GRAPH_PASS_PASS_H__ + +#include + +namespace onert +{ +namespace ir +{ +class Graph; +} // namespace ir +} // namespace onert + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +class Pass +{ +public: + Pass(Graph &graph) : _graph{graph} {} + virtual ~Pass() = default; + +public: + virtual std::string id() = 0; + virtual void run() = 0; + +protected: + Graph &_graph; +}; + +} // namespace pass +} // namespace ir +} // namespace onert + +#endif // __ONERT_GRAPH_PASS_PASS_H__ diff --git a/runtime/onert/core/src/ir/pass/PermutationEliminationPass.cc b/runtime/onert/core/src/ir/pass/PermutationEliminationPass.cc new file mode 100644 index 000000000..f4793d411 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/PermutationEliminationPass.cc @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PermutationEliminationPass.h" + +#include "ir/Operand.h" +#include "ir/operand/LowerInfo.h" +#include "ir/Graph.h" +#include "backend/IConfig.h" +#include "util/logging.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ +void PermutationEliminationPass::callback(const OperandIndex &inp_index, Operand &object) +{ + if (_graph.getInputs().contains(inp_index)) + { + eliminateInput(inp_index, object); + } + else if (_graph.getOutputs().contains(inp_index)) + { + eliminateOutput(inp_index, object); + } +} + +void PermutationEliminationPass::eliminateInput(const OperandIndex &inp_index, Operand &object) +{ + auto &model_inputs = _graph.getInputs(); + + // get uses of the model's given input + auto uses = object.getUses(); + + // input must be used just by permutation + if (uses.size() != 1) + { + return; + } + + for (auto input_use : uses.list()) + { + auto &perm_operation = _graph.operations().at(input_use); + auto perm_inputs = perm_operation.getInputs(); + + auto perm_outputs = perm_operation.getOutputs(); + + if (!isPermuteLayerToEliminate(perm_inputs, perm_outputs, true)) + { + return; + } + + assert(perm_inputs.at(0) == inp_index); + + VERBOSE(PermutationEliminationPass::EliminateInput) << "remove NHWC_TO_NCHW permutation\n"; + + // set model's new input, which was output of permutation + model_inputs.replace(inp_index, perm_outputs.at(0)); + + // remove model's input, which is also input of permutation + _graph.removeOperand(inp_index); + + // remove permutation operation + assert(_lowered_graph.op_seqs().containsOperation(input_use)); + auto op_seq_idx = _lowered_graph.op_seqs().getOperation(input_use); + _lowered_graph.op_seqs().remove(op_seq_idx); + _graph.operations().remove(input_use); + + VERBOSE(PermutationEliminationPass::EliminateInput) + << inp_index.value() << " is model's input and is removed. New input is " + << perm_outputs.at(0).value() << "\n" + << input_use.value() << " is removed permutation operation\n"; + } +} + +void PermutationEliminationPass::eliminateOutput(const OperandIndex &out_index, Operand &object) +{ + auto &model_outputs = _graph.getOutputs(); + + // get defs of the model's given output + auto defs = object.getDef(); + + // output must use just permutation + if (defs.size() != 1) + { + return; + } + + for (auto output_def : defs.list()) + { + auto &perm_operation = _graph.operations().at(output_def); + auto perm_outputs = perm_operation.getOutputs(); + + auto perm_inputs = perm_operation.getInputs(); + if (!isPermuteLayerToEliminate(perm_inputs, perm_outputs, false)) + { + return; + } + + assert(perm_outputs.at(0) == out_index); + + VERBOSE(PermutationEliminationPass::EliminateOutput) << "remove NCHW_TO_NHWC permutation\n"; + + // Update operations' output that is used by permute operand + for (auto perm_input_index : perm_inputs) + { + auto &perm_input_operand = _graph.operands().at(perm_input_index); + perm_input_operand.removeUse(output_def); + } + + // set model's new output, which was input of permutation + model_outputs.replace(out_index, perm_inputs.at(0)); + + // remove model's output, which is also output of permutation + _graph.removeOperand(out_index); + + // remove permutation operation + assert(_lowered_graph.op_seqs().containsOperation(output_def)); + auto op_seq_idx = _lowered_graph.op_seqs().getOperation(output_def); + _lowered_graph.op_seqs().remove(op_seq_idx); + _graph.operations().remove(output_def); + + VERBOSE(PermutationEliminationPass::EliminateOutput) + << out_index.value() << " is model's output and is removed. New output is " + << perm_inputs.at(0).value() << "\n" + << output_def.value() << " is removed permutation operation\n"; + } +} + +bool PermutationEliminationPass::isPermuteLayerToEliminate(const OperandIndexSequence &inp_indexes, + const OperandIndexSequence &out_indexes, + bool is_for_model_input) +{ + auto input_def_factors = _lowered_graph.getLowerInfo(inp_indexes.at(0))->def_factors(); + auto output_def_factors = _lowered_graph.getLowerInfo(out_indexes.at(0))->def_factors(); + + auto input_layout = input_def_factors.getOnlyElement().layout(); + auto output_layout = output_def_factors.getOnlyElement().layout(); + + if (input_def_factors.size() != 1 || output_def_factors.size() != 1) + { + return false; + } + + // all operands' factor must be the same + for (auto index : inp_indexes) + { + auto op_factor_set = _lowered_graph.getLowerInfo(index)->def_factors(); + if (op_factor_set.size() != 1 || + input_layout != _lowered_graph.getLowerInfo(index)->def_factors().getOnlyElement().layout()) + { + return false; + } + } + // all operands' factor must be the same + for (auto index : out_indexes) + { + auto op_factor_set = _lowered_graph.getLowerInfo(index)->def_factors(); + if (op_factor_set.size() != 1 || + output_layout != + _lowered_graph.getLowerInfo(index)->def_factors().getOnlyElement().layout()) + { + return false; + } + } + + if (is_for_model_input) + { + // check if this is NHWC_TO_NCHW permutation: must have single input, which is model's input + return (inp_indexes.size() == 1 && input_layout == Layout::NHWC && + output_layout == Layout::NCHW); + } + + // check if this is NCHW_TO_NHWC permutation: must have single output, which is model's output + return (out_indexes.size() == 1 && input_layout == Layout::NCHW && output_layout == Layout::NHWC); +} + +} // namespace pass +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/pass/PermutationEliminationPass.h b/runtime/onert/core/src/ir/pass/PermutationEliminationPass.h new file mode 100644 index 000000000..1c8430062 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/PermutationEliminationPass.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__ +#define __ONERT_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__ + +#include "LoweredOperandPass.h" +#include "ir/Operand.h" +#include "ir/OperandIndexSequence.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +class PermutationEliminationPass : public LoweredOperandPass +{ +public: + using LoweredOperandPass::LoweredOperandPass; + +public: + std::string id() override { return "PermutationEliminationPass"; } + + void callback(const OperandIndex &index, Operand &object) override; + +private: + /** + * @brief Remove Permute operation that permutates input + * + * Note: This function aslo removes model's input and + * sets output of permutation as model's new input + * + * @param inp_index is the target operand index for the elimination + * @param object is the target operand object for the elimination + * + * @return + */ + void eliminateInput(const OperandIndex &inp_index, Operand &object); + + /** + * @brief Remove Permute operation that permutates output of a model + * + * Note: This function aslo removes model's output and + * sets input of permutation as model's new output + * + * @param out_index is the target operand index for the elimination + * @param object is the target operand object for the elimination + * + * @return + */ + void eliminateOutput(const OperandIndex &out_index, Operand &object); + + /** + * @brief Determine if passed operands are permute layer's input and output, that must be + * eliminated + * + * @param inp_index indexes of the input operand to operation + * @param out_index indexes of the output operand to operation + * @param is_for_model_input checking for model's input or output + * + * @return if it is permutation layer + */ + bool isPermuteLayerToEliminate(const OperandIndexSequence &inp_indexes, + const OperandIndexSequence &out_indexes, bool is_for_model_input); +}; + +} // namespace pass +} // namespace ir +} // namespace onert + +#endif // __ONERT_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__ diff --git a/runtime/onert/core/src/ir/pass/PermutationInsertionPass.cc b/runtime/onert/core/src/ir/pass/PermutationInsertionPass.cc new file mode 100644 index 000000000..32db3d878 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/PermutationInsertionPass.cc @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PermutationInsertionPass.h" + +#include +#include +#include + +#include "ir/Operand.h" +#include "ir/operation/LowerInfo.h" +#include "ir/Graph.h" +#include "backend/IConfig.h" +#include "util/logging.h" +#include +#include "ir/operation/Permute.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +void PermutationInsertionPass::callback(const OperandIndex &index, Operand &object) +{ + auto &&operand_li = _lowered_graph.getLowerInfo(index); + assert(operand_li); + + // NOTE Later, constants also will have Def + // Ignore constants + if (operand_li->def_factors().size() == 0) + { + return; + } + + std::list permute_indexes; + + // Build a map for all necessary type of operands + std::unordered_map factor_to_index; + { + assert(operand_li->def_factors().size() == 1); + for (auto factor : operand_li->def_factors()) + { + factor_to_index.emplace(factor, index); + } + + auto insert_set = operand_li->use_factors() - operand_li->def_factors(); + for (auto factor : insert_set) + { + const auto permute_operation_index = insertPermute(index, factor); + permute_indexes.push_back(permute_operation_index); + VERBOSE(PermutationInsertionPass) << "Insert 'Permute' operation for operand " + << index.value() << std::endl; + const auto &permute_operation = _graph.operations().at(permute_operation_index); + const auto permuted_operand_index = permute_operation.getOutputs().at(0); + factor_to_index.emplace(factor, permuted_operand_index); + } + } + + // Update operations' input that uses this operand + { + std::list remove_list; + + auto uses = object.getUses(); + for (auto use : uses.list()) + { + // If permute operation, ignore it + if (std::find(permute_indexes.begin(), permute_indexes.end(), use) != permute_indexes.end()) + continue; + + auto &operation = _graph.operations().at(use); + assert(_lowered_graph.op_seqs().containsOperation(use)); + auto op_seq_index = _lowered_graph.op_seqs().getOperation(use); + auto op_seq_li = _lowered_graph.getLowerInfo(op_seq_index); + assert(op_seq_li); + const auto op_seq_layout = op_seq_li->layout(); + const backend::Backend *backend = op_seq_li->backend(); + assert(backend); + auto use_node_inputs = operation.getInputs(); + assert(use_node_inputs.contains(index)); + + auto new_index = factor_to_index.at({backend, op_seq_layout}); + if (index != new_index) + { + // Update from op_seq + _lowered_graph.op_seqs().at(op_seq_index).replaceInput(index, new_index); + + // Update from operation + operation.replaceInput(index, new_index); + + // Update from operand + remove_list.push_back( + use); // Removal should be done in another loop since we are in the loop + _graph.operands().at(new_index).appendUse(use); + } + } + + for (auto &operation : remove_list) + { + object.removeUse(operation); + } + } +} + +OperationIndex PermutationInsertionPass::insertPermute(const OperandIndex &operand_index, + const operand::PermuteFactor &factor) +{ + assert(!_graph.isBuildingPhase()); + + auto &operand = _graph.operands().at(operand_index); + + // Generate output operand and permute operation + auto out_operand_index = _graph.addOperand(operand.shape(), operand.typeInfo()); + // change model output if operand_index is model output index + auto &model_outputs = _graph.getOutputs(); + if (model_outputs.contains(operand_index)) + { + model_outputs.replace(operand_index, out_operand_index); + } + + // Find Permute information + auto input_backend = + _lowered_graph.getLowerInfo(operand_index)->def_factors().getOnlyElement().backend(); + auto output_backend = factor.backend(); + // NOTE Permute may not have specific layout because the layout of input and output may be + // different. + const auto permute_node_layout = Layout::UNKNOWN; + const auto permute_node_backend = compiler::BackendManager::get().getDefault(); + const operand::PermuteFactor permute_node_factor{permute_node_backend, permute_node_layout}; + + // Update LowerInfo of input operand + auto operand_lower_info = _lowered_graph.getLowerInfo(operand_index); + operand_lower_info->removeUsePermuteFactor(factor); + operand_lower_info->addUsePermuteFactor(permute_node_factor); + + // Update LowerInfo of output operand + auto out_operand_li = std::make_unique(); + + // The input and output factors of all nodes will be the same except Permute. So Tensor's + // allocators allocates memory using only the information of def permutation factor now. + // TODO Change param to permute_node_factor + out_operand_li->addDefPermuteFactor(factor); + out_operand_li->addUsePermuteFactor(factor); + _lowered_graph.setLowerInfo(out_operand_index, std::move(out_operand_li)); + + auto input_backend_ctx = _lowered_graph.backend_contexts().at(input_backend).get(); + auto output_backend_ctx = _lowered_graph.backend_contexts().at(output_backend).get(); + + // Insert permute operation to the graph + const auto input_layout = + _lowered_graph.getLowerInfo(operand_index)->def_factors().getOnlyElement().layout(); + const auto output_layout = factor.layout(); + using Permute = operation::Permute; + const auto permute_type = [&]() { + if (input_layout == Layout::NHWC && output_layout == Layout::NCHW) + { + return Permute::Type::NHWC_TO_NCHW; + } + else if (input_layout == Layout::NCHW && output_layout == Layout::NHWC) + { + return Permute::Type::NCHW_TO_NHWC; + } + else + { + return Permute::Type::COPY; + } + }(); + auto insert_node = std::make_unique(operand_index, out_operand_index, input_backend_ctx, + output_backend_ctx, permute_type); + + auto node_index = _graph.operations().push(std::move(insert_node)); + const auto &node = _graph.operations().at(node_index); + + // OpSequence + { + auto op_seq_index = _lowered_graph.op_seqs().emplace(node_index, node, permute_node_layout); + auto &op_seq = _lowered_graph.op_seqs().at(op_seq_index); + op_seq.setInputs(node.getInputs()); + op_seq.setOutputs(node.getOutputs()); + _lowered_graph.setLowerInfo(op_seq_index, std::make_unique( + permute_node_backend, permute_node_layout)); + } + + // Update Use/Def info + { + _graph.operands().at(operand_index).appendUse(node_index); + _graph.operands().at(out_operand_index).appendDef(node_index); + } + return node_index; +} +} // namespace pass +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/pass/PermutationInsertionPass.h b/runtime/onert/core/src/ir/pass/PermutationInsertionPass.h new file mode 100644 index 000000000..314a54c95 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/PermutationInsertionPass.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__ +#define __ONERT_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__ + +#include "LoweredOperandPass.h" +#include "compiler/BackendManager.h" +#include "ir/Operand.h" //for OperationIndex +#include "ir/operand/PermuteFactor.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +class PermutationInsertionPass : public LoweredOperandPass +{ +public: + using LoweredOperandPass::LoweredOperandPass; + +public: + std::string id() override { return "PermutationInsertionPass"; } + void callback(const OperandIndex &index, Operand &object) override; + + /** + * @brief Insert Permute operation that has given operand as input + * + * @param operand_index is the target operand index for the insertion + * @param factor is the output operand's backend type and layout + * + * @return OperationIndex + */ + OperationIndex insertPermute(const OperandIndex &operand_index, + const operand::PermuteFactor &factor); + +private: +}; + +} // namespace pass +} // namespace ir +} // namespace onert + +#endif // __ONERT_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__ diff --git a/runtime/onert/core/src/ir/pass/PermutationOperationPass.cc b/runtime/onert/core/src/ir/pass/PermutationOperationPass.cc new file mode 100644 index 000000000..f2172c4b0 --- /dev/null +++ b/runtime/onert/core/src/ir/pass/PermutationOperationPass.cc @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PermutationOperationPass.h" + +#include "backend/Backend.h" +#include "backend/IConfig.h" +#include "ir/Graph.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +void PermutationOperationPass::callback(const OperationIndex &, Operation &node) +{ + node.accept(*this); +}; + +void PermutationOperationPass::changeToKeepLayout(const Operation &node) +{ + const auto &output_ind = node.getOutputs().at(0); + const auto &output_obj = _graph.operands().at(output_ind); + + assert(output_obj.getDef().size() == 1); + const auto &node_index = output_obj.getDef().list().front(); + const auto &op_seq_index = _lowered_graph.op_seqs().getOperation(node_index); + + const auto frontend_layout = _lowered_graph.op_seqs().at(op_seq_index).getLayout(); + const auto backend_layout = _lowered_graph.getLowerInfo(op_seq_index)->layout(); + + if (frontend_layout == backend_layout) + { + return; + } + + // CPU supports only NHWC now + if (_lowered_graph.getLowerInfo(op_seq_index)->backend()->config()->id() != "cpu") + { + // TODO Change backend of this node + assert(frontend_layout == Layout::NHWC || backend_layout == Layout::UNKNOWN); + } + + // Divide op_seq based on target operation + { + auto &prev_op_seq = _lowered_graph.op_seqs().at(op_seq_index); + + // Create new op_seq and move information from existing op_seq to new op_seq if target + // node is the end of op_seq + auto it = prev_op_seq.begin(); + // Find iterator of target node in op_seq + while ((it++)->index != node_index) + ; + if (it != prev_op_seq.end()) + { + const auto &next_op_seq_index = + _lowered_graph.op_seqs().emplace(it->index, *it->node, prev_op_seq.getLayout()); + auto &next_op_seq = _lowered_graph.op_seqs().at(next_op_seq_index); + next_op_seq.setInputs(it->node->getInputs()); + next_op_seq.setOutputs(it->node->getOutputs()); + + std::vector remove_list; + remove_list.emplace_back(it->index); + while (++it != prev_op_seq.end()) + { + next_op_seq.appendOperation(it->index, *it->node); + next_op_seq.setOutputs(it->node->getOutputs()); + remove_list.emplace_back(it->index); + } + + prev_op_seq.setOutputs(node.getOutputs()); + for (const auto &index : remove_list) + { + prev_op_seq.remove(index); + } + + const auto op_seq_li = _lowered_graph.getLowerInfo(op_seq_index); + _lowered_graph.setLowerInfo( + next_op_seq_index, + std::make_unique(op_seq_li->backend(), op_seq_li->layout())); + } + } + + // Remove target operation from op_seq and insert the target operation to new op_seq + { + const auto backend = _lowered_graph.getLowerInfo(op_seq_index)->backend(); + + // Remove target operation from op_sequence + _lowered_graph.op_seqs().removeFromOpSequence(node_index); + + if (!_lowered_graph.op_seqs().exist(op_seq_index)) + { + // Remove lowerinfo for op_seq of target operation if the op_seq does not exist + _lowered_graph.removeLowerInfo(op_seq_index); + } + else + { + // Update op_seq of target operation if the op_seq exists + auto &prev_op_seq = _lowered_graph.op_seqs().at(op_seq_index); + const auto last_node = (--prev_op_seq.end())->node; + prev_op_seq.setOutputs(last_node->getOutputs()); + } + + // Create new op_seq and set information to the op_seq + auto new_op_seq_index = _lowered_graph.op_seqs().emplace(node_index, node, frontend_layout); + auto &new_op_seq = _lowered_graph.op_seqs().at(new_op_seq_index); + new_op_seq.setInputs(node.getInputs()); + new_op_seq.setOutputs(node.getOutputs()); + _lowered_graph.setLowerInfo(new_op_seq_index, + std::make_unique(backend, frontend_layout)); + } + + // Change PermuteFactors of operands of target node + { + const auto &op_seq_index = _lowered_graph.op_seqs().getOperation(node_index); + const auto op_seq_li = _lowered_graph.getLowerInfo(op_seq_index); + const auto backend = op_seq_li->backend(); + const operand::PermuteFactor removed_factor{backend, backend_layout}; + const operand::PermuteFactor new_factor{backend, frontend_layout}; + for (const auto &input : node.getInputs()) + { + bool canRemove = true; + for (const auto &use : _graph.operands().at(input).getUses().list()) + { + if (use != node_index) + { + const auto &use_op_seq_index = _lowered_graph.op_seqs().getOperation(use); + auto use_op_seq_li = _lowered_graph.getLowerInfo(use_op_seq_index); + if (use_op_seq_li->backend() == backend && use_op_seq_li->layout() == backend_layout) + { + canRemove = false; + break; + } + } + } + + auto lower_info = _lowered_graph.getLowerInfo(input); + if (canRemove) + { + lower_info->removeUsePermuteFactor(removed_factor); + } + lower_info->addUsePermuteFactor(new_factor); + + // Whether if node's input is an input of model or a constant + if (_graph.operands().at(input).getDef().size() == 0) + { + assert(_graph.getInputs().contains(input) || _graph.operands().at(input).isConstant()); + lower_info->removeDefPermuteFactor(removed_factor); + lower_info->addDefPermuteFactor(new_factor); + } + } + + for (const auto &output : node.getOutputs()) + { + auto lower_info = _lowered_graph.getLowerInfo(output); + lower_info->removeDefPermuteFactor(removed_factor); + lower_info->addDefPermuteFactor(new_factor); + + // Whether if node's output is an output of model + if (_graph.operands().at(output).getUses().size() == 0) + { + assert(_graph.getOutputs().contains(output)); + lower_info->removeUsePermuteFactor(removed_factor); + lower_info->addUsePermuteFactor(new_factor); + } + } + } +} + +void PermutationOperationPass::visit(const operation::FullyConnected &node) +{ + const auto &input_ind = node.getInputs().at(operation::FullyConnected::Input::INPUT); + const auto &input_obj = _graph.operands().at(input_ind); + const auto &input_shape = input_obj.shape(); + + if (input_shape.rank() == 4) + { + changeToKeepLayout(node); + } +} + +void PermutationOperationPass::visit(const operation::Gather &node) +{ + const auto &input_ind = node.getInputs().at(operation::Gather::Input::INPUT); + const auto &input_obj = _graph.operands().at(input_ind); + const auto &input_shape = input_obj.shape(); + + const auto &output_ind = node.getOutputs().at(0); + const auto &output_obj = _graph.operands().at(output_ind); + const auto &output_shape = output_obj.shape(); + + if (input_shape.rank() >= 4 || output_shape.rank() >= 4) + { + changeToKeepLayout(node); + } +} + +void PermutationOperationPass::visit(const operation::Reshape &node) +{ + const auto &input_ind = node.getInputs().at(operation::Reshape::Input::INPUT); + const auto &input_obj = _graph.operands().at(input_ind); + const auto &input_shape = input_obj.shape(); + + const auto &output_ind = node.getOutputs().at(0); + const auto &output_obj = _graph.operands().at(output_ind); + const auto &output_shape = output_obj.shape(); + + if (input_shape.rank() >= 4 || output_shape.rank() >= 4) + { + changeToKeepLayout(node); + } +} + +} // namespace pass +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/pass/PermutationOperationPass.h b/runtime/onert/core/src/ir/pass/PermutationOperationPass.h new file mode 100644 index 000000000..e68065bfb --- /dev/null +++ b/runtime/onert/core/src/ir/pass/PermutationOperationPass.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_GRAPH_PASS_PERMUTATION_OPERATION_PASS_H__ +#define __ONERT_GRAPH_PASS_PERMUTATION_OPERATION_PASS_H__ + +#include "ir/OperationVisitor.h" +#include "LoweredOperationPass.h" + +namespace onert +{ +namespace ir +{ +namespace pass +{ + +class PermutationOperationPass : public LoweredOperationPass, public OperationVisitor +{ +public: + using LoweredOperationPass::LoweredOperationPass; + +public: + std::string id() final { return "PermutationOperationPass"; } + +public: + void callback(const OperationIndex &i, Operation &n) final; + +public: + void visit(const operation::FullyConnected &) final; + void visit(const operation::Gather &) final; + void visit(const operation::Reshape &) final; + +private: + void changeToKeepLayout(const Operation &); +}; + +} // namespace pass +} // namespace ir +} // namespace onert + +#endif // __ONERT_GRAPH_PASS_PERMUTATION_OPERATION_PASS_H__ diff --git a/runtime/onert/core/src/ir/verifier/Verifier.cc b/runtime/onert/core/src/ir/verifier/Verifier.cc new file mode 100644 index 000000000..c4655ee42 --- /dev/null +++ b/runtime/onert/core/src/ir/verifier/Verifier.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Verifier.h" + +#include "ir/Graph.h" +#include "ir/OperationIndexMap.h" + +#include "util/logging.h" + +namespace onert +{ +namespace ir +{ +namespace verifier +{ + +// +// DAGChecker +// + +bool DAGChecker::verify(const Graph &graph) const +{ + auto &operations = graph.operations(); + bool cyclic = false; + + OperationIndexMap visited; + operations.iterate( + [&](const OperationIndex &index, const Operation &) { visited[index] = false; }); + OperationIndexMap on_stack = visited; // Copy from visited + + std::function dfs_recursive = + [&](const OperationIndex &index, const Operation &node) -> void { + if (on_stack[index]) + cyclic = true; + if (visited[index]) + return; + visited[index] = true; + on_stack[index] = true; + + for (auto output : node.getOutputs()) + { + const auto &operand = graph.operands().at(output); + for (const auto &use : operand.getUses().list()) + { + dfs_recursive(use, graph.operations().at(use)); + } + } + + on_stack[index] = false; + }; + + operations.iterate(dfs_recursive); + + return !cyclic; +} + +// +// EdgeConsistencyVerifier +// + +bool EdgeConsistencyChecker::verify(const Graph &graph) const +{ + auto &operations = graph.operations(); + uint32_t mismatches = 0; + operations.iterate([&](const OperationIndex &index, const Operation &node) { + for (auto operand_index : node.getInputs()) + { + auto &operand = graph.operands().at(operand_index); + mismatches += (operand.getUses().contains(index) ? 0 : 1); + } + for (auto operand_index : node.getOutputs()) + { + auto &operand = graph.operands().at(operand_index); + mismatches += (operand.getDef().contains(index) ? 0 : 1); + } + }); + return mismatches == 0; +} + +} // namespace verifier +} // namespace ir +} // namespace onert diff --git a/runtime/onert/core/src/ir/verifier/Verifier.h b/runtime/onert/core/src/ir/verifier/Verifier.h new file mode 100644 index 000000000..0bc22bc47 --- /dev/null +++ b/runtime/onert/core/src/ir/verifier/Verifier.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_GRAPH_VERIFIER_VERIFIER_H__ +#define __ONERT_GRAPH_VERIFIER_VERIFIER_H__ + +namespace onert +{ +namespace ir +{ +class Graph; +} // namespace ir +} // namespace onert + +namespace onert +{ +namespace ir +{ +namespace verifier +{ + +struct IVerifier +{ + virtual ~IVerifier() = default; + virtual bool verify(const Graph &graph) const = 0; +}; + +} // namespace verifier +} // namespace ir +} // namespace onert + +namespace onert +{ +namespace ir +{ +namespace verifier +{ + +class DAGChecker : public IVerifier +{ +public: + bool verify(const Graph &graph) const override; +}; + +class EdgeConsistencyChecker : public IVerifier +{ +public: + bool verify(const Graph &graph) const override; +}; + +} // namespace verifier +} // namespace ir +} // namespace onert + +#endif // __ONERT_GRAPH_VERIFIER_VERIFIER_H__ diff --git a/runtime/onert/core/src/library_info.cc b/runtime/onert/core/src/library_info.cc new file mode 100644 index 000000000..6d7579cca --- /dev/null +++ b/runtime/onert/core/src/library_info.cc @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +volatile const char info[] = "library information : runtime=onert"; diff --git a/runtime/onert/core/src/util/ConfigSource.cc b/runtime/onert/core/src/util/ConfigSource.cc new file mode 100644 index 000000000..45cce662e --- /dev/null +++ b/runtime/onert/core/src/util/ConfigSource.cc @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/ConfigSource.h" +#include "util/GeneralConfigSource.h" +#include "util/EnvConfigSource.h" + +#include +#include +#include + +#include + +namespace onert +{ +namespace util +{ + +static std::unique_ptr _source; + +void config_source(std::unique_ptr &&source) { _source = std::move(source); } + +static IConfigSource *config_source() +{ + if (!_source) + { +#ifdef ENVVAR_FOR_DEFAULT_CONFIG + // Default ConfigSource is EnvConfigSource + _source = std::make_unique(); +#else + _source = std::make_unique(); +#endif // ENVVAR_FOR_DEFAULT_CONFIG + } + return _source.get(); +} + +static std::string getConfigOrDefault(const std::string &key) +{ + static std::unordered_map defaults; + if (defaults.empty()) + { +#define CONFIG(Name, Type, Default) \ + { \ + auto name = std::string{#Name}; \ + defaults.emplace(name, std::string{Default}); \ + } + +#include "util/Config.lst" + +#undef CONFIG + } + + // Treat empty string and absence of the value to be the same + auto ret = config_source()->get(key); + if (ret.empty()) + { + auto itr = defaults.find(key); + if (itr != defaults.end()) + { + // Return the default value if exists + ret = itr->second; + } + } + + return ret; +} + +bool toBool(const std::string &val) +{ + static const std::array false_list{"0", "OFF", "FALSE", "N", "NO"}; + auto false_found = std::find(false_list.begin(), false_list.end(), val); + return false_found == false_list.end(); +} + +int toInt(const std::string &val) { return std::stoi(val); } + +bool getConfigBool(const std::string &key) +{ + auto raw = getConfigOrDefault(key); + return toBool(raw); +} + +int getConfigInt(const std::string &key) +{ + auto raw = getConfigOrDefault(key); + return toInt(raw); +} + +std::string getConfigString(const std::string &key) { return getConfigOrDefault(key); } + +} // namespace util +} // namespace onert + +namespace onert +{ +namespace util +{ +namespace config +{ + +#define CONFIG(Name, Type, Default) const char *Name = #Name; + +#include "util/Config.lst" + +#undef CONFIG + +} // namespace config +} // namespace util +} // namespace onert diff --git a/runtime/onert/core/src/util/EnvConfigSource.cc b/runtime/onert/core/src/util/EnvConfigSource.cc new file mode 100644 index 000000000..0d25b7353 --- /dev/null +++ b/runtime/onert/core/src/util/EnvConfigSource.cc @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/EnvConfigSource.h" + +#include + +namespace onert +{ +namespace util +{ + +std::string EnvConfigSource::get(const std::string &key) const +{ + const char *value = std::getenv(key.c_str()); + if (value != nullptr) + { + return value; + } + else + { + return GeneralConfigSource::get(key); + } +} + +} // namespace util +} // namespace onert diff --git a/runtime/onert/core/src/util/EventCollectorGlobal.cc b/runtime/onert/core/src/util/EventCollectorGlobal.cc new file mode 100644 index 000000000..ab8ddab60 --- /dev/null +++ b/runtime/onert/core/src/util/EventCollectorGlobal.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/EventCollectorGlobal.h" + +#include +#include + +#include "util/ConfigSource.h" + +namespace onert +{ +namespace util +{ + +EventCollectorGlobal::EventCollectorGlobal() : _recorder{}, _collector{&_recorder} +{ + // DO NOTHING +} + +EventCollectorGlobal::~EventCollectorGlobal() +{ + if (!_recorder.empty()) + { + // TODO Need better way for saved file path than the hardcoded path + std::ofstream ofs{"trace.global.json"}; + _recorder.writeToFile(ofs); + } +} + +EventCollectorGlobal &EventCollectorGlobal::get() +{ + static EventCollectorGlobal instance; + return instance; +} + +EventDurationBlock::EventDurationBlock(const std::string &tag) : _tag{tag} +{ + auto &glob = EventCollectorGlobal::get(); + glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "0", _tag}); +} +EventDurationBlock::~EventDurationBlock() +{ + auto &glob = EventCollectorGlobal::get(); + glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::END, "0", _tag}); +} + +EventDurationManual::EventDurationManual(const std::string &tag) : _tag{tag}, _pair{true} {} + +EventDurationManual::~EventDurationManual() +{ + // Check if it has called begin-end pair + assert(_pair); +} + +void EventDurationManual::begin() +{ + _pair = false; + auto &glob = EventCollectorGlobal::get(); + glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::BEGIN, "0", _tag}); +} + +void EventDurationManual::end() +{ + assert(!_pair); + _pair = true; + auto &glob = EventCollectorGlobal::get(); + glob.collector().onEvent(EventCollector::Event{EventCollector::Edge::END, "0", _tag}); +} + +} // namespace util +} // namespace onert diff --git a/runtime/onert/core/src/util/GeneralConfigSource.cc b/runtime/onert/core/src/util/GeneralConfigSource.cc new file mode 100644 index 000000000..7d2757e58 --- /dev/null +++ b/runtime/onert/core/src/util/GeneralConfigSource.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/GeneralConfigSource.h" +#include "util/logging.h" + +namespace onert +{ +namespace util +{ + +std::string GeneralConfigSource::get(const std::string &key) const +{ + auto itr = _map.find(key); + if (itr == _map.end()) + { + return ""; + } + else + { + return itr->second; + } +} + +void GeneralConfigSource::set(const std::string &key, const std::string &val) +{ + VERBOSE(GeneralConfigSource) << key << " : " << val << std::endl; + _map[key] = val; +} + +} // namespace util +} // namespace onert diff --git a/runtime/onert/core/src/util/ShapeInference.cc b/runtime/onert/core/src/util/ShapeInference.cc new file mode 100644 index 000000000..ace16959d --- /dev/null +++ b/runtime/onert/core/src/util/ShapeInference.cc @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/Utils.h" +#include "ir/InternalType.h" +#include "ir/Shape.h" +#include "ir/operation/AvgPool2D.h" +#include "ir/operation/MaxPool2D.h" +#include "util/ShapeInference.h" + +namespace onert +{ +namespace shape_inference +{ + +// +// Helper functions +// + +namespace +{ + +template +typename std::enable_if::value && std::is_integral::value, + typename std::common_type::type>::type +ceil_div(T dividend, U divisor) +{ + assert(dividend > 0 && divisor > 0 && "this implementations is for positive numbers only"); + return (dividend + divisor - 1) / divisor; +} + +// Calculate the result of broadcast of two shapes +ir::Shape broadcastShapes(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape) +{ + ir::Shape out_shape; + auto max_rank = std::max(lhs_shape.rank(), rhs_shape.rank()); + + for (int idx = 0; idx < max_rank; ++idx) + { + // Go over operands dimensions from right to left + int lhs_idx = lhs_shape.rank() - idx - 1; + int rhs_idx = rhs_shape.rank() - idx - 1; + + int32_t lhs_dim = lhs_idx >= 0 ? lhs_shape.dim(lhs_idx) : 1; + int32_t rhs_dim = rhs_idx >= 0 ? rhs_shape.dim(rhs_idx) : 1; + + if (lhs_dim != 1 && rhs_dim != 1 && lhs_dim != rhs_dim) + throw std::runtime_error("Incompatible shapes for broadcast"); + + out_shape.prepend(std::max(lhs_dim, rhs_dim)); + } + + return out_shape; +} + +// Calculate output height and width of convolution-like operation +std::pair calcConvLikeHeightAndWidth(const int in_h, const int in_w, const int ker_h, + const int ker_w, const ir::Padding pad, + const ir::Stride stride) +{ + int32_t out_h = 0, out_w = 0; + + switch (pad.type) + { + case ir::PaddingType::SAME: + out_h = ceil_div(in_h, stride.vertical); + out_w = ceil_div(in_w, stride.horizontal); + break; + case ir::PaddingType::VALID: + out_h = ceil_div(in_h - ker_h + 1, stride.vertical); + out_w = ceil_div(in_w - ker_w + 1, stride.horizontal); + break; + case ir::PaddingType::EXPLICIT: + out_h = (in_h + pad.param.top + pad.param.bottom - ker_h) / stride.vertical + 1; + out_w = (in_w + pad.param.left + pad.param.right - ker_w) / stride.horizontal + 1; + break; + default: + assert(false); + } + + return {out_h, out_w}; +} + +} // namespace + +// +// Shape inference +// + +Shapes inferEltwiseShape(const ir::Shape &lhs_shape, const ir::Shape &rhs_shape) +{ + return {broadcastShapes(lhs_shape, rhs_shape)}; +} + +Shapes inferAvgPoolShape(const ir::Shape &in_shape, const ir::operation::AvgPool2D::Param ¶m, + const ir::Layout layout) +{ + assert(layout == ir::Layout::NHWC); + auto ifm_shape = in_shape.asFeature(layout); + const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, param.kh, param.kw, + param.padding, param.stride); + // Pooling don't change number of channels and batch size + return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, ifm_shape.C}}; +} + +Shapes inferConcatShape(const Shapes &in_shapes, const ir::operation::Concat::Param ¶m) +{ + const int32_t concat_axis = param.axis; + const auto &first_in_shape = in_shapes[0]; + + // Check that all shapes are equal except for concat axis dimension + for (const auto &in_shape : in_shapes) + { + assert(in_shape.rank() == first_in_shape.rank()); + for (int64_t dim_idx = 0; dim_idx < in_shape.rank(); ++dim_idx) + assert(dim_idx == concat_axis || in_shape.dim(dim_idx) == first_in_shape.dim(dim_idx)); + } + + // Calculate output shape + ir::Shape out_shape(first_in_shape); + out_shape.dim(concat_axis) = 0; + for (const auto &in_shape : in_shapes) + out_shape.dim(concat_axis) += in_shape.dim(concat_axis); + return {out_shape}; +} + +Shapes inferMaxPoolShape(const ir::Shape &in_shape, const ir::operation::MaxPool2D::Param ¶m, + const ir::Layout layout) +{ + assert(layout == ir::Layout::NHWC); + auto ifm_shape = in_shape.asFeature(layout); + const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, param.kh, param.kw, + param.padding, param.stride); + // Pooling don't change number of channels and batch size + return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, ifm_shape.C}}; +} + +Shapes inferConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape, + const ir::operation::Conv2D::Param ¶m, ir::Layout layout) +{ + assert(layout == ir::Layout::NHWC); + auto ifm_shape = in_shape.asFeature(layout); + + // Kernel format is [depth_out, kernel_height, kernel_width, depth_in] + auto kf_shape = ker_shape.asFeature(layout); + assert(ifm_shape.C == kf_shape.C); + + const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, kf_shape.H, kf_shape.W, + param.padding, param.stride); + + return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.N}}; +} + +Shapes inferDepthwiseConv2DShape(const ir::Shape &in_shape, const ir::Shape &ker_shape, + const ir::operation::DepthwiseConv2D::Param ¶m, + ir::Layout layout) +{ + assert(layout == ir::Layout::NHWC); + auto ifm_shape = in_shape.asFeature(layout); + + // Kernel format is [1, kernel_height, kernel_width, depth_out] + auto kf_shape = ker_shape.asFeature(layout); + assert(kf_shape.C == static_cast(ifm_shape.C * param.multiplier)); + assert(kf_shape.N == 1); + + const auto out_h_w = calcConvLikeHeightAndWidth(ifm_shape.H, ifm_shape.W, kf_shape.H, kf_shape.W, + param.padding, param.stride); + + return {ir::Shape{ifm_shape.N, out_h_w.first, out_h_w.second, kf_shape.C}}; +} + +Shapes inferFullyConnectedShape(const ir::Shape &in_shape, const ir::Shape &ker_shape) +{ + assert(in_shape.rank() >= 2); + assert(ker_shape.rank() == 2); + + const auto input_size_with_batch = in_shape.num_elements(); + const auto num_units = ker_shape.dim(0); + const auto input_size = ker_shape.dim(1); + const auto batch_size = input_size_with_batch / input_size; + assert(input_size_with_batch % input_size == 0); + + return {{ir::Shape({static_cast(batch_size), num_units})}}; +} + +/* + StaticInferer +*/ + +void StaticInferer::visit(const ir::operation::Reshape &op) +{ + const auto input_idx{op.getInputs().at(ir::operation::Reshape::Input::INPUT)}; + const auto &input = _operands.at(input_idx); + + // get mutable output operand + const auto output_idx = op.getOutputs().at(0); + ir::Operand &output = _operands.at(output_idx); + + // if input is dynamic, output also becomes dynamic + if (input.info().memAllocType() == ir::MemAllocType::DYNAMIC) + { + output.info().memAllocType(ir::MemAllocType::DYNAMIC); + return; + } + + if (op.getInputs().size() == 1) + { + // no change on output shape + return; + } + + // Let's check the second input + const auto shape_idx{op.getInputs().at(ir::operation::Reshape::Input::SHAPE)}; + const auto &shape = _operands.at(shape_idx); + + if (shape.isConstant()) + { + // if shape is from Const, TFLC put the shape of output into tensor + // no change on output shape + return; + } + + // if shape is NOT Const, set output shape to be dynamic_ + output.info().memAllocType(ir::MemAllocType::DYNAMIC); +} + +} // namespace shape_inference +} // namespace onert diff --git a/runtime/onert/core/src/util/logging.cc b/runtime/onert/core/src/util/logging.cc new file mode 100644 index 000000000..6309d25e5 --- /dev/null +++ b/runtime/onert/core/src/util/logging.cc @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/logging.h" + +onert::util::logging::Context &onert::util::logging::Context::get() noexcept +{ + static Context ctx; + return ctx; +} diff --git a/runtime/onert/frontend/CMakeLists.txt b/runtime/onert/frontend/CMakeLists.txt new file mode 100644 index 000000000..5ea6cdadd --- /dev/null +++ b/runtime/onert/frontend/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectories() diff --git a/runtime/onert/frontend/base_loader/CMakeLists.txt b/runtime/onert/frontend/base_loader/CMakeLists.txt new file mode 100644 index 000000000..921206c31 --- /dev/null +++ b/runtime/onert/frontend/base_loader/CMakeLists.txt @@ -0,0 +1,7 @@ +if(NOT BUILD_TFLITE_LOADER AND NOT BUILD_CIRCLE_LOADER) + return() +endif(NOT BUILD_TFLITE_LOADER AND NOT BUILD_CIRCLE_LOADER) + +add_library(base_loader INTERFACE) +target_include_directories(base_loader INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_link_libraries(base_loader INTERFACE onert_core) diff --git a/runtime/onert/frontend/base_loader/include/base_loader.h b/runtime/onert/frontend/base_loader/include/base_loader.h new file mode 100644 index 000000000..f87c6ea77 --- /dev/null +++ b/runtime/onert/frontend/base_loader/include/base_loader.h @@ -0,0 +1,1362 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BASE_LOADER_BASE_LOADER_H__ +#define __BASE_LOADER_BASE_LOADER_H__ + +#include "ir/Graph.h" +#include "ir/Operations.Include.h" + +#include +#include +#include +#include + +namespace onert +{ +namespace base_loader +{ + +template class BaseLoader +{ + using Verifier = typename LoaderDomain::Verifier; + using ActivationFunctionType = typename LoaderDomain::ActivationFunctionType; + using Buffer = typename LoaderDomain::Buffer; + using BuiltinOperator = typename LoaderDomain::BuiltinOperator; + using CustomOptionsFormat = typename LoaderDomain::CustomOptionsFormat; + using Model = typename LoaderDomain::Model; + using Operator = typename LoaderDomain::Operator; + using Padding = typename LoaderDomain::Padding; + using Pool2DOptions = typename LoaderDomain::Pool2DOptions; + using SubGraph = typename LoaderDomain::SubGraph; + using Tensor = typename LoaderDomain::Tensor; + using TensorType = typename LoaderDomain::TensorType; + +public: + /** + * @brief Construct a new Loader object + * + * @param graph reference on primary subgraph + */ + explicit BaseLoader(std::unique_ptr &graph) : _primary_subgraph(graph), _model{nullptr} + { + } + + /** + * @brief Load a model from file + * + * @param file_path + */ + void loadFromFile(const char *file_path); + +protected: + ~BaseLoader() = default; + + void loadModel(); + + // Helper functions + ir::Activation convertActivation(ActivationFunctionType type); + ir::DataType tensorTypeToDataType(TensorType type); + + // Create operands form tflite::Tensor + ir::OperandIndex loadOperand(const Tensor *tensor, ir::Graph &subg); + void loadOperationIO(const Operator *op, ir::OperandIndexSequence &inputs, + ir::OperandIndexSequence &outputs); + // Create operations from Operator + void loadOperation(const Operator *op, ir::Graph &subg); + // Load Strides and Paddings from options to param + template + void loadStridesAndPaddings(Param ¶m, const OptionsType *options); + // Load Pool2D param + template void loadPool2D(Param ¶m, const Pool2DOptions *options); + + // Operations + void loadConv2D(const Operator *op, ir::Graph &subg); + void loadDepthwiseConv2D(const Operator *op, ir::Graph &subg); + void loadTransposeConv(const Operator *op, ir::Graph &subg); + void loadAvgPool2D(const Operator *op, ir::Graph &subg); + void loadReshape(const Operator *op, ir::Graph &subg); + void loadSoftmax(const Operator *op, ir::Graph &subg); + void loadMaxPool2D(const Operator *op, ir::Graph &subg); + void loadConcatenation(const Operator *op, ir::Graph &subg); + void loadInstanceNorm(const Operator *op, ir::Graph &subg); + void loadFC(const Operator *op, ir::Graph &subg); + void loadAdd(const Operator *op, ir::Graph &subg); + void loadSub(const Operator *op, ir::Graph &subg); + void loadMul(const Operator *op, ir::Graph &subg); + void loadDiv(const Operator *op, ir::Graph &subg); + void loadPack(const Operator *op, ir::Graph &subg); + void loadRelu(const Operator *op, ir::Graph &subg); + void loadRelu6(const Operator *op, ir::Graph &subg); + void loadResizeBilinear(const Operator *op, ir::Graph &subg); + void loadRsqrt(const Operator *op, ir::Graph &subg); + void loadSqrt(const Operator *op, ir::Graph &subg); + void loadSquaredDifference(const Operator *op, ir::Graph &subg); + void loadTanh(const Operator *op, ir::Graph &subg); + void loadTranspose(const Operator *op, ir::Graph &subg); + void loadMean(const Operator *op, ir::Graph &subg); + void loadReduceMax(const Operator *op, ir::Graph &subg); + void loadPad(const Operator *op, ir::Graph &subg); + void loadLogistic(const Operator *op, ir::Graph &subg); + void loadExp(const Operator *op, ir::Graph &subg); + void loadGather(const Operator *op, ir::Graph &subg); + void loadCustom(const Operator *op, ir::Graph &subg); + void loadSpaceToBatchND(const Operator *op, ir::Graph &subg); + void loadBatchToSpaceND(const Operator *op, ir::Graph &subg); + void loadReduceSum(const Operator *op, ir::Graph &subg); + void loadSqueeze(const Operator *op, ir::Graph &subg); + void loadPrelu(const Operator *op, ir::Graph &subg); + void loadSplit(const Operator *op, ir::Graph &subg); + void loadSlice(const Operator *op, ir::Graph &subg); + void loadStridedSlice(const Operator *op, ir::Graph &subg); + void loadUnpack(const Operator *op, ir::Graph &subg); + void loadMinimum(const Operator *op, ir::Graph &subg); + void loadMaximum(const Operator *op, ir::Graph &subg); + void loadCast(const Operator *op, ir::Graph &subg); + void loadComparison(const Operator *op, ir::Graph &subg); + void loadOneHot(const Operator *op, ir::Graph &subg); + void loadAbs(const Operator *op, ir::Graph &subg); + void loadSin(const Operator *op, ir::Graph &subg); + void loadShape(const Operator *op, ir::Graph &subg); + +protected: + // Buffer for loading (if needed) + std::vector _buffer; + // Reference on loadable primary subgraph + std::unique_ptr &_primary_subgraph; + const Model *_model; + // Maps Tensor indices to onert Operands. + std::vector _tensor_to_operand; + // Verifier + std::unique_ptr _verifier; +}; + +template +void BaseLoader::BaseLoader::loadFromFile(const char *file_path) +{ + std::ifstream stream(file_path, std::fstream::in | std::fstream::binary); + + if (!stream) + { + std::string msg = "Failed to open file `"; + msg += file_path; + msg += "`"; + throw std::runtime_error{msg}; + } + + stream.seekg(0, stream.end); + auto size = stream.tellg(); + stream.seekg(0, stream.beg); + + _buffer.resize(size); + stream.read(_buffer.data(), size); + + stream.close(); + + // Prepare verifier + _verifier = std::make_unique(reinterpret_cast(_buffer.data()), + _buffer.size()); + + loadModel(); +} + +template +ir::Activation BaseLoader::BaseLoader::convertActivation( + const ActivationFunctionType type) +{ + switch (type) + { + case ActivationFunctionType::ActivationFunctionType_NONE: + return ir::Activation::NONE; + case ActivationFunctionType::ActivationFunctionType_RELU: + return ir::Activation::RELU; + case ActivationFunctionType::ActivationFunctionType_RELU_N1_TO_1: + return ir::Activation::RELU1; + case ActivationFunctionType::ActivationFunctionType_RELU6: + return ir::Activation::RELU6; + case ActivationFunctionType::ActivationFunctionType_TANH: + return ir::Activation::TANH; + default: + throw std::runtime_error(std::string("Unsupported activation type: ") + .append(EnumNameActivationFunctionType(type))); + } +} + +template +ir::DataType +BaseLoader::BaseLoader::tensorTypeToDataType(const TensorType type) +{ + switch (type) + { + case TensorType::TensorType_FLOAT32: + return ir::DataType::FLOAT32; + case TensorType::TensorType_INT32: + return ir::DataType::INT32; + case TensorType::TensorType_BOOL: + return ir::DataType::BOOL8; + case TensorType::TensorType_UINT8: + return ir::DataType::QUANT8_ASYMM; + default: + throw std::runtime_error( + std::string("Unsupported tensor type: ").append(EnumNameTensorType(type))); + } +} + +template +ir::OperandIndex BaseLoader::loadOperand(const Tensor *tensor, + ir::Graph &subg) +{ + ir::Shape shape; + // Shape + const auto *tensor_shape = tensor->shape(); + if (tensor_shape != nullptr) + { + for (const auto &dim : *tensor_shape) + { + shape.append(dim); + } + } + // Type + ir::DataType data_type = tensorTypeToDataType(tensor->type()); + // Quantization + auto q_params = tensor->quantization(); + float scale = 0.0; + long zero_point = 0; + if (q_params != nullptr) + { + if (q_params->scale()) + { + if (q_params->scale()->size() != 1) + { + throw std::runtime_error("Only 1 scale for a tensor is supported."); + } + scale = q_params->scale()->Get(0); + } + + if (q_params->zero_point()) + { + if (q_params->zero_point()->size() != 1) + { + throw std::runtime_error("Only 1 zero_point value for a tensor is supported."); + } + zero_point = q_params->zero_point()->Get(0); + // zero_point is long while TypeInfo.zero_point is defined as int32_t. + assert(zero_point >= std::numeric_limits::min()); + assert(zero_point <= std::numeric_limits::max()); + } + auto details = q_params->details_as_CustomQuantization(); + if (details != nullptr) + throw std::runtime_error("Custom Quantization is not supported"); + } + // Create TypeInfo + ir::TypeInfo type_info(data_type, scale, zero_point); + // Create operand + const auto operand_index = subg.addOperand(shape, type_info); + + // Constant tensors are indicated by non-empty data. + const auto *data = _model->buffers()->Get(tensor->buffer())->data(); + if (data != nullptr) + { + auto ptr = std::make_unique(data->data(), data->size()); + subg.setOperandValue(operand_index, std::move(ptr)); + } + + // Name unused + // auto name = tensor->name(); + // Variablie + if (tensor->is_variable()) + throw std::runtime_error("Variable tensor not supported!"); + + return operand_index; +} + +template +void BaseLoader::loadOperationIO(const Operator *op, + ir::OperandIndexSequence &inputs, + ir::OperandIndexSequence &outputs) +{ + for (const std::int32_t idx : *op->inputs()) + { + inputs.append(_tensor_to_operand[idx]); + } + + for (const std::int32_t idx : *op->outputs()) + { + outputs.append(_tensor_to_operand[idx]); + } +} + +template +template +void BaseLoader::loadStridesAndPaddings(Param ¶m, + const OptionsType *options) +{ + // Strides + param.stride.vertical = options->stride_w(); + param.stride.horizontal = options->stride_h(); + // Paddings + if (options->padding() == Padding::Padding_SAME) + param.padding.type = ir::PaddingType::SAME; + if (options->padding() == Padding::Padding_VALID) + param.padding.type = ir::PaddingType::VALID; + // param paddings indexes unused +} + +template +template +void BaseLoader::loadPool2D(Param ¶m, + const Pool2DOptions *options) +{ + // Strides and Paddings + loadStridesAndPaddings(param, options); + // Filter width and height + // Strides + param.kw = options->filter_width(); + param.kh = options->filter_height(); + // Activation + param.activation = convertActivation(options->fused_activation_function()); +} + +template +void BaseLoader::loadConv2D(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Conv2D::Param param; + const auto *options = op->builtin_options_as_Conv2DOptions(); + param.activation = convertActivation(options->fused_activation_function()); + loadStridesAndPaddings(param, options); + // Dilation h/w factor unused + std::unique_ptr new_op(new ir::operation::Conv2D(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadDepthwiseConv2D(const Operator *op, + ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::DepthwiseConv2D::Param param; + const auto *options = op->builtin_options_as_DepthwiseConv2DOptions(); + param.activation = convertActivation(options->fused_activation_function()); + loadStridesAndPaddings(param, options); + // Multiplier + param.multiplier = options->depth_multiplier(); + // Dilation h/w factor unused + std::unique_ptr new_op(new ir::operation::DepthwiseConv2D(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadTransposeConv(const Operator *op, + ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::TransposeConv::Param param; + const auto *options = op->builtin_options_as_TransposeConvOptions(); + loadStridesAndPaddings(param, options); + std::unique_ptr new_op(new ir::operation::TransposeConv(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadAvgPool2D(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::AvgPool2D::Param param; + const auto *options = op->builtin_options_as_Pool2DOptions(); + + loadPool2D(param, options); + + std::unique_ptr new_op(new ir::operation::AvgPool2D(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadReshape(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + // const auto *options = op->builtin_options_as_ReshapeOptions(); + // No params + + std::unique_ptr new_op(new ir::operation::Reshape(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadSoftmax(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Softmax::Param param; + const auto *options = op->builtin_options_as_SoftmaxOptions(); + // Beta + param.beta = options->beta(); + + std::unique_ptr new_op(new ir::operation::Softmax(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadMaxPool2D(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::MaxPool2D::Param param; + const auto *options = op->builtin_options_as_Pool2DOptions(); + + loadPool2D(param, options); + + std::unique_ptr new_op(new ir::operation::MaxPool2D(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadConcatenation(const Operator *op, + ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Concat::Param param; + const auto *options = op->builtin_options_as_ConcatenationOptions(); + // Axis + param.axis = options->axis(); + param.rank = subg.operands().at(outputs.at(0)).shape().rank(); + // activation unused + + std::unique_ptr new_op(new ir::operation::Concat(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadInstanceNorm(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::InstanceNorm::Param param; + const auto *options = op->builtin_options_as_InstanceNormOptions(); + + param.activation = convertActivation(options->fused_activation_function()); + // Use default value 1e-5 if value of epsilon is zero + param.epsilon = options->epsilon() == 0.f ? 1e-5 : options->epsilon(); + + std::unique_ptr new_op(new ir::operation::InstanceNorm(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadFC(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + const auto &input_operand = subg.operands().at(inputs.at(ir::operation::FullyConnected::INPUT)); + auto &weights_operand = subg.operands().at(inputs.at(ir::operation::FullyConnected::WEIGHT)); + if (input_operand.typeInfo().type() == ir::DataType::FLOAT32 && + weights_operand.typeInfo().type() == ir::DataType::QUANT8_ASYMM) + { + weights_operand.type(ir::DataType::QUANT8_SYMM); + } + + ir::operation::FullyConnected::Param param; + const auto *options = op->builtin_options_as_FullyConnectedOptions(); + + param.activation = convertActivation(options->fused_activation_function()); + // weights_format unused + + std::unique_ptr new_op(new ir::operation::FullyConnected(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadAdd(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Add::Param param; + const auto *options = op->builtin_options_as_AddOptions(); + + param.activation = convertActivation(options->fused_activation_function()); + + std::unique_ptr new_op(new ir::operation::Add(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadSub(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Sub::Param param; + const auto *options = op->builtin_options_as_SubOptions(); + + param.activation = convertActivation(options->fused_activation_function()); + + std::unique_ptr new_op(new ir::operation::Sub(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadMul(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Mul::Param param; + const auto *options = op->builtin_options_as_MulOptions(); + + param.activation = convertActivation(options->fused_activation_function()); + + std::unique_ptr new_op(new ir::operation::Mul(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadDiv(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Div::Param param; + const auto *options = op->builtin_options_as_DivOptions(); + + param.activation = convertActivation(options->fused_activation_function()); + + std::unique_ptr new_op(new ir::operation::Div(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadPack(const Operator *op, ir::Graph &subg) +{ + // This runtime_error will be removed if the one of backend supports this operation + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Pack::Param param; + const auto *options = op->builtin_options_as_PackOptions(); + param.num = options->values_count(); + param.axis = options->axis(); + param.rank = subg.operands().at(outputs.at(0)).shape().rank(); + + std::unique_ptr new_op(new ir::operation::Pack(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadRelu(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::ReLU(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadRelu6(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::ReLU6(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadResizeBilinear(const Operator *op, + ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + auto input = inputs.at(0); + auto size = inputs.at(1); + + // FIXME Handle ResizeBilinearOptions. + if (!subg.operands().at(size).isConstant()) + throw std::runtime_error("ResizeBilinear: non-constant 'size' is not supported."); + + std::vector size_v = subg.operands().at(size).template asVector(); + + ir::operation::ResizeBilinear::Param param; + param.height_out = size_v[0]; + param.width_out = size_v[1]; + + std::unique_ptr new_op(new ir::operation::ResizeBilinear({input}, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadRsqrt(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::RSQRT(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadSqrt(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::SQRT(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadSquaredDifference(const Operator *op, + ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::SquaredDifference(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadTanh(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::Tanh(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadTranspose(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + auto input = inputs.at(0); + auto perm = inputs.at(1); + + if (!subg.operands().at(perm).isConstant()) + throw std::runtime_error("Transpose: non-constant 'perm' is not supported."); + + ir::operation::Transpose::Param param; + param.perm = subg.operands().at(perm).template asVector(); + param.rank = subg.operands().at(inputs.at(0)).shape().rank(); + + std::unique_ptr new_op(new ir::operation::Transpose({input}, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadMean(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + auto input = inputs.at(0); + auto axes = inputs.at(1); + + if (!subg.operands().at(axes).isConstant()) + throw std::runtime_error("Mean: non-constant 'axes' is not supported."); + + ir::operation::Mean::Param param; + param.axes = subg.operands().at(axes).template asVector(); + param.keep_dims = op->builtin_options_as_ReducerOptions()->keep_dims(); + param.rank = subg.operands().at(inputs.at(0)).shape().rank(); + + std::unique_ptr new_op(new ir::operation::Mean({input}, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadReduceMax(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + auto input = inputs.at(0); + auto axes = inputs.at(1); + + // FIXME Handle ReducerOptions. + if (!subg.operands().at(axes).isConstant()) + throw std::runtime_error("ReduceSum: non-constant 'axes' is not supported."); + + ir::operation::ReduceMax::Param param; + param.axes = subg.operands().at(axes).template asVector(); + param.keep_dims = op->builtin_options_as_ReducerOptions()->keep_dims(); + param.rank = subg.operands().at(inputs.at(0)).shape().rank(); + + std::unique_ptr new_op(new ir::operation::ReduceMax({input}, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadPad(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Pad::Param param; + param.rank = subg.operands().at(inputs.at(0)).shape().rank(); + + std::unique_ptr new_op(new ir::operation::Pad(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadLogistic(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::Logistic(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadExp(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::Exp(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadGather(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + ir::operation::Gather::Param param; + param.axis = op->builtin_options_as_GatherOptions()->axis(); + param.rank = subg.operands().at(inputs.at(0)).shape().rank(); + + std::unique_ptr new_op(new ir::operation::Gather(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadSpaceToBatchND(const Operator *op, + ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op{new ir::operation::SpaceToBatchND{inputs, outputs}}; + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadBatchToSpaceND(const Operator *op, + ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + auto input = inputs.at(0); + auto block_shape = inputs.at(1); + auto crops = inputs.at(2); + + if (!subg.operands().at(crops).isConstant()) + throw std::runtime_error("BatchToSpaceND: non-constant 'crops' is not supported."); + + std::vector crops_v = subg.operands().at(crops).template asVector(); + assert(crops_v.size() == 4); + if (crops_v != std::vector{0, 0, 0, 0}) + throw std::runtime_error("BatchToSpaceND: 'crops' other than {0, 0, 0, 0} is not supported."); + + std::unique_ptr new_op{ + new ir::operation::BatchToSpaceND{{input, block_shape}, outputs}}; + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadReduceSum(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + auto input = inputs.at(0); + auto axes = inputs.at(1); + + // FIXME Handle ReducerOptions. + if (!subg.operands().at(axes).isConstant()) + throw std::runtime_error("ReduceSum: non-constant 'axes' is not supported."); + + ir::operation::ReduceSum::Param param; + param.axes = subg.operands().at(axes).template asVector(); + param.keep_dims = op->builtin_options_as_ReducerOptions()->keep_dims(); + param.rank = subg.operands().at(inputs.at(0)).shape().rank(); + + std::unique_ptr new_op{new ir::operation::ReduceSum{{input}, outputs, param}}; + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadCustom(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + auto *op_code = _model->operator_codes()->Get(op->opcode_index()); + auto custom_op_id = op_code->custom_code()->str(); + + auto constraint = ir::OperandConstraint::createExact(inputs.size()); + + assert(op->custom_options_format() == CustomOptionsFormat::CustomOptionsFormat_FLEXBUFFERS && + "Unsupported custom operation options format"); + + size_t custom_op_data_size = op->custom_options()->size(); + auto custom_op_data = new char[custom_op_data_size]; + std::copy(op->custom_options()->begin(), op->custom_options()->end(), custom_op_data); + + ir::operation::Custom::Userdata userdata{}; + userdata.data = custom_op_data; + userdata.size = custom_op_data_size; + + auto new_op = + std::make_unique(constraint, inputs, outputs, custom_op_id, userdata); + + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadSqueeze(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Squeeze::Param param{}; + const auto *options = op->builtin_options_as_SqueezeOptions(); + const auto *dims = options->squeeze_dims(); + if (dims) + { + if (dims->Length() > sizeof(param.dims) / sizeof(param.dims[0])) + throw std::runtime_error("Squeeze: 'param.ndims' is out of range."); + param.ndim = dims->Length(); + for (int i = 0; i < param.ndim; ++i) + param.dims[i] = dims->Get(i); + } + + std::unique_ptr new_op(new ir::operation::Squeeze(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadPrelu(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::PReLU(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadSplit(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + // Notice : input order is strange for tflite split + auto input = inputs.at(1); + auto axis = inputs.at(0); + + // FIXME Handle SplitOptions. + if (!subg.operands().at(axis).isConstant()) + throw std::runtime_error("Split: non-constant 'axis' is not supported."); + + ir::operation::Split::Param param{}; + param.axis = subg.operands().at(axis).template asScalar(); + const auto *options = op->builtin_options_as_SplitOptions(); + param.num_splits = options->num_splits(); + param.rank = subg.operands().at(input).shape().rank(); + + std::unique_ptr new_op(new ir::operation::Split({input}, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadSlice(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Slice::Param param; + param.rank = subg.operands().at(inputs.at(0)).shape().rank(); + + std::unique_ptr new_op{new ir::operation::Slice{inputs, outputs, param}}; + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadStridedSlice(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::StridedSlice::Param param; + + const auto *options = op->builtin_options_as_StridedSliceOptions(); + param.begin_mask = options->begin_mask(); + param.end_mask = options->end_mask(); + param.shrink_axis_mask = options->shrink_axis_mask(); + param.rank = subg.operands().at(inputs.at(0)).shape().rank(); + + std::unique_ptr new_op{new ir::operation::StridedSlice{inputs, outputs, param}}; + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadUnpack(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Unpack::Param param; + const auto *options = op->builtin_options_as_UnpackOptions(); + param.num = options->num(); + param.axis = options->axis(); + param.rank = subg.operands().at(inputs.at(0)).shape().rank(); + + std::unique_ptr new_op(new ir::operation::Unpack(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadMinimum(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::Min(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadMaximum(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::Max(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadCast(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + auto qasymm8ToUint8 = [](ir::Operand &operand) { + if (operand.typeInfo().type() == ir::DataType::QUANT8_ASYMM) + { + operand.type(ir::DataType::UINT8); + } + }; + qasymm8ToUint8(subg.operands().at(inputs.at(ir::operation::Cast::Input::INPUT))); + qasymm8ToUint8(subg.operands().at(outputs.at(0))); + + std::unique_ptr new_op(new ir::operation::Cast(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadComparison(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + ir::operation::Comparison::Param param; + + const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code(); + + switch (builtin_op) + { + case BuiltinOperator::BuiltinOperator_EQUAL: + param.comparison_type = ir::operation::Comparison::ComparisonType::Equal; + break; + case BuiltinOperator::BuiltinOperator_NOT_EQUAL: + param.comparison_type = ir::operation::Comparison::ComparisonType::NotEqual; + break; + case BuiltinOperator::BuiltinOperator_GREATER_EQUAL: + param.comparison_type = ir::operation::Comparison::ComparisonType::GreaterEqual; + break; + case BuiltinOperator::BuiltinOperator_GREATER: + param.comparison_type = ir::operation::Comparison::ComparisonType::Greater; + break; + case BuiltinOperator::BuiltinOperator_LESS_EQUAL: + param.comparison_type = ir::operation::Comparison::ComparisonType::LessEqual; + break; + case BuiltinOperator::BuiltinOperator_LESS: + param.comparison_type = ir::operation::Comparison::ComparisonType::Less; + break; + default: + throw std::runtime_error( + std::string("Unsupported operation: ").append(EnumNameBuiltinOperator(builtin_op))); + } + + std::unique_ptr new_op(new ir::operation::Comparison(inputs, outputs, param)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadOneHot(const Operator *op, ir::Graph &subg) +{ + if (op->inputs()->size() != 4 || op->outputs()->size() != 1) + throw std::runtime_error("OneHot Op has wrong number of input or output tensors."); + + enum + { + INDICES = 0, + DEPTH = 1, + ON_VALUE = 2, + OFF_VALUE = 3, + }; + + // Set input and output tensors + ir::OperandIndexSequence inputs, outputs; + inputs.append(_tensor_to_operand[op->inputs()->Get(INDICES)]); + outputs.append(_tensor_to_operand[op->outputs()->Get(0)]); + + // Set parameters + // depth, on_value and off_value are scalar though it is passed as inputs + auto depth_opidx = _tensor_to_operand[op->inputs()->Get(DEPTH)]; + auto on_value_opidx = _tensor_to_operand[op->inputs()->Get(ON_VALUE)]; + auto off_value_opidx = _tensor_to_operand[op->inputs()->Get(OFF_VALUE)]; + const auto depth = subg.operands().at(depth_opidx).template asScalar(); + const auto on_value = subg.operands().at(on_value_opidx).template asScalar(); + const auto off_value = subg.operands().at(off_value_opidx).template asScalar(); + const auto axis = op->builtin_options_as_OneHotOptions()->axis(); + std::unique_ptr new_op( + new ir::operation::OneHot(inputs, outputs, {depth, on_value, off_value, axis})); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadAbs(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::Abs(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadSin(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + std::unique_ptr new_op(new ir::operation::Sin(inputs, outputs)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadShape(const Operator *op, ir::Graph &subg) +{ + ir::OperandIndexSequence inputs; + ir::OperandIndexSequence outputs; + + loadOperationIO(op, inputs, outputs); + + // ir::operation::Shape::Param param; + // const auto *options = op->builtin_options_as_ShapeOptions(); + // param.out_type = tensorTypeToDataType(options->out_type()); + + std::unique_ptr new_op(new ir::operation::Shape(inputs, outputs /*, param*/)); + subg.addOperation(std::move(new_op)); +} + +template +void BaseLoader::loadOperation(const Operator *op, ir::Graph &subg) +{ + const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code(); + + switch (builtin_op) + { + case BuiltinOperator::BuiltinOperator_CONV_2D: + loadConv2D(op, subg); + return; + case BuiltinOperator::BuiltinOperator_AVERAGE_POOL_2D: + loadAvgPool2D(op, subg); + return; + case BuiltinOperator::BuiltinOperator_DEPTHWISE_CONV_2D: + loadDepthwiseConv2D(op, subg); + return; + case BuiltinOperator::BuiltinOperator_TRANSPOSE_CONV: + loadTransposeConv(op, subg); + return; + case BuiltinOperator::BuiltinOperator_RESHAPE: + loadReshape(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SOFTMAX: + loadSoftmax(op, subg); + return; + case BuiltinOperator::BuiltinOperator_MAX_POOL_2D: + loadMaxPool2D(op, subg); + return; + case BuiltinOperator::BuiltinOperator_CONCATENATION: + loadConcatenation(op, subg); + return; + case BuiltinOperator::BuiltinOperator_FULLY_CONNECTED: + loadFC(op, subg); + return; + case BuiltinOperator::BuiltinOperator_ADD: + loadAdd(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SUB: + loadSub(op, subg); + return; + case BuiltinOperator::BuiltinOperator_MUL: + loadMul(op, subg); + return; + case BuiltinOperator::BuiltinOperator_DIV: + loadDiv(op, subg); + return; + case BuiltinOperator::BuiltinOperator_PACK: + loadPack(op, subg); + return; + case BuiltinOperator::BuiltinOperator_RELU: + loadRelu(op, subg); + return; + case BuiltinOperator::BuiltinOperator_RELU6: + loadRelu6(op, subg); + return; + case BuiltinOperator::BuiltinOperator_RESIZE_BILINEAR: + loadResizeBilinear(op, subg); + return; + case BuiltinOperator::BuiltinOperator_RSQRT: + loadRsqrt(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SQRT: + loadSqrt(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SQUARED_DIFFERENCE: + loadSquaredDifference(op, subg); + return; + case BuiltinOperator::BuiltinOperator_TANH: + loadTanh(op, subg); + return; + case BuiltinOperator::BuiltinOperator_TRANSPOSE: + loadTranspose(op, subg); + return; + case BuiltinOperator::BuiltinOperator_MEAN: + loadMean(op, subg); + return; + case BuiltinOperator::BuiltinOperator_REDUCE_MAX: + loadReduceMax(op, subg); + return; + case BuiltinOperator::BuiltinOperator_PAD: + loadPad(op, subg); + return; + case BuiltinOperator::BuiltinOperator_LOGISTIC: + loadLogistic(op, subg); + return; + case BuiltinOperator::BuiltinOperator_EXP: + loadExp(op, subg); + return; + case BuiltinOperator::BuiltinOperator_GATHER: + loadGather(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SPACE_TO_BATCH_ND: + loadSpaceToBatchND(op, subg); + return; + case BuiltinOperator::BuiltinOperator_BATCH_TO_SPACE_ND: + loadBatchToSpaceND(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SUM: + loadReduceSum(op, subg); + return; + case BuiltinOperator::BuiltinOperator_CUSTOM: + loadCustom(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SQUEEZE: + loadSqueeze(op, subg); + return; + case BuiltinOperator::BuiltinOperator_PRELU: + loadPrelu(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SPLIT: + loadSplit(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SLICE: + loadSlice(op, subg); + return; + case BuiltinOperator::BuiltinOperator_STRIDED_SLICE: + loadStridedSlice(op, subg); + return; + case BuiltinOperator::BuiltinOperator_UNPACK: + loadUnpack(op, subg); + return; + case BuiltinOperator::BuiltinOperator_MINIMUM: + loadMinimum(op, subg); + return; + case BuiltinOperator::BuiltinOperator_MAXIMUM: + loadMaximum(op, subg); + return; + case BuiltinOperator::BuiltinOperator_CAST: + loadCast(op, subg); + return; + case BuiltinOperator::BuiltinOperator_EQUAL: + case BuiltinOperator::BuiltinOperator_NOT_EQUAL: + case BuiltinOperator::BuiltinOperator_GREATER_EQUAL: + case BuiltinOperator::BuiltinOperator_GREATER: + case BuiltinOperator::BuiltinOperator_LESS_EQUAL: + case BuiltinOperator::BuiltinOperator_LESS: + loadComparison(op, subg); + return; + case BuiltinOperator::BuiltinOperator_ONE_HOT: + loadOneHot(op, subg); + return; + case BuiltinOperator::BuiltinOperator_ABS: + loadAbs(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SIN: + loadSin(op, subg); + return; + case BuiltinOperator::BuiltinOperator_SHAPE: + loadShape(op, subg); + return; + // TODO Implement loading subgraphs of conftrol flow ops + default: + throw std::runtime_error( + std::string("Unsupported operation: ").append(EnumNameBuiltinOperator(builtin_op))); + } +} + +template +void BaseLoader::loadModel() +{ + LoaderDomain::VerifyModelBuffer(*_verifier.get()); + _model = LoaderDomain::GetModel(_buffer.data()); + // Version unused + // const auto version = _model->version(); + // Description unused + // const auto *description = _model->description(); + // Metabuffer unsued + // const auto *metadata_buffer = _model->metadata_buffer(); + // Load subgraphs recursively from primary subgraph and map operations on subgraph + const auto domain_subgraph = (*_model->subgraphs())[0]; + _primary_subgraph = static_cast(this)->loadSubgraph(domain_subgraph); +} + +} // namespace base_loader +} // namespace onert + +#endif //__BASE_LOADER_BASE_LOADER_H__ diff --git a/runtime/onert/frontend/circle/CMakeLists.txt b/runtime/onert/frontend/circle/CMakeLists.txt new file mode 100644 index 000000000..b446e694a --- /dev/null +++ b/runtime/onert/frontend/circle/CMakeLists.txt @@ -0,0 +1,17 @@ +if (NOT BUILD_CIRCLE_LOADER) + return() +endif () + +nnfw_find_package(FlatBuffersSource REQUIRED) + +set(CIRCLE_LOADER_SOURCES src/circle_loader.cc) + +add_library(circle_loader SHARED ${CIRCLE_LOADER_SOURCES}) + +target_include_directories(circle_loader PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(circle_loader PRIVATE ${FlatBuffersSource_DIR}/include) + +target_link_libraries(circle_loader PUBLIC onert_core) +target_link_libraries(circle_loader PRIVATE base_loader nnfw_common nnfw_coverage) + +install(TARGETS circle_loader DESTINATION lib) diff --git a/runtime/onert/frontend/circle/include/circle_loader.h b/runtime/onert/frontend/circle/include/circle_loader.h new file mode 100644 index 000000000..718bc0b65 --- /dev/null +++ b/runtime/onert/frontend/circle/include/circle_loader.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CIRCLE_CIRCLE_LOADER_H__ +#define __CIRCLE_CIRCLE_LOADER_H__ + +#include "ir/Graph.h" + +#include + +namespace onert +{ +namespace circle_loader +{ +std::unique_ptr loadModel(const char *filename); +} // namespace circle_loader +} // namespace onert + +#endif // __CIRCLE_CIRCLE_LOADER_H__ diff --git a/runtime/onert/frontend/circle/src/circle_loader.cc b/runtime/onert/frontend/circle/src/circle_loader.cc new file mode 100644 index 000000000..49aaccc4c --- /dev/null +++ b/runtime/onert/frontend/circle/src/circle_loader.cc @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "circle_loader.h" +#include "base_loader.h" +#include "circle_schema_generated.h" + +namespace onert +{ +namespace circle_loader +{ + +namespace +{ + +ir::Layout convertDataFormat(circle::DataFormat data_format) +{ + switch (data_format) + { + case circle::DataFormat::DataFormat_CHANNELS_FIRST: + return ir::Layout::NCHW; + case circle::DataFormat::DataFormat_CHANNELS_LAST: + return ir::Layout::NHWC; + default: + throw std::runtime_error("Unsupported DataFormat"); + } +} + +struct LoaderDomain +{ + using Verifier = flatbuffers::Verifier; + using ActivationFunctionType = circle::ActivationFunctionType; + using Buffer = circle::Buffer; + using BuiltinOperator = circle::BuiltinOperator; + using CustomOptionsFormat = circle::CustomOptionsFormat; + using Model = circle::Model; + using Operator = circle::Operator; + using Padding = circle::Padding; + using Pool2DOptions = circle::Pool2DOptions; + using Tensor = circle::Tensor; + using TensorType = circle::TensorType; + using SubGraph = circle::SubGraph; + + static const char *EnumNameBuiltinOperator(BuiltinOperator e) + { + return circle::EnumNameBuiltinOperator(e); + } + static const char *EnumNameActivationFunctionType(ActivationFunctionType e) + { + return circle::EnumNameActivationFunctionType(e); + } + static const char *EnumNameTensorType(TensorType e) { return circle::EnumNameTensorType(e); } + static const Model *GetModel(const void *buf) { return circle::GetModel(buf); } + static bool VerifyModelBuffer(Verifier &verifier) { return circle::VerifyModelBuffer(verifier); } +}; + +class CircleLoader final : public base_loader::BaseLoader +{ +public: + using BaseLoader::BaseLoader; + + std::unique_ptr loadSubgraph(const circle::SubGraph *circle_subg) + { + auto subg = std::make_unique(); + // Load tensors + _tensor_to_operand.resize(circle_subg->tensors()->size()); + for (flatbuffers::uoffset_t i = 0; i < circle_subg->tensors()->size(); ++i) + { + _tensor_to_operand[i] = loadOperand(circle_subg->tensors()->Get(i), *subg); + } + // Set inputs + for (const std::int32_t input_ind : *circle_subg->inputs()) + { + subg->addInput(_tensor_to_operand[input_ind]); + } + // Set outputs + for (const std::int32_t output_ind : *circle_subg->outputs()) + { + subg->addOutput(_tensor_to_operand[output_ind]); + } + // Create operations + for (const auto *op : *circle_subg->operators()) + { + CircleLoader::loadOperation(op, *subg); + } + + subg->setLayout(convertDataFormat(circle_subg->data_format())); + + subg->finishBuilding(); + + return subg; + } + + void loadOperation(const circle::Operator *op, ir::Graph &subg) + { + const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code(); + + switch (builtin_op) + { + case circle::BuiltinOperator::BuiltinOperator_INSTANCE_NORM: + loadInstanceNorm(op, subg); + return; + default: + BaseLoader::loadOperation(op, subg); + return; + } + } +}; + +} // namespace + +std::unique_ptr loadModel(const char *filename) +{ + auto primary_subgraph = std::make_unique(); + CircleLoader loader(primary_subgraph); + loader.loadFromFile(filename); + return primary_subgraph; +} + +} // namespace circle_loader +} // namespace onert diff --git a/runtime/onert/frontend/circle/src/circle_schema_generated.h b/runtime/onert/frontend/circle/src/circle_schema_generated.h new file mode 100644 index 000000000..b1337f20d --- /dev/null +++ b/runtime/onert/frontend/circle/src/circle_schema_generated.h @@ -0,0 +1,9952 @@ +/* + * Copyright (c) 2019-2020 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2018 The TensorFlow Authors. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// automatically generated by the FlatBuffers compiler, do not modify + +#ifndef FLATBUFFERS_GENERATED_CIRCLESCHEMA_CIRCLE_H_ +#define FLATBUFFERS_GENERATED_CIRCLESCHEMA_CIRCLE_H_ + +#include "flatbuffers/flatbuffers.h" + +namespace circle +{ + +struct CustomQuantization; + +struct QuantizationParameters; + +struct Int32Vector; + +struct Uint16Vector; + +struct Uint8Vector; + +struct DimensionMetadata; + +struct SparsityParameters; + +struct Tensor; + +struct Conv2DOptions; + +struct Pool2DOptions; + +struct DepthwiseConv2DOptions; + +struct ConcatEmbeddingsOptions; + +struct LSHProjectionOptions; + +struct SVDFOptions; + +struct RNNOptions; + +struct SequenceRNNOptions; + +struct BidirectionalSequenceRNNOptions; + +struct FullyConnectedOptions; + +struct SoftmaxOptions; + +struct ConcatenationOptions; + +struct AddOptions; + +struct MulOptions; + +struct L2NormOptions; + +struct LocalResponseNormalizationOptions; + +struct LSTMOptions; + +struct UnidirectionalSequenceLSTMOptions; + +struct BidirectionalSequenceLSTMOptions; + +struct ResizeBilinearOptions; + +struct ResizeNearestNeighborOptions; + +struct CallOptions; + +struct PadOptions; + +struct PadV2Options; + +struct ReshapeOptions; + +struct SpaceToBatchNDOptions; + +struct BatchToSpaceNDOptions; + +struct SkipGramOptions; + +struct SpaceToDepthOptions; + +struct DepthToSpaceOptions; + +struct SubOptions; + +struct DivOptions; + +struct TopKV2Options; + +struct EmbeddingLookupSparseOptions; + +struct GatherOptions; + +struct TransposeOptions; + +struct ExpOptions; + +struct CosOptions; + +struct ReducerOptions; + +struct SqueezeOptions; + +struct SplitOptions; + +struct SplitVOptions; + +struct StridedSliceOptions; + +struct LogSoftmaxOptions; + +struct CastOptions; + +struct DequantizeOptions; + +struct MaximumMinimumOptions; + +struct TileOptions; + +struct ArgMaxOptions; + +struct ArgMinOptions; + +struct GreaterOptions; + +struct GreaterEqualOptions; + +struct LessOptions; + +struct LessEqualOptions; + +struct NegOptions; + +struct SelectOptions; + +struct SliceOptions; + +struct TransposeConvOptions; + +struct ExpandDimsOptions; + +struct SparseToDenseOptions; + +struct EqualOptions; + +struct NotEqualOptions; + +struct ShapeOptions; + +struct RankOptions; + +struct PowOptions; + +struct FakeQuantOptions; + +struct PackOptions; + +struct LogicalOrOptions; + +struct OneHotOptions; + +struct AbsOptions; + +struct HardSwishOptions; + +struct LogicalAndOptions; + +struct LogicalNotOptions; + +struct UnpackOptions; + +struct FloorDivOptions; + +struct SquareOptions; + +struct ZerosLikeOptions; + +struct FillOptions; + +struct FloorModOptions; + +struct RangeOptions; + +struct LeakyReluOptions; + +struct SquaredDifferenceOptions; + +struct MirrorPadOptions; + +struct UniqueOptions; + +struct ReverseV2Options; + +struct AddNOptions; + +struct GatherNdOptions; + +struct WhereOptions; + +struct ReverseSequenceOptions; + +struct MatrixDiagOptions; + +struct QuantizeOptions; + +struct MatrixSetDiagOptions; + +struct IfOptions; + +struct WhileOptions; + +struct NonMaxSuppressionV4Options; + +struct NonMaxSuppressionV5Options; + +struct ScatterNdOptions; + +struct SelectV2Options; + +struct DensifyOptions; + +struct SegmentSumOptions; + +struct BatchMatMulOptions; + +struct InstanceNormOptions; + +struct OperatorCode; + +struct Operator; + +struct SubGraph; + +struct Buffer; + +struct Metadata; + +struct Model; + +enum TensorType +{ + TensorType_FLOAT32 = 0, + TensorType_FLOAT16 = 1, + TensorType_INT32 = 2, + TensorType_UINT8 = 3, + TensorType_INT64 = 4, + TensorType_STRING = 5, + TensorType_BOOL = 6, + TensorType_INT16 = 7, + TensorType_COMPLEX64 = 8, + TensorType_INT8 = 9, + TensorType_FLOAT64 = 10, + TensorType_MIN = TensorType_FLOAT32, + TensorType_MAX = TensorType_FLOAT64 +}; + +inline const TensorType (&EnumValuesTensorType())[11] +{ + static const TensorType values[] = {TensorType_FLOAT32, TensorType_FLOAT16, TensorType_INT32, + TensorType_UINT8, TensorType_INT64, TensorType_STRING, + TensorType_BOOL, TensorType_INT16, TensorType_COMPLEX64, + TensorType_INT8, TensorType_FLOAT64}; + return values; +} + +inline const char *const *EnumNamesTensorType() +{ + static const char *const names[] = {"FLOAT32", "FLOAT16", "INT32", "UINT8", + "INT64", "STRING", "BOOL", "INT16", + "COMPLEX64", "INT8", "FLOAT64", nullptr}; + return names; +} + +inline const char *EnumNameTensorType(TensorType e) +{ + const size_t index = static_cast(e); + return EnumNamesTensorType()[index]; +} + +enum QuantizationDetails +{ + QuantizationDetails_NONE = 0, + QuantizationDetails_CustomQuantization = 1, + QuantizationDetails_MIN = QuantizationDetails_NONE, + QuantizationDetails_MAX = QuantizationDetails_CustomQuantization +}; + +inline const QuantizationDetails (&EnumValuesQuantizationDetails())[2] +{ + static const QuantizationDetails values[] = {QuantizationDetails_NONE, + QuantizationDetails_CustomQuantization}; + return values; +} + +inline const char *const *EnumNamesQuantizationDetails() +{ + static const char *const names[] = {"NONE", "CustomQuantization", nullptr}; + return names; +} + +inline const char *EnumNameQuantizationDetails(QuantizationDetails e) +{ + const size_t index = static_cast(e); + return EnumNamesQuantizationDetails()[index]; +} + +template struct QuantizationDetailsTraits +{ + static const QuantizationDetails enum_value = QuantizationDetails_NONE; +}; + +template <> struct QuantizationDetailsTraits +{ + static const QuantizationDetails enum_value = QuantizationDetails_CustomQuantization; +}; + +bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj, + QuantizationDetails type); +bool VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types); + +enum DimensionType +{ + DimensionType_DENSE = 0, + DimensionType_SPARSE_CSR = 1, + DimensionType_MIN = DimensionType_DENSE, + DimensionType_MAX = DimensionType_SPARSE_CSR +}; + +inline const DimensionType (&EnumValuesDimensionType())[2] +{ + static const DimensionType values[] = {DimensionType_DENSE, DimensionType_SPARSE_CSR}; + return values; +} + +inline const char *const *EnumNamesDimensionType() +{ + static const char *const names[] = {"DENSE", "SPARSE_CSR", nullptr}; + return names; +} + +inline const char *EnumNameDimensionType(DimensionType e) +{ + const size_t index = static_cast(e); + return EnumNamesDimensionType()[index]; +} + +enum SparseIndexVector +{ + SparseIndexVector_NONE = 0, + SparseIndexVector_Int32Vector = 1, + SparseIndexVector_Uint16Vector = 2, + SparseIndexVector_Uint8Vector = 3, + SparseIndexVector_MIN = SparseIndexVector_NONE, + SparseIndexVector_MAX = SparseIndexVector_Uint8Vector +}; + +inline const SparseIndexVector (&EnumValuesSparseIndexVector())[4] +{ + static const SparseIndexVector values[] = {SparseIndexVector_NONE, SparseIndexVector_Int32Vector, + SparseIndexVector_Uint16Vector, + SparseIndexVector_Uint8Vector}; + return values; +} + +inline const char *const *EnumNamesSparseIndexVector() +{ + static const char *const names[] = {"NONE", "Int32Vector", "Uint16Vector", "Uint8Vector", + nullptr}; + return names; +} + +inline const char *EnumNameSparseIndexVector(SparseIndexVector e) +{ + const size_t index = static_cast(e); + return EnumNamesSparseIndexVector()[index]; +} + +template struct SparseIndexVectorTraits +{ + static const SparseIndexVector enum_value = SparseIndexVector_NONE; +}; + +template <> struct SparseIndexVectorTraits +{ + static const SparseIndexVector enum_value = SparseIndexVector_Int32Vector; +}; + +template <> struct SparseIndexVectorTraits +{ + static const SparseIndexVector enum_value = SparseIndexVector_Uint16Vector; +}; + +template <> struct SparseIndexVectorTraits +{ + static const SparseIndexVector enum_value = SparseIndexVector_Uint8Vector; +}; + +bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj, + SparseIndexVector type); +bool VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types); + +enum BuiltinOperator +{ + BuiltinOperator_ADD = 0, + BuiltinOperator_AVERAGE_POOL_2D = 1, + BuiltinOperator_CONCATENATION = 2, + BuiltinOperator_CONV_2D = 3, + BuiltinOperator_DEPTHWISE_CONV_2D = 4, + BuiltinOperator_DEPTH_TO_SPACE = 5, + BuiltinOperator_DEQUANTIZE = 6, + BuiltinOperator_EMBEDDING_LOOKUP = 7, + BuiltinOperator_FLOOR = 8, + BuiltinOperator_FULLY_CONNECTED = 9, + BuiltinOperator_HASHTABLE_LOOKUP = 10, + BuiltinOperator_L2_NORMALIZATION = 11, + BuiltinOperator_L2_POOL_2D = 12, + BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION = 13, + BuiltinOperator_LOGISTIC = 14, + BuiltinOperator_LSH_PROJECTION = 15, + BuiltinOperator_LSTM = 16, + BuiltinOperator_MAX_POOL_2D = 17, + BuiltinOperator_MUL = 18, + BuiltinOperator_RELU = 19, + BuiltinOperator_RELU_N1_TO_1 = 20, + BuiltinOperator_RELU6 = 21, + BuiltinOperator_RESHAPE = 22, + BuiltinOperator_RESIZE_BILINEAR = 23, + BuiltinOperator_RNN = 24, + BuiltinOperator_SOFTMAX = 25, + BuiltinOperator_SPACE_TO_DEPTH = 26, + BuiltinOperator_SVDF = 27, + BuiltinOperator_TANH = 28, + BuiltinOperator_CONCAT_EMBEDDINGS = 29, + BuiltinOperator_SKIP_GRAM = 30, + BuiltinOperator_CALL = 31, + BuiltinOperator_CUSTOM = 32, + BuiltinOperator_EMBEDDING_LOOKUP_SPARSE = 33, + BuiltinOperator_PAD = 34, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN = 35, + BuiltinOperator_GATHER = 36, + BuiltinOperator_BATCH_TO_SPACE_ND = 37, + BuiltinOperator_SPACE_TO_BATCH_ND = 38, + BuiltinOperator_TRANSPOSE = 39, + BuiltinOperator_MEAN = 40, + BuiltinOperator_SUB = 41, + BuiltinOperator_DIV = 42, + BuiltinOperator_SQUEEZE = 43, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + BuiltinOperator_STRIDED_SLICE = 45, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN = 46, + BuiltinOperator_EXP = 47, + BuiltinOperator_TOPK_V2 = 48, + BuiltinOperator_SPLIT = 49, + BuiltinOperator_LOG_SOFTMAX = 50, + BuiltinOperator_DELEGATE = 51, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM = 52, + BuiltinOperator_CAST = 53, + BuiltinOperator_PRELU = 54, + BuiltinOperator_MAXIMUM = 55, + BuiltinOperator_ARG_MAX = 56, + BuiltinOperator_MINIMUM = 57, + BuiltinOperator_LESS = 58, + BuiltinOperator_NEG = 59, + BuiltinOperator_PADV2 = 60, + BuiltinOperator_GREATER = 61, + BuiltinOperator_GREATER_EQUAL = 62, + BuiltinOperator_LESS_EQUAL = 63, + BuiltinOperator_SELECT = 64, + BuiltinOperator_SLICE = 65, + BuiltinOperator_SIN = 66, + BuiltinOperator_TRANSPOSE_CONV = 67, + BuiltinOperator_SPARSE_TO_DENSE = 68, + BuiltinOperator_TILE = 69, + BuiltinOperator_EXPAND_DIMS = 70, + BuiltinOperator_EQUAL = 71, + BuiltinOperator_NOT_EQUAL = 72, + BuiltinOperator_LOG = 73, + BuiltinOperator_SUM = 74, + BuiltinOperator_SQRT = 75, + BuiltinOperator_RSQRT = 76, + BuiltinOperator_SHAPE = 77, + BuiltinOperator_POW = 78, + BuiltinOperator_ARG_MIN = 79, + BuiltinOperator_FAKE_QUANT = 80, + BuiltinOperator_REDUCE_PROD = 81, + BuiltinOperator_REDUCE_MAX = 82, + BuiltinOperator_PACK = 83, + BuiltinOperator_LOGICAL_OR = 84, + BuiltinOperator_ONE_HOT = 85, + BuiltinOperator_LOGICAL_AND = 86, + BuiltinOperator_LOGICAL_NOT = 87, + BuiltinOperator_UNPACK = 88, + BuiltinOperator_REDUCE_MIN = 89, + BuiltinOperator_FLOOR_DIV = 90, + BuiltinOperator_REDUCE_ANY = 91, + BuiltinOperator_SQUARE = 92, + BuiltinOperator_ZEROS_LIKE = 93, + BuiltinOperator_FILL = 94, + BuiltinOperator_FLOOR_MOD = 95, + BuiltinOperator_RANGE = 96, + BuiltinOperator_RESIZE_NEAREST_NEIGHBOR = 97, + BuiltinOperator_LEAKY_RELU = 98, + BuiltinOperator_SQUARED_DIFFERENCE = 99, + BuiltinOperator_MIRROR_PAD = 100, + BuiltinOperator_ABS = 101, + BuiltinOperator_SPLIT_V = 102, + BuiltinOperator_UNIQUE = 103, + BuiltinOperator_CEIL = 104, + BuiltinOperator_REVERSE_V2 = 105, + BuiltinOperator_ADD_N = 106, + BuiltinOperator_GATHER_ND = 107, + BuiltinOperator_COS = 108, + BuiltinOperator_WHERE = 109, + BuiltinOperator_RANK = 110, + BuiltinOperator_ELU = 111, + BuiltinOperator_REVERSE_SEQUENCE = 112, + BuiltinOperator_MATRIX_DIAG = 113, + BuiltinOperator_QUANTIZE = 114, + BuiltinOperator_MATRIX_SET_DIAG = 115, + BuiltinOperator_ROUND = 116, + BuiltinOperator_HARD_SWISH = 117, + BuiltinOperator_IF = 118, + BuiltinOperator_WHILE = 119, + BuiltinOperator_NON_MAX_SUPPRESSION_V4 = 120, + BuiltinOperator_NON_MAX_SUPPRESSION_V5 = 121, + BuiltinOperator_SCATTER_ND = 122, + BuiltinOperator_SELECT_V2 = 123, + BuiltinOperator_DENSIFY = 124, + BuiltinOperator_SEGMENT_SUM = 125, + BuiltinOperator_BATCH_MATMUL = 126, + BuiltinOperator_INSTANCE_NORM = 254, + BuiltinOperator_MIN = BuiltinOperator_ADD, + BuiltinOperator_MAX = BuiltinOperator_INSTANCE_NORM +}; + +inline const BuiltinOperator (&EnumValuesBuiltinOperator())[128] +{ + static const BuiltinOperator values[] = {BuiltinOperator_ADD, + BuiltinOperator_AVERAGE_POOL_2D, + BuiltinOperator_CONCATENATION, + BuiltinOperator_CONV_2D, + BuiltinOperator_DEPTHWISE_CONV_2D, + BuiltinOperator_DEPTH_TO_SPACE, + BuiltinOperator_DEQUANTIZE, + BuiltinOperator_EMBEDDING_LOOKUP, + BuiltinOperator_FLOOR, + BuiltinOperator_FULLY_CONNECTED, + BuiltinOperator_HASHTABLE_LOOKUP, + BuiltinOperator_L2_NORMALIZATION, + BuiltinOperator_L2_POOL_2D, + BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION, + BuiltinOperator_LOGISTIC, + BuiltinOperator_LSH_PROJECTION, + BuiltinOperator_LSTM, + BuiltinOperator_MAX_POOL_2D, + BuiltinOperator_MUL, + BuiltinOperator_RELU, + BuiltinOperator_RELU_N1_TO_1, + BuiltinOperator_RELU6, + BuiltinOperator_RESHAPE, + BuiltinOperator_RESIZE_BILINEAR, + BuiltinOperator_RNN, + BuiltinOperator_SOFTMAX, + BuiltinOperator_SPACE_TO_DEPTH, + BuiltinOperator_SVDF, + BuiltinOperator_TANH, + BuiltinOperator_CONCAT_EMBEDDINGS, + BuiltinOperator_SKIP_GRAM, + BuiltinOperator_CALL, + BuiltinOperator_CUSTOM, + BuiltinOperator_EMBEDDING_LOOKUP_SPARSE, + BuiltinOperator_PAD, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN, + BuiltinOperator_GATHER, + BuiltinOperator_BATCH_TO_SPACE_ND, + BuiltinOperator_SPACE_TO_BATCH_ND, + BuiltinOperator_TRANSPOSE, + BuiltinOperator_MEAN, + BuiltinOperator_SUB, + BuiltinOperator_DIV, + BuiltinOperator_SQUEEZE, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, + BuiltinOperator_STRIDED_SLICE, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN, + BuiltinOperator_EXP, + BuiltinOperator_TOPK_V2, + BuiltinOperator_SPLIT, + BuiltinOperator_LOG_SOFTMAX, + BuiltinOperator_DELEGATE, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM, + BuiltinOperator_CAST, + BuiltinOperator_PRELU, + BuiltinOperator_MAXIMUM, + BuiltinOperator_ARG_MAX, + BuiltinOperator_MINIMUM, + BuiltinOperator_LESS, + BuiltinOperator_NEG, + BuiltinOperator_PADV2, + BuiltinOperator_GREATER, + BuiltinOperator_GREATER_EQUAL, + BuiltinOperator_LESS_EQUAL, + BuiltinOperator_SELECT, + BuiltinOperator_SLICE, + BuiltinOperator_SIN, + BuiltinOperator_TRANSPOSE_CONV, + BuiltinOperator_SPARSE_TO_DENSE, + BuiltinOperator_TILE, + BuiltinOperator_EXPAND_DIMS, + BuiltinOperator_EQUAL, + BuiltinOperator_NOT_EQUAL, + BuiltinOperator_LOG, + BuiltinOperator_SUM, + BuiltinOperator_SQRT, + BuiltinOperator_RSQRT, + BuiltinOperator_SHAPE, + BuiltinOperator_POW, + BuiltinOperator_ARG_MIN, + BuiltinOperator_FAKE_QUANT, + BuiltinOperator_REDUCE_PROD, + BuiltinOperator_REDUCE_MAX, + BuiltinOperator_PACK, + BuiltinOperator_LOGICAL_OR, + BuiltinOperator_ONE_HOT, + BuiltinOperator_LOGICAL_AND, + BuiltinOperator_LOGICAL_NOT, + BuiltinOperator_UNPACK, + BuiltinOperator_REDUCE_MIN, + BuiltinOperator_FLOOR_DIV, + BuiltinOperator_REDUCE_ANY, + BuiltinOperator_SQUARE, + BuiltinOperator_ZEROS_LIKE, + BuiltinOperator_FILL, + BuiltinOperator_FLOOR_MOD, + BuiltinOperator_RANGE, + BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, + BuiltinOperator_LEAKY_RELU, + BuiltinOperator_SQUARED_DIFFERENCE, + BuiltinOperator_MIRROR_PAD, + BuiltinOperator_ABS, + BuiltinOperator_SPLIT_V, + BuiltinOperator_UNIQUE, + BuiltinOperator_CEIL, + BuiltinOperator_REVERSE_V2, + BuiltinOperator_ADD_N, + BuiltinOperator_GATHER_ND, + BuiltinOperator_COS, + BuiltinOperator_WHERE, + BuiltinOperator_RANK, + BuiltinOperator_ELU, + BuiltinOperator_REVERSE_SEQUENCE, + BuiltinOperator_MATRIX_DIAG, + BuiltinOperator_QUANTIZE, + BuiltinOperator_MATRIX_SET_DIAG, + BuiltinOperator_ROUND, + BuiltinOperator_HARD_SWISH, + BuiltinOperator_IF, + BuiltinOperator_WHILE, + BuiltinOperator_NON_MAX_SUPPRESSION_V4, + BuiltinOperator_NON_MAX_SUPPRESSION_V5, + BuiltinOperator_SCATTER_ND, + BuiltinOperator_SELECT_V2, + BuiltinOperator_DENSIFY, + BuiltinOperator_SEGMENT_SUM, + BuiltinOperator_BATCH_MATMUL, + BuiltinOperator_INSTANCE_NORM}; + return values; +} + +inline const char *const *EnumNamesBuiltinOperator() +{ + static const char *const names[] = {"ADD", + "AVERAGE_POOL_2D", + "CONCATENATION", + "CONV_2D", + "DEPTHWISE_CONV_2D", + "DEPTH_TO_SPACE", + "DEQUANTIZE", + "EMBEDDING_LOOKUP", + "FLOOR", + "FULLY_CONNECTED", + "HASHTABLE_LOOKUP", + "L2_NORMALIZATION", + "L2_POOL_2D", + "LOCAL_RESPONSE_NORMALIZATION", + "LOGISTIC", + "LSH_PROJECTION", + "LSTM", + "MAX_POOL_2D", + "MUL", + "RELU", + "RELU_N1_TO_1", + "RELU6", + "RESHAPE", + "RESIZE_BILINEAR", + "RNN", + "SOFTMAX", + "SPACE_TO_DEPTH", + "SVDF", + "TANH", + "CONCAT_EMBEDDINGS", + "SKIP_GRAM", + "CALL", + "CUSTOM", + "EMBEDDING_LOOKUP_SPARSE", + "PAD", + "UNIDIRECTIONAL_SEQUENCE_RNN", + "GATHER", + "BATCH_TO_SPACE_ND", + "SPACE_TO_BATCH_ND", + "TRANSPOSE", + "MEAN", + "SUB", + "DIV", + "SQUEEZE", + "UNIDIRECTIONAL_SEQUENCE_LSTM", + "STRIDED_SLICE", + "BIDIRECTIONAL_SEQUENCE_RNN", + "EXP", + "TOPK_V2", + "SPLIT", + "LOG_SOFTMAX", + "DELEGATE", + "BIDIRECTIONAL_SEQUENCE_LSTM", + "CAST", + "PRELU", + "MAXIMUM", + "ARG_MAX", + "MINIMUM", + "LESS", + "NEG", + "PADV2", + "GREATER", + "GREATER_EQUAL", + "LESS_EQUAL", + "SELECT", + "SLICE", + "SIN", + "TRANSPOSE_CONV", + "SPARSE_TO_DENSE", + "TILE", + "EXPAND_DIMS", + "EQUAL", + "NOT_EQUAL", + "LOG", + "SUM", + "SQRT", + "RSQRT", + "SHAPE", + "POW", + "ARG_MIN", + "FAKE_QUANT", + "REDUCE_PROD", + "REDUCE_MAX", + "PACK", + "LOGICAL_OR", + "ONE_HOT", + "LOGICAL_AND", + "LOGICAL_NOT", + "UNPACK", + "REDUCE_MIN", + "FLOOR_DIV", + "REDUCE_ANY", + "SQUARE", + "ZEROS_LIKE", + "FILL", + "FLOOR_MOD", + "RANGE", + "RESIZE_NEAREST_NEIGHBOR", + "LEAKY_RELU", + "SQUARED_DIFFERENCE", + "MIRROR_PAD", + "ABS", + "SPLIT_V", + "UNIQUE", + "CEIL", + "REVERSE_V2", + "ADD_N", + "GATHER_ND", + "COS", + "WHERE", + "RANK", + "ELU", + "REVERSE_SEQUENCE", + "MATRIX_DIAG", + "QUANTIZE", + "MATRIX_SET_DIAG", + "ROUND", + "HARD_SWISH", + "IF", + "WHILE", + "NON_MAX_SUPPRESSION_V4", + "NON_MAX_SUPPRESSION_V5", + "SCATTER_ND", + "SELECT_V2", + "DENSIFY", + "SEGMENT_SUM", + "BATCH_MATMUL", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "INSTANCE_NORM", + nullptr}; + return names; +} + +inline const char *EnumNameBuiltinOperator(BuiltinOperator e) +{ + const size_t index = static_cast(e); + return EnumNamesBuiltinOperator()[index]; +} + +enum BuiltinOptions +{ + BuiltinOptions_NONE = 0, + BuiltinOptions_Conv2DOptions = 1, + BuiltinOptions_DepthwiseConv2DOptions = 2, + BuiltinOptions_ConcatEmbeddingsOptions = 3, + BuiltinOptions_LSHProjectionOptions = 4, + BuiltinOptions_Pool2DOptions = 5, + BuiltinOptions_SVDFOptions = 6, + BuiltinOptions_RNNOptions = 7, + BuiltinOptions_FullyConnectedOptions = 8, + BuiltinOptions_SoftmaxOptions = 9, + BuiltinOptions_ConcatenationOptions = 10, + BuiltinOptions_AddOptions = 11, + BuiltinOptions_L2NormOptions = 12, + BuiltinOptions_LocalResponseNormalizationOptions = 13, + BuiltinOptions_LSTMOptions = 14, + BuiltinOptions_ResizeBilinearOptions = 15, + BuiltinOptions_CallOptions = 16, + BuiltinOptions_ReshapeOptions = 17, + BuiltinOptions_SkipGramOptions = 18, + BuiltinOptions_SpaceToDepthOptions = 19, + BuiltinOptions_EmbeddingLookupSparseOptions = 20, + BuiltinOptions_MulOptions = 21, + BuiltinOptions_PadOptions = 22, + BuiltinOptions_GatherOptions = 23, + BuiltinOptions_BatchToSpaceNDOptions = 24, + BuiltinOptions_SpaceToBatchNDOptions = 25, + BuiltinOptions_TransposeOptions = 26, + BuiltinOptions_ReducerOptions = 27, + BuiltinOptions_SubOptions = 28, + BuiltinOptions_DivOptions = 29, + BuiltinOptions_SqueezeOptions = 30, + BuiltinOptions_SequenceRNNOptions = 31, + BuiltinOptions_StridedSliceOptions = 32, + BuiltinOptions_ExpOptions = 33, + BuiltinOptions_TopKV2Options = 34, + BuiltinOptions_SplitOptions = 35, + BuiltinOptions_LogSoftmaxOptions = 36, + BuiltinOptions_CastOptions = 37, + BuiltinOptions_DequantizeOptions = 38, + BuiltinOptions_MaximumMinimumOptions = 39, + BuiltinOptions_ArgMaxOptions = 40, + BuiltinOptions_LessOptions = 41, + BuiltinOptions_NegOptions = 42, + BuiltinOptions_PadV2Options = 43, + BuiltinOptions_GreaterOptions = 44, + BuiltinOptions_GreaterEqualOptions = 45, + BuiltinOptions_LessEqualOptions = 46, + BuiltinOptions_SelectOptions = 47, + BuiltinOptions_SliceOptions = 48, + BuiltinOptions_TransposeConvOptions = 49, + BuiltinOptions_SparseToDenseOptions = 50, + BuiltinOptions_TileOptions = 51, + BuiltinOptions_ExpandDimsOptions = 52, + BuiltinOptions_EqualOptions = 53, + BuiltinOptions_NotEqualOptions = 54, + BuiltinOptions_ShapeOptions = 55, + BuiltinOptions_PowOptions = 56, + BuiltinOptions_ArgMinOptions = 57, + BuiltinOptions_FakeQuantOptions = 58, + BuiltinOptions_PackOptions = 59, + BuiltinOptions_LogicalOrOptions = 60, + BuiltinOptions_OneHotOptions = 61, + BuiltinOptions_LogicalAndOptions = 62, + BuiltinOptions_LogicalNotOptions = 63, + BuiltinOptions_UnpackOptions = 64, + BuiltinOptions_FloorDivOptions = 65, + BuiltinOptions_SquareOptions = 66, + BuiltinOptions_ZerosLikeOptions = 67, + BuiltinOptions_FillOptions = 68, + BuiltinOptions_BidirectionalSequenceLSTMOptions = 69, + BuiltinOptions_BidirectionalSequenceRNNOptions = 70, + BuiltinOptions_UnidirectionalSequenceLSTMOptions = 71, + BuiltinOptions_FloorModOptions = 72, + BuiltinOptions_RangeOptions = 73, + BuiltinOptions_ResizeNearestNeighborOptions = 74, + BuiltinOptions_LeakyReluOptions = 75, + BuiltinOptions_SquaredDifferenceOptions = 76, + BuiltinOptions_MirrorPadOptions = 77, + BuiltinOptions_AbsOptions = 78, + BuiltinOptions_SplitVOptions = 79, + BuiltinOptions_UniqueOptions = 80, + BuiltinOptions_ReverseV2Options = 81, + BuiltinOptions_AddNOptions = 82, + BuiltinOptions_GatherNdOptions = 83, + BuiltinOptions_CosOptions = 84, + BuiltinOptions_WhereOptions = 85, + BuiltinOptions_RankOptions = 86, + BuiltinOptions_ReverseSequenceOptions = 87, + BuiltinOptions_MatrixDiagOptions = 88, + BuiltinOptions_QuantizeOptions = 89, + BuiltinOptions_MatrixSetDiagOptions = 90, + BuiltinOptions_HardSwishOptions = 91, + BuiltinOptions_IfOptions = 92, + BuiltinOptions_WhileOptions = 93, + BuiltinOptions_DepthToSpaceOptions = 94, + BuiltinOptions_NonMaxSuppressionV4Options = 95, + BuiltinOptions_NonMaxSuppressionV5Options = 96, + BuiltinOptions_ScatterNdOptions = 97, + BuiltinOptions_SelectV2Options = 98, + BuiltinOptions_DensifyOptions = 99, + BuiltinOptions_SegmentSumOptions = 100, + BuiltinOptions_BatchMatMulOptions = 101, + BuiltinOptions_InstanceNormOptions = 254, + BuiltinOptions_MIN = BuiltinOptions_NONE, + BuiltinOptions_MAX = BuiltinOptions_InstanceNormOptions +}; + +inline const BuiltinOptions (&EnumValuesBuiltinOptions())[103] +{ + static const BuiltinOptions values[] = {BuiltinOptions_NONE, + BuiltinOptions_Conv2DOptions, + BuiltinOptions_DepthwiseConv2DOptions, + BuiltinOptions_ConcatEmbeddingsOptions, + BuiltinOptions_LSHProjectionOptions, + BuiltinOptions_Pool2DOptions, + BuiltinOptions_SVDFOptions, + BuiltinOptions_RNNOptions, + BuiltinOptions_FullyConnectedOptions, + BuiltinOptions_SoftmaxOptions, + BuiltinOptions_ConcatenationOptions, + BuiltinOptions_AddOptions, + BuiltinOptions_L2NormOptions, + BuiltinOptions_LocalResponseNormalizationOptions, + BuiltinOptions_LSTMOptions, + BuiltinOptions_ResizeBilinearOptions, + BuiltinOptions_CallOptions, + BuiltinOptions_ReshapeOptions, + BuiltinOptions_SkipGramOptions, + BuiltinOptions_SpaceToDepthOptions, + BuiltinOptions_EmbeddingLookupSparseOptions, + BuiltinOptions_MulOptions, + BuiltinOptions_PadOptions, + BuiltinOptions_GatherOptions, + BuiltinOptions_BatchToSpaceNDOptions, + BuiltinOptions_SpaceToBatchNDOptions, + BuiltinOptions_TransposeOptions, + BuiltinOptions_ReducerOptions, + BuiltinOptions_SubOptions, + BuiltinOptions_DivOptions, + BuiltinOptions_SqueezeOptions, + BuiltinOptions_SequenceRNNOptions, + BuiltinOptions_StridedSliceOptions, + BuiltinOptions_ExpOptions, + BuiltinOptions_TopKV2Options, + BuiltinOptions_SplitOptions, + BuiltinOptions_LogSoftmaxOptions, + BuiltinOptions_CastOptions, + BuiltinOptions_DequantizeOptions, + BuiltinOptions_MaximumMinimumOptions, + BuiltinOptions_ArgMaxOptions, + BuiltinOptions_LessOptions, + BuiltinOptions_NegOptions, + BuiltinOptions_PadV2Options, + BuiltinOptions_GreaterOptions, + BuiltinOptions_GreaterEqualOptions, + BuiltinOptions_LessEqualOptions, + BuiltinOptions_SelectOptions, + BuiltinOptions_SliceOptions, + BuiltinOptions_TransposeConvOptions, + BuiltinOptions_SparseToDenseOptions, + BuiltinOptions_TileOptions, + BuiltinOptions_ExpandDimsOptions, + BuiltinOptions_EqualOptions, + BuiltinOptions_NotEqualOptions, + BuiltinOptions_ShapeOptions, + BuiltinOptions_PowOptions, + BuiltinOptions_ArgMinOptions, + BuiltinOptions_FakeQuantOptions, + BuiltinOptions_PackOptions, + BuiltinOptions_LogicalOrOptions, + BuiltinOptions_OneHotOptions, + BuiltinOptions_LogicalAndOptions, + BuiltinOptions_LogicalNotOptions, + BuiltinOptions_UnpackOptions, + BuiltinOptions_FloorDivOptions, + BuiltinOptions_SquareOptions, + BuiltinOptions_ZerosLikeOptions, + BuiltinOptions_FillOptions, + BuiltinOptions_BidirectionalSequenceLSTMOptions, + BuiltinOptions_BidirectionalSequenceRNNOptions, + BuiltinOptions_UnidirectionalSequenceLSTMOptions, + BuiltinOptions_FloorModOptions, + BuiltinOptions_RangeOptions, + BuiltinOptions_ResizeNearestNeighborOptions, + BuiltinOptions_LeakyReluOptions, + BuiltinOptions_SquaredDifferenceOptions, + BuiltinOptions_MirrorPadOptions, + BuiltinOptions_AbsOptions, + BuiltinOptions_SplitVOptions, + BuiltinOptions_UniqueOptions, + BuiltinOptions_ReverseV2Options, + BuiltinOptions_AddNOptions, + BuiltinOptions_GatherNdOptions, + BuiltinOptions_CosOptions, + BuiltinOptions_WhereOptions, + BuiltinOptions_RankOptions, + BuiltinOptions_ReverseSequenceOptions, + BuiltinOptions_MatrixDiagOptions, + BuiltinOptions_QuantizeOptions, + BuiltinOptions_MatrixSetDiagOptions, + BuiltinOptions_HardSwishOptions, + BuiltinOptions_IfOptions, + BuiltinOptions_WhileOptions, + BuiltinOptions_DepthToSpaceOptions, + BuiltinOptions_NonMaxSuppressionV4Options, + BuiltinOptions_NonMaxSuppressionV5Options, + BuiltinOptions_ScatterNdOptions, + BuiltinOptions_SelectV2Options, + BuiltinOptions_DensifyOptions, + BuiltinOptions_SegmentSumOptions, + BuiltinOptions_BatchMatMulOptions, + BuiltinOptions_InstanceNormOptions}; + return values; +} + +inline const char *const *EnumNamesBuiltinOptions() +{ + static const char *const names[] = {"NONE", + "Conv2DOptions", + "DepthwiseConv2DOptions", + "ConcatEmbeddingsOptions", + "LSHProjectionOptions", + "Pool2DOptions", + "SVDFOptions", + "RNNOptions", + "FullyConnectedOptions", + "SoftmaxOptions", + "ConcatenationOptions", + "AddOptions", + "L2NormOptions", + "LocalResponseNormalizationOptions", + "LSTMOptions", + "ResizeBilinearOptions", + "CallOptions", + "ReshapeOptions", + "SkipGramOptions", + "SpaceToDepthOptions", + "EmbeddingLookupSparseOptions", + "MulOptions", + "PadOptions", + "GatherOptions", + "BatchToSpaceNDOptions", + "SpaceToBatchNDOptions", + "TransposeOptions", + "ReducerOptions", + "SubOptions", + "DivOptions", + "SqueezeOptions", + "SequenceRNNOptions", + "StridedSliceOptions", + "ExpOptions", + "TopKV2Options", + "SplitOptions", + "LogSoftmaxOptions", + "CastOptions", + "DequantizeOptions", + "MaximumMinimumOptions", + "ArgMaxOptions", + "LessOptions", + "NegOptions", + "PadV2Options", + "GreaterOptions", + "GreaterEqualOptions", + "LessEqualOptions", + "SelectOptions", + "SliceOptions", + "TransposeConvOptions", + "SparseToDenseOptions", + "TileOptions", + "ExpandDimsOptions", + "EqualOptions", + "NotEqualOptions", + "ShapeOptions", + "PowOptions", + "ArgMinOptions", + "FakeQuantOptions", + "PackOptions", + "LogicalOrOptions", + "OneHotOptions", + "LogicalAndOptions", + "LogicalNotOptions", + "UnpackOptions", + "FloorDivOptions", + "SquareOptions", + "ZerosLikeOptions", + "FillOptions", + "BidirectionalSequenceLSTMOptions", + "BidirectionalSequenceRNNOptions", + "UnidirectionalSequenceLSTMOptions", + "FloorModOptions", + "RangeOptions", + "ResizeNearestNeighborOptions", + "LeakyReluOptions", + "SquaredDifferenceOptions", + "MirrorPadOptions", + "AbsOptions", + "SplitVOptions", + "UniqueOptions", + "ReverseV2Options", + "AddNOptions", + "GatherNdOptions", + "CosOptions", + "WhereOptions", + "RankOptions", + "ReverseSequenceOptions", + "MatrixDiagOptions", + "QuantizeOptions", + "MatrixSetDiagOptions", + "HardSwishOptions", + "IfOptions", + "WhileOptions", + "DepthToSpaceOptions", + "NonMaxSuppressionV4Options", + "NonMaxSuppressionV5Options", + "ScatterNdOptions", + "SelectV2Options", + "DensifyOptions", + "SegmentSumOptions", + "BatchMatMulOptions", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "InstanceNormOptions", + nullptr}; + return names; +} + +inline const char *EnumNameBuiltinOptions(BuiltinOptions e) +{ + const size_t index = static_cast(e); + return EnumNamesBuiltinOptions()[index]; +} + +template struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NONE; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_Conv2DOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DepthwiseConv2DOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ConcatEmbeddingsOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LSHProjectionOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_Pool2DOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SVDFOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_RNNOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FullyConnectedOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SoftmaxOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ConcatenationOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_AddOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_L2NormOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LocalResponseNormalizationOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LSTMOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ResizeBilinearOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_CallOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ReshapeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SkipGramOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SpaceToDepthOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_EmbeddingLookupSparseOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MulOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_PadOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_GatherOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_BatchToSpaceNDOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SpaceToBatchNDOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_TransposeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ReducerOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SubOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DivOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SqueezeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SequenceRNNOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_StridedSliceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ExpOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_TopKV2Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SplitOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LogSoftmaxOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_CastOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DequantizeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MaximumMinimumOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ArgMaxOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LessOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NegOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_PadV2Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_GreaterOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_GreaterEqualOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LessEqualOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SelectOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SliceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_TransposeConvOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SparseToDenseOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_TileOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ExpandDimsOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_EqualOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NotEqualOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ShapeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_PowOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ArgMinOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FakeQuantOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_PackOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LogicalOrOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_OneHotOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LogicalAndOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LogicalNotOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_UnpackOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FloorDivOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SquareOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ZerosLikeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FillOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceLSTMOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceRNNOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_UnidirectionalSequenceLSTMOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FloorModOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_RangeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ResizeNearestNeighborOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LeakyReluOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SquaredDifferenceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MirrorPadOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_AbsOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SplitVOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_UniqueOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ReverseV2Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_AddNOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_GatherNdOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_CosOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_WhereOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_RankOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ReverseSequenceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MatrixDiagOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_QuantizeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MatrixSetDiagOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_HardSwishOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_IfOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_WhileOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DepthToSpaceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV4Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV5Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ScatterNdOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SelectV2Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DensifyOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SegmentSumOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_BatchMatMulOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_InstanceNormOptions; +}; + +bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, BuiltinOptions type); +bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types); + +enum Padding +{ + Padding_SAME = 0, + Padding_VALID = 1, + Padding_MIN = Padding_SAME, + Padding_MAX = Padding_VALID +}; + +inline const Padding (&EnumValuesPadding())[2] +{ + static const Padding values[] = {Padding_SAME, Padding_VALID}; + return values; +} + +inline const char *const *EnumNamesPadding() +{ + static const char *const names[] = {"SAME", "VALID", nullptr}; + return names; +} + +inline const char *EnumNamePadding(Padding e) +{ + const size_t index = static_cast(e); + return EnumNamesPadding()[index]; +} + +enum ActivationFunctionType +{ + ActivationFunctionType_NONE = 0, + ActivationFunctionType_RELU = 1, + ActivationFunctionType_RELU_N1_TO_1 = 2, + ActivationFunctionType_RELU6 = 3, + ActivationFunctionType_TANH = 4, + ActivationFunctionType_SIGN_BIT = 5, + ActivationFunctionType_MIN = ActivationFunctionType_NONE, + ActivationFunctionType_MAX = ActivationFunctionType_SIGN_BIT +}; + +inline const ActivationFunctionType (&EnumValuesActivationFunctionType())[6] +{ + static const ActivationFunctionType values[] = { + ActivationFunctionType_NONE, ActivationFunctionType_RELU, + ActivationFunctionType_RELU_N1_TO_1, ActivationFunctionType_RELU6, + ActivationFunctionType_TANH, ActivationFunctionType_SIGN_BIT}; + return values; +} + +inline const char *const *EnumNamesActivationFunctionType() +{ + static const char *const names[] = {"NONE", "RELU", "RELU_N1_TO_1", "RELU6", + "TANH", "SIGN_BIT", nullptr}; + return names; +} + +inline const char *EnumNameActivationFunctionType(ActivationFunctionType e) +{ + const size_t index = static_cast(e); + return EnumNamesActivationFunctionType()[index]; +} + +enum LSHProjectionType +{ + LSHProjectionType_UNKNOWN = 0, + LSHProjectionType_SPARSE = 1, + LSHProjectionType_DENSE = 2, + LSHProjectionType_MIN = LSHProjectionType_UNKNOWN, + LSHProjectionType_MAX = LSHProjectionType_DENSE +}; + +inline const LSHProjectionType (&EnumValuesLSHProjectionType())[3] +{ + static const LSHProjectionType values[] = {LSHProjectionType_UNKNOWN, LSHProjectionType_SPARSE, + LSHProjectionType_DENSE}; + return values; +} + +inline const char *const *EnumNamesLSHProjectionType() +{ + static const char *const names[] = {"UNKNOWN", "SPARSE", "DENSE", nullptr}; + return names; +} + +inline const char *EnumNameLSHProjectionType(LSHProjectionType e) +{ + const size_t index = static_cast(e); + return EnumNamesLSHProjectionType()[index]; +} + +enum FullyConnectedOptionsWeightsFormat +{ + FullyConnectedOptionsWeightsFormat_DEFAULT = 0, + FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8 = 1, + FullyConnectedOptionsWeightsFormat_MIN = FullyConnectedOptionsWeightsFormat_DEFAULT, + FullyConnectedOptionsWeightsFormat_MAX = FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8 +}; + +inline const FullyConnectedOptionsWeightsFormat (&EnumValuesFullyConnectedOptionsWeightsFormat())[2] +{ + static const FullyConnectedOptionsWeightsFormat values[] = { + FullyConnectedOptionsWeightsFormat_DEFAULT, + FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8}; + return values; +} + +inline const char *const *EnumNamesFullyConnectedOptionsWeightsFormat() +{ + static const char *const names[] = {"DEFAULT", "SHUFFLED4x16INT8", nullptr}; + return names; +} + +inline const char *EnumNameFullyConnectedOptionsWeightsFormat(FullyConnectedOptionsWeightsFormat e) +{ + const size_t index = static_cast(e); + return EnumNamesFullyConnectedOptionsWeightsFormat()[index]; +} + +enum LSTMKernelType +{ + LSTMKernelType_FULL = 0, + LSTMKernelType_BASIC = 1, + LSTMKernelType_MIN = LSTMKernelType_FULL, + LSTMKernelType_MAX = LSTMKernelType_BASIC +}; + +inline const LSTMKernelType (&EnumValuesLSTMKernelType())[2] +{ + static const LSTMKernelType values[] = {LSTMKernelType_FULL, LSTMKernelType_BASIC}; + return values; +} + +inline const char *const *EnumNamesLSTMKernelType() +{ + static const char *const names[] = {"FULL", "BASIC", nullptr}; + return names; +} + +inline const char *EnumNameLSTMKernelType(LSTMKernelType e) +{ + const size_t index = static_cast(e); + return EnumNamesLSTMKernelType()[index]; +} + +enum CombinerType +{ + CombinerType_SUM = 0, + CombinerType_MEAN = 1, + CombinerType_SQRTN = 2, + CombinerType_MIN = CombinerType_SUM, + CombinerType_MAX = CombinerType_SQRTN +}; + +inline const CombinerType (&EnumValuesCombinerType())[3] +{ + static const CombinerType values[] = {CombinerType_SUM, CombinerType_MEAN, CombinerType_SQRTN}; + return values; +} + +inline const char *const *EnumNamesCombinerType() +{ + static const char *const names[] = {"SUM", "MEAN", "SQRTN", nullptr}; + return names; +} + +inline const char *EnumNameCombinerType(CombinerType e) +{ + const size_t index = static_cast(e); + return EnumNamesCombinerType()[index]; +} + +enum MirrorPadMode +{ + MirrorPadMode_REFLECT = 0, + MirrorPadMode_SYMMETRIC = 1, + MirrorPadMode_MIN = MirrorPadMode_REFLECT, + MirrorPadMode_MAX = MirrorPadMode_SYMMETRIC +}; + +inline const MirrorPadMode (&EnumValuesMirrorPadMode())[2] +{ + static const MirrorPadMode values[] = {MirrorPadMode_REFLECT, MirrorPadMode_SYMMETRIC}; + return values; +} + +inline const char *const *EnumNamesMirrorPadMode() +{ + static const char *const names[] = {"REFLECT", "SYMMETRIC", nullptr}; + return names; +} + +inline const char *EnumNameMirrorPadMode(MirrorPadMode e) +{ + const size_t index = static_cast(e); + return EnumNamesMirrorPadMode()[index]; +} + +enum CustomOptionsFormat +{ + CustomOptionsFormat_FLEXBUFFERS = 0, + CustomOptionsFormat_MIN = CustomOptionsFormat_FLEXBUFFERS, + CustomOptionsFormat_MAX = CustomOptionsFormat_FLEXBUFFERS +}; + +inline const CustomOptionsFormat (&EnumValuesCustomOptionsFormat())[1] +{ + static const CustomOptionsFormat values[] = {CustomOptionsFormat_FLEXBUFFERS}; + return values; +} + +inline const char *const *EnumNamesCustomOptionsFormat() +{ + static const char *const names[] = {"FLEXBUFFERS", nullptr}; + return names; +} + +inline const char *EnumNameCustomOptionsFormat(CustomOptionsFormat e) +{ + const size_t index = static_cast(e); + return EnumNamesCustomOptionsFormat()[index]; +} + +enum DataFormat +{ + DataFormat_CHANNELS_LAST = 0, + DataFormat_CHANNELS_FIRST = 1, + DataFormat_MIN = DataFormat_CHANNELS_LAST, + DataFormat_MAX = DataFormat_CHANNELS_FIRST +}; + +inline const DataFormat (&EnumValuesDataFormat())[2] +{ + static const DataFormat values[] = {DataFormat_CHANNELS_LAST, DataFormat_CHANNELS_FIRST}; + return values; +} + +inline const char *const *EnumNamesDataFormat() +{ + static const char *const names[] = {"CHANNELS_LAST", "CHANNELS_FIRST", nullptr}; + return names; +} + +inline const char *EnumNameDataFormat(DataFormat e) +{ + const size_t index = static_cast(e); + return EnumNamesDataFormat()[index]; +} + +struct CustomQuantization FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_CUSTOM = 4 + }; + const flatbuffers::Vector *custom() const + { + return GetPointer *>(VT_CUSTOM); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_CUSTOM) && + verifier.VerifyVector(custom()) && verifier.EndTable(); + } +}; + +struct CustomQuantizationBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_custom(flatbuffers::Offset> custom) + { + fbb_.AddOffset(CustomQuantization::VT_CUSTOM, custom); + } + explicit CustomQuantizationBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + CustomQuantizationBuilder &operator=(const CustomQuantizationBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateCustomQuantization(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> custom = 0) +{ + CustomQuantizationBuilder builder_(_fbb); + builder_.add_custom(custom); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateCustomQuantizationDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *custom = nullptr) +{ + return circle::CreateCustomQuantization(_fbb, custom ? _fbb.CreateVector(*custom) : 0); +} + +struct QuantizationParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_MIN = 4, + VT_MAX = 6, + VT_SCALE = 8, + VT_ZERO_POINT = 10, + VT_DETAILS_TYPE = 12, + VT_DETAILS = 14, + VT_QUANTIZED_DIMENSION = 16 + }; + const flatbuffers::Vector *min() const + { + return GetPointer *>(VT_MIN); + } + const flatbuffers::Vector *max() const + { + return GetPointer *>(VT_MAX); + } + const flatbuffers::Vector *scale() const + { + return GetPointer *>(VT_SCALE); + } + const flatbuffers::Vector *zero_point() const + { + return GetPointer *>(VT_ZERO_POINT); + } + QuantizationDetails details_type() const + { + return static_cast(GetField(VT_DETAILS_TYPE, 0)); + } + const void *details() const { return GetPointer(VT_DETAILS); } + template const T *details_as() const; + const CustomQuantization *details_as_CustomQuantization() const + { + return details_type() == QuantizationDetails_CustomQuantization + ? static_cast(details()) + : nullptr; + } + int32_t quantized_dimension() const { return GetField(VT_QUANTIZED_DIMENSION, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_MIN) && + verifier.VerifyVector(min()) && VerifyOffset(verifier, VT_MAX) && + verifier.VerifyVector(max()) && VerifyOffset(verifier, VT_SCALE) && + verifier.VerifyVector(scale()) && VerifyOffset(verifier, VT_ZERO_POINT) && + verifier.VerifyVector(zero_point()) && VerifyField(verifier, VT_DETAILS_TYPE) && + VerifyOffset(verifier, VT_DETAILS) && + VerifyQuantizationDetails(verifier, details(), details_type()) && + VerifyField(verifier, VT_QUANTIZED_DIMENSION) && verifier.EndTable(); + } +}; + +template <> +inline const CustomQuantization *QuantizationParameters::details_as() const +{ + return details_as_CustomQuantization(); +} + +struct QuantizationParametersBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_min(flatbuffers::Offset> min) + { + fbb_.AddOffset(QuantizationParameters::VT_MIN, min); + } + void add_max(flatbuffers::Offset> max) + { + fbb_.AddOffset(QuantizationParameters::VT_MAX, max); + } + void add_scale(flatbuffers::Offset> scale) + { + fbb_.AddOffset(QuantizationParameters::VT_SCALE, scale); + } + void add_zero_point(flatbuffers::Offset> zero_point) + { + fbb_.AddOffset(QuantizationParameters::VT_ZERO_POINT, zero_point); + } + void add_details_type(QuantizationDetails details_type) + { + fbb_.AddElement(QuantizationParameters::VT_DETAILS_TYPE, + static_cast(details_type), 0); + } + void add_details(flatbuffers::Offset details) + { + fbb_.AddOffset(QuantizationParameters::VT_DETAILS, details); + } + void add_quantized_dimension(int32_t quantized_dimension) + { + fbb_.AddElement(QuantizationParameters::VT_QUANTIZED_DIMENSION, quantized_dimension, + 0); + } + explicit QuantizationParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + QuantizationParametersBuilder &operator=(const QuantizationParametersBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateQuantizationParameters(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> min = 0, + flatbuffers::Offset> max = 0, + flatbuffers::Offset> scale = 0, + flatbuffers::Offset> zero_point = 0, + QuantizationDetails details_type = QuantizationDetails_NONE, + flatbuffers::Offset details = 0, int32_t quantized_dimension = 0) +{ + QuantizationParametersBuilder builder_(_fbb); + builder_.add_quantized_dimension(quantized_dimension); + builder_.add_details(details); + builder_.add_zero_point(zero_point); + builder_.add_scale(scale); + builder_.add_max(max); + builder_.add_min(min); + builder_.add_details_type(details_type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateQuantizationParametersDirect( + flatbuffers::FlatBufferBuilder &_fbb, const std::vector *min = nullptr, + const std::vector *max = nullptr, const std::vector *scale = nullptr, + const std::vector *zero_point = nullptr, + QuantizationDetails details_type = QuantizationDetails_NONE, + flatbuffers::Offset details = 0, int32_t quantized_dimension = 0) +{ + return circle::CreateQuantizationParameters( + _fbb, min ? _fbb.CreateVector(*min) : 0, max ? _fbb.CreateVector(*max) : 0, + scale ? _fbb.CreateVector(*scale) : 0, + zero_point ? _fbb.CreateVector(*zero_point) : 0, details_type, details, + quantized_dimension); +} + +struct Int32Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALUES = 4 + }; + const flatbuffers::Vector *values() const + { + return GetPointer *>(VT_VALUES); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && verifier.EndTable(); + } +}; + +struct Int32VectorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values(flatbuffers::Offset> values) + { + fbb_.AddOffset(Int32Vector::VT_VALUES, values); + } + explicit Int32VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Int32VectorBuilder &operator=(const Int32VectorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateInt32Vector(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> values = 0) +{ + Int32VectorBuilder builder_(_fbb); + builder_.add_values(values); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateInt32VectorDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *values = nullptr) +{ + return circle::CreateInt32Vector(_fbb, values ? _fbb.CreateVector(*values) : 0); +} + +struct Uint16Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALUES = 4 + }; + const flatbuffers::Vector *values() const + { + return GetPointer *>(VT_VALUES); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && verifier.EndTable(); + } +}; + +struct Uint16VectorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values(flatbuffers::Offset> values) + { + fbb_.AddOffset(Uint16Vector::VT_VALUES, values); + } + explicit Uint16VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Uint16VectorBuilder &operator=(const Uint16VectorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateUint16Vector(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> values = 0) +{ + Uint16VectorBuilder builder_(_fbb); + builder_.add_values(values); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateUint16VectorDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *values = nullptr) +{ + return circle::CreateUint16Vector(_fbb, values ? _fbb.CreateVector(*values) : 0); +} + +struct Uint8Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALUES = 4 + }; + const flatbuffers::Vector *values() const + { + return GetPointer *>(VT_VALUES); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && verifier.EndTable(); + } +}; + +struct Uint8VectorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values(flatbuffers::Offset> values) + { + fbb_.AddOffset(Uint8Vector::VT_VALUES, values); + } + explicit Uint8VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Uint8VectorBuilder &operator=(const Uint8VectorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateUint8Vector(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> values = 0) +{ + Uint8VectorBuilder builder_(_fbb); + builder_.add_values(values); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateUint8VectorDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *values = nullptr) +{ + return circle::CreateUint8Vector(_fbb, values ? _fbb.CreateVector(*values) : 0); +} + +struct DimensionMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FORMAT = 4, + VT_DENSE_SIZE = 6, + VT_ARRAY_SEGMENTS_TYPE = 8, + VT_ARRAY_SEGMENTS = 10, + VT_ARRAY_INDICES_TYPE = 12, + VT_ARRAY_INDICES = 14 + }; + DimensionType format() const + { + return static_cast(GetField(VT_FORMAT, 0)); + } + int32_t dense_size() const { return GetField(VT_DENSE_SIZE, 0); } + SparseIndexVector array_segments_type() const + { + return static_cast(GetField(VT_ARRAY_SEGMENTS_TYPE, 0)); + } + const void *array_segments() const { return GetPointer(VT_ARRAY_SEGMENTS); } + template const T *array_segments_as() const; + const Int32Vector *array_segments_as_Int32Vector() const + { + return array_segments_type() == SparseIndexVector_Int32Vector + ? static_cast(array_segments()) + : nullptr; + } + const Uint16Vector *array_segments_as_Uint16Vector() const + { + return array_segments_type() == SparseIndexVector_Uint16Vector + ? static_cast(array_segments()) + : nullptr; + } + const Uint8Vector *array_segments_as_Uint8Vector() const + { + return array_segments_type() == SparseIndexVector_Uint8Vector + ? static_cast(array_segments()) + : nullptr; + } + SparseIndexVector array_indices_type() const + { + return static_cast(GetField(VT_ARRAY_INDICES_TYPE, 0)); + } + const void *array_indices() const { return GetPointer(VT_ARRAY_INDICES); } + template const T *array_indices_as() const; + const Int32Vector *array_indices_as_Int32Vector() const + { + return array_indices_type() == SparseIndexVector_Int32Vector + ? static_cast(array_indices()) + : nullptr; + } + const Uint16Vector *array_indices_as_Uint16Vector() const + { + return array_indices_type() == SparseIndexVector_Uint16Vector + ? static_cast(array_indices()) + : nullptr; + } + const Uint8Vector *array_indices_as_Uint8Vector() const + { + return array_indices_type() == SparseIndexVector_Uint8Vector + ? static_cast(array_indices()) + : nullptr; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_FORMAT) && + VerifyField(verifier, VT_DENSE_SIZE) && + VerifyField(verifier, VT_ARRAY_SEGMENTS_TYPE) && + VerifyOffset(verifier, VT_ARRAY_SEGMENTS) && + VerifySparseIndexVector(verifier, array_segments(), array_segments_type()) && + VerifyField(verifier, VT_ARRAY_INDICES_TYPE) && + VerifyOffset(verifier, VT_ARRAY_INDICES) && + VerifySparseIndexVector(verifier, array_indices(), array_indices_type()) && + verifier.EndTable(); + } +}; + +template <> inline const Int32Vector *DimensionMetadata::array_segments_as() const +{ + return array_segments_as_Int32Vector(); +} + +template <> inline const Uint16Vector *DimensionMetadata::array_segments_as() const +{ + return array_segments_as_Uint16Vector(); +} + +template <> inline const Uint8Vector *DimensionMetadata::array_segments_as() const +{ + return array_segments_as_Uint8Vector(); +} + +template <> inline const Int32Vector *DimensionMetadata::array_indices_as() const +{ + return array_indices_as_Int32Vector(); +} + +template <> inline const Uint16Vector *DimensionMetadata::array_indices_as() const +{ + return array_indices_as_Uint16Vector(); +} + +template <> inline const Uint8Vector *DimensionMetadata::array_indices_as() const +{ + return array_indices_as_Uint8Vector(); +} + +struct DimensionMetadataBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_format(DimensionType format) + { + fbb_.AddElement(DimensionMetadata::VT_FORMAT, static_cast(format), 0); + } + void add_dense_size(int32_t dense_size) + { + fbb_.AddElement(DimensionMetadata::VT_DENSE_SIZE, dense_size, 0); + } + void add_array_segments_type(SparseIndexVector array_segments_type) + { + fbb_.AddElement(DimensionMetadata::VT_ARRAY_SEGMENTS_TYPE, + static_cast(array_segments_type), 0); + } + void add_array_segments(flatbuffers::Offset array_segments) + { + fbb_.AddOffset(DimensionMetadata::VT_ARRAY_SEGMENTS, array_segments); + } + void add_array_indices_type(SparseIndexVector array_indices_type) + { + fbb_.AddElement(DimensionMetadata::VT_ARRAY_INDICES_TYPE, + static_cast(array_indices_type), 0); + } + void add_array_indices(flatbuffers::Offset array_indices) + { + fbb_.AddOffset(DimensionMetadata::VT_ARRAY_INDICES, array_indices); + } + explicit DimensionMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DimensionMetadataBuilder &operator=(const DimensionMetadataBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDimensionMetadata(flatbuffers::FlatBufferBuilder &_fbb, + DimensionType format = DimensionType_DENSE, int32_t dense_size = 0, + SparseIndexVector array_segments_type = SparseIndexVector_NONE, + flatbuffers::Offset array_segments = 0, + SparseIndexVector array_indices_type = SparseIndexVector_NONE, + flatbuffers::Offset array_indices = 0) +{ + DimensionMetadataBuilder builder_(_fbb); + builder_.add_array_indices(array_indices); + builder_.add_array_segments(array_segments); + builder_.add_dense_size(dense_size); + builder_.add_array_indices_type(array_indices_type); + builder_.add_array_segments_type(array_segments_type); + builder_.add_format(format); + return builder_.Finish(); +} + +struct SparsityParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TRAVERSAL_ORDER = 4, + VT_BLOCK_MAP = 6, + VT_DIM_METADATA = 8 + }; + const flatbuffers::Vector *traversal_order() const + { + return GetPointer *>(VT_TRAVERSAL_ORDER); + } + const flatbuffers::Vector *block_map() const + { + return GetPointer *>(VT_BLOCK_MAP); + } + const flatbuffers::Vector> *dim_metadata() const + { + return GetPointer> *>( + VT_DIM_METADATA); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TRAVERSAL_ORDER) && + verifier.VerifyVector(traversal_order()) && VerifyOffset(verifier, VT_BLOCK_MAP) && + verifier.VerifyVector(block_map()) && VerifyOffset(verifier, VT_DIM_METADATA) && + verifier.VerifyVector(dim_metadata()) && verifier.VerifyVectorOfTables(dim_metadata()) && + verifier.EndTable(); + } +}; + +struct SparsityParametersBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_traversal_order(flatbuffers::Offset> traversal_order) + { + fbb_.AddOffset(SparsityParameters::VT_TRAVERSAL_ORDER, traversal_order); + } + void add_block_map(flatbuffers::Offset> block_map) + { + fbb_.AddOffset(SparsityParameters::VT_BLOCK_MAP, block_map); + } + void add_dim_metadata( + flatbuffers::Offset>> dim_metadata) + { + fbb_.AddOffset(SparsityParameters::VT_DIM_METADATA, dim_metadata); + } + explicit SparsityParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SparsityParametersBuilder &operator=(const SparsityParametersBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSparsityParameters( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> traversal_order = 0, + flatbuffers::Offset> block_map = 0, + flatbuffers::Offset>> dim_metadata = + 0) +{ + SparsityParametersBuilder builder_(_fbb); + builder_.add_dim_metadata(dim_metadata); + builder_.add_block_map(block_map); + builder_.add_traversal_order(traversal_order); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateSparsityParametersDirect( + flatbuffers::FlatBufferBuilder &_fbb, const std::vector *traversal_order = nullptr, + const std::vector *block_map = nullptr, + const std::vector> *dim_metadata = nullptr) +{ + return circle::CreateSparsityParameters( + _fbb, traversal_order ? _fbb.CreateVector(*traversal_order) : 0, + block_map ? _fbb.CreateVector(*block_map) : 0, + dim_metadata ? _fbb.CreateVector>(*dim_metadata) : 0); +} + +struct Tensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_SHAPE = 4, + VT_TYPE = 6, + VT_BUFFER = 8, + VT_NAME = 10, + VT_QUANTIZATION = 12, + VT_IS_VARIABLE = 14, + VT_SPARSITY = 16, + VT_SHAPE_SIGNATURE = 18 + }; + const flatbuffers::Vector *shape() const + { + return GetPointer *>(VT_SHAPE); + } + TensorType type() const { return static_cast(GetField(VT_TYPE, 0)); } + uint32_t buffer() const { return GetField(VT_BUFFER, 0); } + const flatbuffers::String *name() const + { + return GetPointer(VT_NAME); + } + const QuantizationParameters *quantization() const + { + return GetPointer(VT_QUANTIZATION); + } + bool is_variable() const { return GetField(VT_IS_VARIABLE, 0) != 0; } + const SparsityParameters *sparsity() const + { + return GetPointer(VT_SPARSITY); + } + const flatbuffers::Vector *shape_signature() const + { + return GetPointer *>(VT_SHAPE_SIGNATURE); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_SHAPE) && + verifier.VerifyVector(shape()) && VerifyField(verifier, VT_TYPE) && + VerifyField(verifier, VT_BUFFER) && VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && VerifyOffset(verifier, VT_QUANTIZATION) && + verifier.VerifyTable(quantization()) && VerifyField(verifier, VT_IS_VARIABLE) && + VerifyOffset(verifier, VT_SPARSITY) && verifier.VerifyTable(sparsity()) && + VerifyOffset(verifier, VT_SHAPE_SIGNATURE) && verifier.VerifyVector(shape_signature()) && + verifier.EndTable(); + } +}; + +struct TensorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_shape(flatbuffers::Offset> shape) + { + fbb_.AddOffset(Tensor::VT_SHAPE, shape); + } + void add_type(TensorType type) + { + fbb_.AddElement(Tensor::VT_TYPE, static_cast(type), 0); + } + void add_buffer(uint32_t buffer) { fbb_.AddElement(Tensor::VT_BUFFER, buffer, 0); } + void add_name(flatbuffers::Offset name) + { + fbb_.AddOffset(Tensor::VT_NAME, name); + } + void add_quantization(flatbuffers::Offset quantization) + { + fbb_.AddOffset(Tensor::VT_QUANTIZATION, quantization); + } + void add_is_variable(bool is_variable) + { + fbb_.AddElement(Tensor::VT_IS_VARIABLE, static_cast(is_variable), 0); + } + void add_sparsity(flatbuffers::Offset sparsity) + { + fbb_.AddOffset(Tensor::VT_SPARSITY, sparsity); + } + void add_shape_signature(flatbuffers::Offset> shape_signature) + { + fbb_.AddOffset(Tensor::VT_SHAPE_SIGNATURE, shape_signature); + } + explicit TensorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TensorBuilder &operator=(const TensorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateTensor(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> shape = 0, + TensorType type = TensorType_FLOAT32, uint32_t buffer = 0, + flatbuffers::Offset name = 0, + flatbuffers::Offset quantization = 0, bool is_variable = false, + flatbuffers::Offset sparsity = 0, + flatbuffers::Offset> shape_signature = 0) +{ + TensorBuilder builder_(_fbb); + builder_.add_shape_signature(shape_signature); + builder_.add_sparsity(sparsity); + builder_.add_quantization(quantization); + builder_.add_name(name); + builder_.add_buffer(buffer); + builder_.add_shape(shape); + builder_.add_is_variable(is_variable); + builder_.add_type(type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateTensorDirect( + flatbuffers::FlatBufferBuilder &_fbb, const std::vector *shape = nullptr, + TensorType type = TensorType_FLOAT32, uint32_t buffer = 0, const char *name = nullptr, + flatbuffers::Offset quantization = 0, bool is_variable = false, + flatbuffers::Offset sparsity = 0, + const std::vector *shape_signature = nullptr) +{ + return circle::CreateTensor(_fbb, shape ? _fbb.CreateVector(*shape) : 0, type, buffer, + name ? _fbb.CreateString(name) : 0, quantization, is_variable, + sparsity, + shape_signature ? _fbb.CreateVector(*shape_signature) : 0); +} + +struct Conv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8, + VT_FUSED_ACTIVATION_FUNCTION = 10, + VT_DILATION_W_FACTOR = 12, + VT_DILATION_H_FACTOR = 14 + }; + Padding padding() const { return static_cast(GetField(VT_PADDING, 0)); } + int32_t stride_w() const { return GetField(VT_STRIDE_W, 0); } + int32_t stride_h() const { return GetField(VT_STRIDE_H, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + int32_t dilation_w_factor() const { return GetField(VT_DILATION_W_FACTOR, 1); } + int32_t dilation_h_factor() const { return GetField(VT_DILATION_H_FACTOR, 1); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_PADDING) && + VerifyField(verifier, VT_STRIDE_W) && + VerifyField(verifier, VT_STRIDE_H) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_DILATION_W_FACTOR) && + VerifyField(verifier, VT_DILATION_H_FACTOR) && verifier.EndTable(); + } +}; + +struct Conv2DOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(Padding padding) + { + fbb_.AddElement(Conv2DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) + { + fbb_.AddElement(Conv2DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) + { + fbb_.AddElement(Conv2DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(Conv2DOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_dilation_w_factor(int32_t dilation_w_factor) + { + fbb_.AddElement(Conv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1); + } + void add_dilation_h_factor(int32_t dilation_h_factor) + { + fbb_.AddElement(Conv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1); + } + explicit Conv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Conv2DOptionsBuilder &operator=(const Conv2DOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateConv2DOptions(flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME, + int32_t stride_w = 0, int32_t stride_h = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + int32_t dilation_w_factor = 1, int32_t dilation_h_factor = 1) +{ + Conv2DOptionsBuilder builder_(_fbb); + builder_.add_dilation_h_factor(dilation_h_factor); + builder_.add_dilation_w_factor(dilation_w_factor); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +struct Pool2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8, + VT_FILTER_WIDTH = 10, + VT_FILTER_HEIGHT = 12, + VT_FUSED_ACTIVATION_FUNCTION = 14 + }; + Padding padding() const { return static_cast(GetField(VT_PADDING, 0)); } + int32_t stride_w() const { return GetField(VT_STRIDE_W, 0); } + int32_t stride_h() const { return GetField(VT_STRIDE_H, 0); } + int32_t filter_width() const { return GetField(VT_FILTER_WIDTH, 0); } + int32_t filter_height() const { return GetField(VT_FILTER_HEIGHT, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_PADDING) && + VerifyField(verifier, VT_STRIDE_W) && + VerifyField(verifier, VT_STRIDE_H) && + VerifyField(verifier, VT_FILTER_WIDTH) && + VerifyField(verifier, VT_FILTER_HEIGHT) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct Pool2DOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(Padding padding) + { + fbb_.AddElement(Pool2DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) + { + fbb_.AddElement(Pool2DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) + { + fbb_.AddElement(Pool2DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_filter_width(int32_t filter_width) + { + fbb_.AddElement(Pool2DOptions::VT_FILTER_WIDTH, filter_width, 0); + } + void add_filter_height(int32_t filter_height) + { + fbb_.AddElement(Pool2DOptions::VT_FILTER_HEIGHT, filter_height, 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(Pool2DOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit Pool2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Pool2DOptionsBuilder &operator=(const Pool2DOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreatePool2DOptions(flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME, + int32_t stride_w = 0, int32_t stride_h = 0, int32_t filter_width = 0, + int32_t filter_height = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + Pool2DOptionsBuilder builder_(_fbb); + builder_.add_filter_height(filter_height); + builder_.add_filter_width(filter_width); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +struct DepthwiseConv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8, + VT_DEPTH_MULTIPLIER = 10, + VT_FUSED_ACTIVATION_FUNCTION = 12, + VT_DILATION_W_FACTOR = 14, + VT_DILATION_H_FACTOR = 16 + }; + Padding padding() const { return static_cast(GetField(VT_PADDING, 0)); } + int32_t stride_w() const { return GetField(VT_STRIDE_W, 0); } + int32_t stride_h() const { return GetField(VT_STRIDE_H, 0); } + int32_t depth_multiplier() const { return GetField(VT_DEPTH_MULTIPLIER, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + int32_t dilation_w_factor() const { return GetField(VT_DILATION_W_FACTOR, 1); } + int32_t dilation_h_factor() const { return GetField(VT_DILATION_H_FACTOR, 1); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_PADDING) && + VerifyField(verifier, VT_STRIDE_W) && + VerifyField(verifier, VT_STRIDE_H) && + VerifyField(verifier, VT_DEPTH_MULTIPLIER) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_DILATION_W_FACTOR) && + VerifyField(verifier, VT_DILATION_H_FACTOR) && verifier.EndTable(); + } +}; + +struct DepthwiseConv2DOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(Padding padding) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_depth_multiplier(int32_t depth_multiplier) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_DEPTH_MULTIPLIER, depth_multiplier, 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_dilation_w_factor(int32_t dilation_w_factor) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1); + } + void add_dilation_h_factor(int32_t dilation_h_factor) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1); + } + explicit DepthwiseConv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DepthwiseConv2DOptionsBuilder &operator=(const DepthwiseConv2DOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateDepthwiseConv2DOptions( + flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME, int32_t stride_w = 0, + int32_t stride_h = 0, int32_t depth_multiplier = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + int32_t dilation_w_factor = 1, int32_t dilation_h_factor = 1) +{ + DepthwiseConv2DOptionsBuilder builder_(_fbb); + builder_.add_dilation_h_factor(dilation_h_factor); + builder_.add_dilation_w_factor(dilation_w_factor); + builder_.add_depth_multiplier(depth_multiplier); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +struct ConcatEmbeddingsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NUM_CHANNELS = 4, + VT_NUM_COLUMNS_PER_CHANNEL = 6, + VT_EMBEDDING_DIM_PER_CHANNEL = 8 + }; + int32_t num_channels() const { return GetField(VT_NUM_CHANNELS, 0); } + const flatbuffers::Vector *num_columns_per_channel() const + { + return GetPointer *>(VT_NUM_COLUMNS_PER_CHANNEL); + } + const flatbuffers::Vector *embedding_dim_per_channel() const + { + return GetPointer *>(VT_EMBEDDING_DIM_PER_CHANNEL); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NUM_CHANNELS) && + VerifyOffset(verifier, VT_NUM_COLUMNS_PER_CHANNEL) && + verifier.VerifyVector(num_columns_per_channel()) && + VerifyOffset(verifier, VT_EMBEDDING_DIM_PER_CHANNEL) && + verifier.VerifyVector(embedding_dim_per_channel()) && verifier.EndTable(); + } +}; + +struct ConcatEmbeddingsOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_channels(int32_t num_channels) + { + fbb_.AddElement(ConcatEmbeddingsOptions::VT_NUM_CHANNELS, num_channels, 0); + } + void add_num_columns_per_channel( + flatbuffers::Offset> num_columns_per_channel) + { + fbb_.AddOffset(ConcatEmbeddingsOptions::VT_NUM_COLUMNS_PER_CHANNEL, num_columns_per_channel); + } + void add_embedding_dim_per_channel( + flatbuffers::Offset> embedding_dim_per_channel) + { + fbb_.AddOffset(ConcatEmbeddingsOptions::VT_EMBEDDING_DIM_PER_CHANNEL, + embedding_dim_per_channel); + } + explicit ConcatEmbeddingsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ConcatEmbeddingsOptionsBuilder &operator=(const ConcatEmbeddingsOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateConcatEmbeddingsOptions( + flatbuffers::FlatBufferBuilder &_fbb, int32_t num_channels = 0, + flatbuffers::Offset> num_columns_per_channel = 0, + flatbuffers::Offset> embedding_dim_per_channel = 0) +{ + ConcatEmbeddingsOptionsBuilder builder_(_fbb); + builder_.add_embedding_dim_per_channel(embedding_dim_per_channel); + builder_.add_num_columns_per_channel(num_columns_per_channel); + builder_.add_num_channels(num_channels); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateConcatEmbeddingsOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb, int32_t num_channels = 0, + const std::vector *num_columns_per_channel = nullptr, + const std::vector *embedding_dim_per_channel = nullptr) +{ + return circle::CreateConcatEmbeddingsOptions( + _fbb, num_channels, + num_columns_per_channel ? _fbb.CreateVector(*num_columns_per_channel) : 0, + embedding_dim_per_channel ? _fbb.CreateVector(*embedding_dim_per_channel) : 0); +} + +struct LSHProjectionOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TYPE = 4 + }; + LSHProjectionType type() const + { + return static_cast(GetField(VT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_TYPE) && + verifier.EndTable(); + } +}; + +struct LSHProjectionOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_type(LSHProjectionType type) + { + fbb_.AddElement(LSHProjectionOptions::VT_TYPE, static_cast(type), 0); + } + explicit LSHProjectionOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LSHProjectionOptionsBuilder &operator=(const LSHProjectionOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLSHProjectionOptions(flatbuffers::FlatBufferBuilder &_fbb, + LSHProjectionType type = LSHProjectionType_UNKNOWN) +{ + LSHProjectionOptionsBuilder builder_(_fbb); + builder_.add_type(type); + return builder_.Finish(); +} + +struct SVDFOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_RANK = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 8 + }; + int32_t rank() const { return GetField(VT_RANK, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_RANK) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct SVDFOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_rank(int32_t rank) { fbb_.AddElement(SVDFOptions::VT_RANK, rank, 0); } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(SVDFOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(SVDFOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit SVDFOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SVDFOptionsBuilder &operator=(const SVDFOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSVDFOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t rank = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + bool asymmetric_quantize_inputs = false) +{ + SVDFOptionsBuilder builder_(_fbb); + builder_.add_rank(rank); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct RNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 6 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct RNNOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(RNNOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(RNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit RNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + RNNOptionsBuilder &operator=(const RNNOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateRNNOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + bool asymmetric_quantize_inputs = false) +{ + RNNOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct SequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TIME_MAJOR = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 8 + }; + bool time_major() const { return GetField(VT_TIME_MAJOR, 0) != 0; } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_TIME_MAJOR) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct SequenceRNNOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_time_major(bool time_major) + { + fbb_.AddElement(SequenceRNNOptions::VT_TIME_MAJOR, static_cast(time_major), + 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(SequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(SequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit SequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SequenceRNNOptionsBuilder &operator=(const SequenceRNNOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSequenceRNNOptions( + flatbuffers::FlatBufferBuilder &_fbb, bool time_major = false, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + bool asymmetric_quantize_inputs = false) +{ + SequenceRNNOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_time_major(time_major); + return builder_.Finish(); +} + +struct BidirectionalSequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TIME_MAJOR = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6, + VT_MERGE_OUTPUTS = 8, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 10 + }; + bool time_major() const { return GetField(VT_TIME_MAJOR, 0) != 0; } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool merge_outputs() const { return GetField(VT_MERGE_OUTPUTS, 0) != 0; } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_TIME_MAJOR) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_MERGE_OUTPUTS) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct BidirectionalSequenceRNNOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_time_major(bool time_major) + { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_TIME_MAJOR, + static_cast(time_major), 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_merge_outputs(bool merge_outputs) + { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_MERGE_OUTPUTS, + static_cast(merge_outputs), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit BidirectionalSequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BidirectionalSequenceRNNOptionsBuilder &operator=(const BidirectionalSequenceRNNOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBidirectionalSequenceRNNOptions( + flatbuffers::FlatBufferBuilder &_fbb, bool time_major = false, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + bool merge_outputs = false, bool asymmetric_quantize_inputs = false) +{ + BidirectionalSequenceRNNOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_merge_outputs(merge_outputs); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_time_major(time_major); + return builder_.Finish(); +} + +struct FullyConnectedOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_WEIGHTS_FORMAT = 6, + VT_KEEP_NUM_DIMS = 8, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 10 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + FullyConnectedOptionsWeightsFormat weights_format() const + { + return static_cast(GetField(VT_WEIGHTS_FORMAT, 0)); + } + bool keep_num_dims() const { return GetField(VT_KEEP_NUM_DIMS, 0) != 0; } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_WEIGHTS_FORMAT) && + VerifyField(verifier, VT_KEEP_NUM_DIMS) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct FullyConnectedOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(FullyConnectedOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_weights_format(FullyConnectedOptionsWeightsFormat weights_format) + { + fbb_.AddElement(FullyConnectedOptions::VT_WEIGHTS_FORMAT, + static_cast(weights_format), 0); + } + void add_keep_num_dims(bool keep_num_dims) + { + fbb_.AddElement(FullyConnectedOptions::VT_KEEP_NUM_DIMS, + static_cast(keep_num_dims), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(FullyConnectedOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit FullyConnectedOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FullyConnectedOptionsBuilder &operator=(const FullyConnectedOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFullyConnectedOptions( + flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + FullyConnectedOptionsWeightsFormat weights_format = FullyConnectedOptionsWeightsFormat_DEFAULT, + bool keep_num_dims = false, bool asymmetric_quantize_inputs = false) +{ + FullyConnectedOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_keep_num_dims(keep_num_dims); + builder_.add_weights_format(weights_format); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct SoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BETA = 4 + }; + float beta() const { return GetField(VT_BETA, 0.0f); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BETA) && + verifier.EndTable(); + } +}; + +struct SoftmaxOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_beta(float beta) { fbb_.AddElement(SoftmaxOptions::VT_BETA, beta, 0.0f); } + explicit SoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SoftmaxOptionsBuilder &operator=(const SoftmaxOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb, float beta = 0.0f) +{ + SoftmaxOptionsBuilder builder_(_fbb); + builder_.add_beta(beta); + return builder_.Finish(); +} + +struct ConcatenationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_AXIS = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6 + }; + int32_t axis() const { return GetField(VT_AXIS, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_AXIS) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct ConcatenationOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(int32_t axis) { fbb_.AddElement(ConcatenationOptions::VT_AXIS, axis, 0); } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(ConcatenationOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit ConcatenationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ConcatenationOptionsBuilder &operator=(const ConcatenationOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateConcatenationOptions( + flatbuffers::FlatBufferBuilder &_fbb, int32_t axis = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + ConcatenationOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct AddOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct AddOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(AddOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit AddOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + AddOptionsBuilder &operator=(const AddOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateAddOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + AddOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct MulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct MulOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(MulOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit MulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MulOptionsBuilder &operator=(const MulOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMulOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + MulOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct L2NormOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct L2NormOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(L2NormOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit L2NormOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + L2NormOptionsBuilder &operator=(const L2NormOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateL2NormOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + L2NormOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct LocalResponseNormalizationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_RADIUS = 4, + VT_BIAS = 6, + VT_ALPHA = 8, + VT_BETA = 10 + }; + int32_t radius() const { return GetField(VT_RADIUS, 0); } + float bias() const { return GetField(VT_BIAS, 0.0f); } + float alpha() const { return GetField(VT_ALPHA, 0.0f); } + float beta() const { return GetField(VT_BETA, 0.0f); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_RADIUS) && + VerifyField(verifier, VT_BIAS) && VerifyField(verifier, VT_ALPHA) && + VerifyField(verifier, VT_BETA) && verifier.EndTable(); + } +}; + +struct LocalResponseNormalizationOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_radius(int32_t radius) + { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_RADIUS, radius, 0); + } + void add_bias(float bias) + { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_BIAS, bias, 0.0f); + } + void add_alpha(float alpha) + { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_ALPHA, alpha, 0.0f); + } + void add_beta(float beta) + { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_BETA, beta, 0.0f); + } + explicit LocalResponseNormalizationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LocalResponseNormalizationOptionsBuilder & + operator=(const LocalResponseNormalizationOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLocalResponseNormalizationOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t radius = 0, + float bias = 0.0f, float alpha = 0.0f, float beta = 0.0f) +{ + LocalResponseNormalizationOptionsBuilder builder_(_fbb); + builder_.add_beta(beta); + builder_.add_alpha(alpha); + builder_.add_bias(bias); + builder_.add_radius(radius); + return builder_.Finish(); +} + +struct LSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_CELL_CLIP = 6, + VT_PROJ_CLIP = 8, + VT_KERNEL_TYPE = 10, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 12 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + float cell_clip() const { return GetField(VT_CELL_CLIP, 0.0f); } + float proj_clip() const { return GetField(VT_PROJ_CLIP, 0.0f); } + LSTMKernelType kernel_type() const + { + return static_cast(GetField(VT_KERNEL_TYPE, 0)); + } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_CELL_CLIP) && + VerifyField(verifier, VT_PROJ_CLIP) && + VerifyField(verifier, VT_KERNEL_TYPE) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct LSTMOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(LSTMOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_cell_clip(float cell_clip) + { + fbb_.AddElement(LSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f); + } + void add_proj_clip(float proj_clip) + { + fbb_.AddElement(LSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f); + } + void add_kernel_type(LSTMKernelType kernel_type) + { + fbb_.AddElement(LSTMOptions::VT_KERNEL_TYPE, static_cast(kernel_type), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(LSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit LSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LSTMOptionsBuilder &operator=(const LSTMOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLSTMOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + float cell_clip = 0.0f, float proj_clip = 0.0f, + LSTMKernelType kernel_type = LSTMKernelType_FULL, + bool asymmetric_quantize_inputs = false) +{ + LSTMOptionsBuilder builder_(_fbb); + builder_.add_proj_clip(proj_clip); + builder_.add_cell_clip(cell_clip); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_kernel_type(kernel_type); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct UnidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_CELL_CLIP = 6, + VT_PROJ_CLIP = 8, + VT_TIME_MAJOR = 10, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 12 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + float cell_clip() const { return GetField(VT_CELL_CLIP, 0.0f); } + float proj_clip() const { return GetField(VT_PROJ_CLIP, 0.0f); } + bool time_major() const { return GetField(VT_TIME_MAJOR, 0) != 0; } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_CELL_CLIP) && + VerifyField(verifier, VT_PROJ_CLIP) && + VerifyField(verifier, VT_TIME_MAJOR) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct UnidirectionalSequenceLSTMOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_cell_clip(float cell_clip) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f); + } + void add_proj_clip(float proj_clip) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f); + } + void add_time_major(bool time_major) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_TIME_MAJOR, + static_cast(time_major), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit UnidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + UnidirectionalSequenceLSTMOptionsBuilder & + operator=(const UnidirectionalSequenceLSTMOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateUnidirectionalSequenceLSTMOptions( + flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + float cell_clip = 0.0f, float proj_clip = 0.0f, bool time_major = false, + bool asymmetric_quantize_inputs = false) +{ + UnidirectionalSequenceLSTMOptionsBuilder builder_(_fbb); + builder_.add_proj_clip(proj_clip); + builder_.add_cell_clip(cell_clip); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_time_major(time_major); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct BidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_CELL_CLIP = 6, + VT_PROJ_CLIP = 8, + VT_MERGE_OUTPUTS = 10, + VT_TIME_MAJOR = 12, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 14 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + float cell_clip() const { return GetField(VT_CELL_CLIP, 0.0f); } + float proj_clip() const { return GetField(VT_PROJ_CLIP, 0.0f); } + bool merge_outputs() const { return GetField(VT_MERGE_OUTPUTS, 0) != 0; } + bool time_major() const { return GetField(VT_TIME_MAJOR, 1) != 0; } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_CELL_CLIP) && + VerifyField(verifier, VT_PROJ_CLIP) && + VerifyField(verifier, VT_MERGE_OUTPUTS) && + VerifyField(verifier, VT_TIME_MAJOR) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct BidirectionalSequenceLSTMOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_cell_clip(float cell_clip) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f); + } + void add_proj_clip(float proj_clip) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f); + } + void add_merge_outputs(bool merge_outputs) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_MERGE_OUTPUTS, + static_cast(merge_outputs), 0); + } + void add_time_major(bool time_major) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_TIME_MAJOR, + static_cast(time_major), 1); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit BidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BidirectionalSequenceLSTMOptionsBuilder & + operator=(const BidirectionalSequenceLSTMOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBidirectionalSequenceLSTMOptions( + flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + float cell_clip = 0.0f, float proj_clip = 0.0f, bool merge_outputs = false, + bool time_major = true, bool asymmetric_quantize_inputs = false) +{ + BidirectionalSequenceLSTMOptionsBuilder builder_(_fbb); + builder_.add_proj_clip(proj_clip); + builder_.add_cell_clip(cell_clip); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_time_major(time_major); + builder_.add_merge_outputs(merge_outputs); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct ResizeBilinearOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_ALIGN_CORNERS = 8, + VT_HALF_PIXEL_CENTERS = 10 + }; + bool align_corners() const { return GetField(VT_ALIGN_CORNERS, 0) != 0; } + bool half_pixel_centers() const { return GetField(VT_HALF_PIXEL_CENTERS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_ALIGN_CORNERS) && + VerifyField(verifier, VT_HALF_PIXEL_CENTERS) && verifier.EndTable(); + } +}; + +struct ResizeBilinearOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_align_corners(bool align_corners) + { + fbb_.AddElement(ResizeBilinearOptions::VT_ALIGN_CORNERS, + static_cast(align_corners), 0); + } + void add_half_pixel_centers(bool half_pixel_centers) + { + fbb_.AddElement(ResizeBilinearOptions::VT_HALF_PIXEL_CENTERS, + static_cast(half_pixel_centers), 0); + } + explicit ResizeBilinearOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ResizeBilinearOptionsBuilder &operator=(const ResizeBilinearOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateResizeBilinearOptions(flatbuffers::FlatBufferBuilder &_fbb, bool align_corners = false, + bool half_pixel_centers = false) +{ + ResizeBilinearOptionsBuilder builder_(_fbb); + builder_.add_half_pixel_centers(half_pixel_centers); + builder_.add_align_corners(align_corners); + return builder_.Finish(); +} + +struct ResizeNearestNeighborOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_ALIGN_CORNERS = 4 + }; + bool align_corners() const { return GetField(VT_ALIGN_CORNERS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_ALIGN_CORNERS) && + verifier.EndTable(); + } +}; + +struct ResizeNearestNeighborOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_align_corners(bool align_corners) + { + fbb_.AddElement(ResizeNearestNeighborOptions::VT_ALIGN_CORNERS, + static_cast(align_corners), 0); + } + explicit ResizeNearestNeighborOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ResizeNearestNeighborOptionsBuilder &operator=(const ResizeNearestNeighborOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateResizeNearestNeighborOptions(flatbuffers::FlatBufferBuilder &_fbb, bool align_corners = false) +{ + ResizeNearestNeighborOptionsBuilder builder_(_fbb); + builder_.add_align_corners(align_corners); + return builder_.Finish(); +} + +struct CallOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_SUBGRAPH = 4 + }; + uint32_t subgraph() const { return GetField(VT_SUBGRAPH, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_SUBGRAPH) && + verifier.EndTable(); + } +}; + +struct CallOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_subgraph(uint32_t subgraph) + { + fbb_.AddElement(CallOptions::VT_SUBGRAPH, subgraph, 0); + } + explicit CallOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + CallOptionsBuilder &operator=(const CallOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCallOptions(flatbuffers::FlatBufferBuilder &_fbb, + uint32_t subgraph = 0) +{ + CallOptionsBuilder builder_(_fbb); + builder_.add_subgraph(subgraph); + return builder_.Finish(); +} + +struct PadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct PadOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit PadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + PadOptionsBuilder &operator=(const PadOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePadOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + PadOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct PadV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct PadV2OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit PadV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + PadV2OptionsBuilder &operator=(const PadV2OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePadV2Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + PadV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ReshapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NEW_SHAPE = 4 + }; + const flatbuffers::Vector *new_shape() const + { + return GetPointer *>(VT_NEW_SHAPE); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NEW_SHAPE) && + verifier.VerifyVector(new_shape()) && verifier.EndTable(); + } +}; + +struct ReshapeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_new_shape(flatbuffers::Offset> new_shape) + { + fbb_.AddOffset(ReshapeOptions::VT_NEW_SHAPE, new_shape); + } + explicit ReshapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ReshapeOptionsBuilder &operator=(const ReshapeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateReshapeOptions(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> new_shape = 0) +{ + ReshapeOptionsBuilder builder_(_fbb); + builder_.add_new_shape(new_shape); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateReshapeOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *new_shape = nullptr) +{ + return circle::CreateReshapeOptions(_fbb, new_shape ? _fbb.CreateVector(*new_shape) : 0); +} + +struct SpaceToBatchNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SpaceToBatchNDOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SpaceToBatchNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SpaceToBatchNDOptionsBuilder &operator=(const SpaceToBatchNDOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSpaceToBatchNDOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SpaceToBatchNDOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct BatchToSpaceNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct BatchToSpaceNDOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit BatchToSpaceNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BatchToSpaceNDOptionsBuilder &operator=(const BatchToSpaceNDOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateBatchToSpaceNDOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + BatchToSpaceNDOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SkipGramOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NGRAM_SIZE = 4, + VT_MAX_SKIP_SIZE = 6, + VT_INCLUDE_ALL_NGRAMS = 8 + }; + int32_t ngram_size() const { return GetField(VT_NGRAM_SIZE, 0); } + int32_t max_skip_size() const { return GetField(VT_MAX_SKIP_SIZE, 0); } + bool include_all_ngrams() const { return GetField(VT_INCLUDE_ALL_NGRAMS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NGRAM_SIZE) && + VerifyField(verifier, VT_MAX_SKIP_SIZE) && + VerifyField(verifier, VT_INCLUDE_ALL_NGRAMS) && verifier.EndTable(); + } +}; + +struct SkipGramOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_ngram_size(int32_t ngram_size) + { + fbb_.AddElement(SkipGramOptions::VT_NGRAM_SIZE, ngram_size, 0); + } + void add_max_skip_size(int32_t max_skip_size) + { + fbb_.AddElement(SkipGramOptions::VT_MAX_SKIP_SIZE, max_skip_size, 0); + } + void add_include_all_ngrams(bool include_all_ngrams) + { + fbb_.AddElement(SkipGramOptions::VT_INCLUDE_ALL_NGRAMS, + static_cast(include_all_ngrams), 0); + } + explicit SkipGramOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SkipGramOptionsBuilder &operator=(const SkipGramOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSkipGramOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t ngram_size = 0, + int32_t max_skip_size = 0, bool include_all_ngrams = false) +{ + SkipGramOptionsBuilder builder_(_fbb); + builder_.add_max_skip_size(max_skip_size); + builder_.add_ngram_size(ngram_size); + builder_.add_include_all_ngrams(include_all_ngrams); + return builder_.Finish(); +} + +struct SpaceToDepthOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BLOCK_SIZE = 4 + }; + int32_t block_size() const { return GetField(VT_BLOCK_SIZE, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BLOCK_SIZE) && + verifier.EndTable(); + } +}; + +struct SpaceToDepthOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_block_size(int32_t block_size) + { + fbb_.AddElement(SpaceToDepthOptions::VT_BLOCK_SIZE, block_size, 0); + } + explicit SpaceToDepthOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SpaceToDepthOptionsBuilder &operator=(const SpaceToDepthOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSpaceToDepthOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t block_size = 0) +{ + SpaceToDepthOptionsBuilder builder_(_fbb); + builder_.add_block_size(block_size); + return builder_.Finish(); +} + +struct DepthToSpaceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BLOCK_SIZE = 4 + }; + int32_t block_size() const { return GetField(VT_BLOCK_SIZE, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BLOCK_SIZE) && + verifier.EndTable(); + } +}; + +struct DepthToSpaceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_block_size(int32_t block_size) + { + fbb_.AddElement(DepthToSpaceOptions::VT_BLOCK_SIZE, block_size, 0); + } + explicit DepthToSpaceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DepthToSpaceOptionsBuilder &operator=(const DepthToSpaceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDepthToSpaceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t block_size = 0) +{ + DepthToSpaceOptionsBuilder builder_(_fbb); + builder_.add_block_size(block_size); + return builder_.Finish(); +} + +struct SubOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct SubOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(SubOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit SubOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SubOptionsBuilder &operator=(const SubOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSubOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + SubOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct DivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct DivOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(DivOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit DivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DivOptionsBuilder &operator=(const DivOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDivOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + DivOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct TopKV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct TopKV2OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit TopKV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TopKV2OptionsBuilder &operator=(const TopKV2OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTopKV2Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + TopKV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct EmbeddingLookupSparseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_COMBINER = 4 + }; + CombinerType combiner() const + { + return static_cast(GetField(VT_COMBINER, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_COMBINER) && + verifier.EndTable(); + } +}; + +struct EmbeddingLookupSparseOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_combiner(CombinerType combiner) + { + fbb_.AddElement(EmbeddingLookupSparseOptions::VT_COMBINER, + static_cast(combiner), 0); + } + explicit EmbeddingLookupSparseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + EmbeddingLookupSparseOptionsBuilder &operator=(const EmbeddingLookupSparseOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateEmbeddingLookupSparseOptions(flatbuffers::FlatBufferBuilder &_fbb, + CombinerType combiner = CombinerType_SUM) +{ + EmbeddingLookupSparseOptionsBuilder builder_(_fbb); + builder_.add_combiner(combiner); + return builder_.Finish(); +} + +struct GatherOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_AXIS = 4 + }; + int32_t axis() const { return GetField(VT_AXIS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_AXIS) && + verifier.EndTable(); + } +}; + +struct GatherOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(int32_t axis) { fbb_.AddElement(GatherOptions::VT_AXIS, axis, 0); } + explicit GatherOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + GatherOptionsBuilder &operator=(const GatherOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateGatherOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t axis = 0) +{ + GatherOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + return builder_.Finish(); +} + +struct TransposeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct TransposeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit TransposeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TransposeOptionsBuilder &operator=(const TransposeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateTransposeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + TransposeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ExpOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ExpOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ExpOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ExpOptionsBuilder &operator=(const ExpOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateExpOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + ExpOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct CosOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct CosOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit CosOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + CosOptionsBuilder &operator=(const CosOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCosOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + CosOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ReducerOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_KEEP_DIMS = 4 + }; + bool keep_dims() const { return GetField(VT_KEEP_DIMS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_KEEP_DIMS) && + verifier.EndTable(); + } +}; + +struct ReducerOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_keep_dims(bool keep_dims) + { + fbb_.AddElement(ReducerOptions::VT_KEEP_DIMS, static_cast(keep_dims), 0); + } + explicit ReducerOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ReducerOptionsBuilder &operator=(const ReducerOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateReducerOptions(flatbuffers::FlatBufferBuilder &_fbb, bool keep_dims = false) +{ + ReducerOptionsBuilder builder_(_fbb); + builder_.add_keep_dims(keep_dims); + return builder_.Finish(); +} + +struct SqueezeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_SQUEEZE_DIMS = 4 + }; + const flatbuffers::Vector *squeeze_dims() const + { + return GetPointer *>(VT_SQUEEZE_DIMS); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_SQUEEZE_DIMS) && + verifier.VerifyVector(squeeze_dims()) && verifier.EndTable(); + } +}; + +struct SqueezeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_squeeze_dims(flatbuffers::Offset> squeeze_dims) + { + fbb_.AddOffset(SqueezeOptions::VT_SQUEEZE_DIMS, squeeze_dims); + } + explicit SqueezeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SqueezeOptionsBuilder &operator=(const SqueezeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSqueezeOptions(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> squeeze_dims = 0) +{ + SqueezeOptionsBuilder builder_(_fbb); + builder_.add_squeeze_dims(squeeze_dims); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateSqueezeOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *squeeze_dims = nullptr) +{ + return circle::CreateSqueezeOptions(_fbb, + squeeze_dims ? _fbb.CreateVector(*squeeze_dims) : 0); +} + +struct SplitOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NUM_SPLITS = 4 + }; + int32_t num_splits() const { return GetField(VT_NUM_SPLITS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NUM_SPLITS) && + verifier.EndTable(); + } +}; + +struct SplitOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_splits(int32_t num_splits) + { + fbb_.AddElement(SplitOptions::VT_NUM_SPLITS, num_splits, 0); + } + explicit SplitOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SplitOptionsBuilder &operator=(const SplitOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSplitOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t num_splits = 0) +{ + SplitOptionsBuilder builder_(_fbb); + builder_.add_num_splits(num_splits); + return builder_.Finish(); +} + +struct SplitVOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NUM_SPLITS = 4 + }; + int32_t num_splits() const { return GetField(VT_NUM_SPLITS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NUM_SPLITS) && + verifier.EndTable(); + } +}; + +struct SplitVOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_splits(int32_t num_splits) + { + fbb_.AddElement(SplitVOptions::VT_NUM_SPLITS, num_splits, 0); + } + explicit SplitVOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SplitVOptionsBuilder &operator=(const SplitVOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSplitVOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t num_splits = 0) +{ + SplitVOptionsBuilder builder_(_fbb); + builder_.add_num_splits(num_splits); + return builder_.Finish(); +} + +struct StridedSliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BEGIN_MASK = 4, + VT_END_MASK = 6, + VT_ELLIPSIS_MASK = 8, + VT_NEW_AXIS_MASK = 10, + VT_SHRINK_AXIS_MASK = 12 + }; + int32_t begin_mask() const { return GetField(VT_BEGIN_MASK, 0); } + int32_t end_mask() const { return GetField(VT_END_MASK, 0); } + int32_t ellipsis_mask() const { return GetField(VT_ELLIPSIS_MASK, 0); } + int32_t new_axis_mask() const { return GetField(VT_NEW_AXIS_MASK, 0); } + int32_t shrink_axis_mask() const { return GetField(VT_SHRINK_AXIS_MASK, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BEGIN_MASK) && + VerifyField(verifier, VT_END_MASK) && + VerifyField(verifier, VT_ELLIPSIS_MASK) && + VerifyField(verifier, VT_NEW_AXIS_MASK) && + VerifyField(verifier, VT_SHRINK_AXIS_MASK) && verifier.EndTable(); + } +}; + +struct StridedSliceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_begin_mask(int32_t begin_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_BEGIN_MASK, begin_mask, 0); + } + void add_end_mask(int32_t end_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_END_MASK, end_mask, 0); + } + void add_ellipsis_mask(int32_t ellipsis_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_ELLIPSIS_MASK, ellipsis_mask, 0); + } + void add_new_axis_mask(int32_t new_axis_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_NEW_AXIS_MASK, new_axis_mask, 0); + } + void add_shrink_axis_mask(int32_t shrink_axis_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_SHRINK_AXIS_MASK, shrink_axis_mask, 0); + } + explicit StridedSliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + StridedSliceOptionsBuilder &operator=(const StridedSliceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateStridedSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t begin_mask = 0, + int32_t end_mask = 0, int32_t ellipsis_mask = 0, + int32_t new_axis_mask = 0, int32_t shrink_axis_mask = 0) +{ + StridedSliceOptionsBuilder builder_(_fbb); + builder_.add_shrink_axis_mask(shrink_axis_mask); + builder_.add_new_axis_mask(new_axis_mask); + builder_.add_ellipsis_mask(ellipsis_mask); + builder_.add_end_mask(end_mask); + builder_.add_begin_mask(begin_mask); + return builder_.Finish(); +} + +struct LogSoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LogSoftmaxOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogSoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LogSoftmaxOptionsBuilder &operator=(const LogSoftmaxOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLogSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LogSoftmaxOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct CastOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_IN_DATA_TYPE = 4, + VT_OUT_DATA_TYPE = 6 + }; + TensorType in_data_type() const + { + return static_cast(GetField(VT_IN_DATA_TYPE, 0)); + } + TensorType out_data_type() const + { + return static_cast(GetField(VT_OUT_DATA_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_IN_DATA_TYPE) && + VerifyField(verifier, VT_OUT_DATA_TYPE) && verifier.EndTable(); + } +}; + +struct CastOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_in_data_type(TensorType in_data_type) + { + fbb_.AddElement(CastOptions::VT_IN_DATA_TYPE, static_cast(in_data_type), 0); + } + void add_out_data_type(TensorType out_data_type) + { + fbb_.AddElement(CastOptions::VT_OUT_DATA_TYPE, static_cast(out_data_type), 0); + } + explicit CastOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + CastOptionsBuilder &operator=(const CastOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateCastOptions(flatbuffers::FlatBufferBuilder &_fbb, + TensorType in_data_type = TensorType_FLOAT32, + TensorType out_data_type = TensorType_FLOAT32) +{ + CastOptionsBuilder builder_(_fbb); + builder_.add_out_data_type(out_data_type); + builder_.add_in_data_type(in_data_type); + return builder_.Finish(); +} + +struct DequantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct DequantizeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit DequantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DequantizeOptionsBuilder &operator=(const DequantizeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDequantizeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + DequantizeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct MaximumMinimumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct MaximumMinimumOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit MaximumMinimumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MaximumMinimumOptionsBuilder &operator=(const MaximumMinimumOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMaximumMinimumOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + MaximumMinimumOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct TileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct TileOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit TileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TileOptionsBuilder &operator=(const TileOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTileOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + TileOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ArgMaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_OUTPUT_TYPE = 4 + }; + TensorType output_type() const + { + return static_cast(GetField(VT_OUTPUT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_OUTPUT_TYPE) && + verifier.EndTable(); + } +}; + +struct ArgMaxOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_output_type(TensorType output_type) + { + fbb_.AddElement(ArgMaxOptions::VT_OUTPUT_TYPE, static_cast(output_type), 0); + } + explicit ArgMaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ArgMaxOptionsBuilder &operator=(const ArgMaxOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateArgMaxOptions(flatbuffers::FlatBufferBuilder &_fbb, + TensorType output_type = TensorType_FLOAT32) +{ + ArgMaxOptionsBuilder builder_(_fbb); + builder_.add_output_type(output_type); + return builder_.Finish(); +} + +struct ArgMinOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_OUTPUT_TYPE = 4 + }; + TensorType output_type() const + { + return static_cast(GetField(VT_OUTPUT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_OUTPUT_TYPE) && + verifier.EndTable(); + } +}; + +struct ArgMinOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_output_type(TensorType output_type) + { + fbb_.AddElement(ArgMinOptions::VT_OUTPUT_TYPE, static_cast(output_type), 0); + } + explicit ArgMinOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ArgMinOptionsBuilder &operator=(const ArgMinOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateArgMinOptions(flatbuffers::FlatBufferBuilder &_fbb, + TensorType output_type = TensorType_FLOAT32) +{ + ArgMinOptionsBuilder builder_(_fbb); + builder_.add_output_type(output_type); + return builder_.Finish(); +} + +struct GreaterOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct GreaterOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit GreaterOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + GreaterOptionsBuilder &operator=(const GreaterOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateGreaterOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + GreaterOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct GreaterEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct GreaterEqualOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit GreaterEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + GreaterEqualOptionsBuilder &operator=(const GreaterEqualOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateGreaterEqualOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + GreaterEqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LessOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LessOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LessOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LessOptionsBuilder &operator=(const LessOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLessOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LessOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LessEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LessEqualOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LessEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LessEqualOptionsBuilder &operator=(const LessEqualOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLessEqualOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LessEqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct NegOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct NegOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NegOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + NegOptionsBuilder &operator=(const NegOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateNegOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + NegOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SelectOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SelectOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SelectOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SelectOptionsBuilder &operator=(const SelectOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSelectOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SelectOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SliceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SliceOptionsBuilder &operator=(const SliceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSliceOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SliceOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct TransposeConvOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8 + }; + Padding padding() const { return static_cast(GetField(VT_PADDING, 0)); } + int32_t stride_w() const { return GetField(VT_STRIDE_W, 0); } + int32_t stride_h() const { return GetField(VT_STRIDE_H, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_PADDING) && + VerifyField(verifier, VT_STRIDE_W) && + VerifyField(verifier, VT_STRIDE_H) && verifier.EndTable(); + } +}; + +struct TransposeConvOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(Padding padding) + { + fbb_.AddElement(TransposeConvOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) + { + fbb_.AddElement(TransposeConvOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) + { + fbb_.AddElement(TransposeConvOptions::VT_STRIDE_H, stride_h, 0); + } + explicit TransposeConvOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TransposeConvOptionsBuilder &operator=(const TransposeConvOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateTransposeConvOptions(flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME, + int32_t stride_w = 0, int32_t stride_h = 0) +{ + TransposeConvOptionsBuilder builder_(_fbb); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_padding(padding); + return builder_.Finish(); +} + +struct ExpandDimsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ExpandDimsOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ExpandDimsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ExpandDimsOptionsBuilder &operator=(const ExpandDimsOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateExpandDimsOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + ExpandDimsOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SparseToDenseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALIDATE_INDICES = 4 + }; + bool validate_indices() const { return GetField(VT_VALIDATE_INDICES, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_VALIDATE_INDICES) && + verifier.EndTable(); + } +}; + +struct SparseToDenseOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_validate_indices(bool validate_indices) + { + fbb_.AddElement(SparseToDenseOptions::VT_VALIDATE_INDICES, + static_cast(validate_indices), 0); + } + explicit SparseToDenseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SparseToDenseOptionsBuilder &operator=(const SparseToDenseOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSparseToDenseOptions(flatbuffers::FlatBufferBuilder &_fbb, bool validate_indices = false) +{ + SparseToDenseOptionsBuilder builder_(_fbb); + builder_.add_validate_indices(validate_indices); + return builder_.Finish(); +} + +struct EqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct EqualOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit EqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + EqualOptionsBuilder &operator=(const EqualOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateEqualOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + EqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct NotEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct NotEqualOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NotEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + NotEqualOptionsBuilder &operator=(const NotEqualOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateNotEqualOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + NotEqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ShapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_OUT_TYPE = 4 + }; + TensorType out_type() const { return static_cast(GetField(VT_OUT_TYPE, 0)); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_OUT_TYPE) && + verifier.EndTable(); + } +}; + +struct ShapeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_out_type(TensorType out_type) + { + fbb_.AddElement(ShapeOptions::VT_OUT_TYPE, static_cast(out_type), 0); + } + explicit ShapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ShapeOptionsBuilder &operator=(const ShapeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateShapeOptions(flatbuffers::FlatBufferBuilder &_fbb, TensorType out_type = TensorType_FLOAT32) +{ + ShapeOptionsBuilder builder_(_fbb); + builder_.add_out_type(out_type); + return builder_.Finish(); +} + +struct RankOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct RankOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit RankOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + RankOptionsBuilder &operator=(const RankOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRankOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + RankOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct PowOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct PowOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit PowOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + PowOptionsBuilder &operator=(const PowOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePowOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + PowOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct FakeQuantOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_MIN = 4, + VT_MAX = 6, + VT_NUM_BITS = 8, + VT_NARROW_RANGE = 10 + }; + float min() const { return GetField(VT_MIN, 0.0f); } + float max() const { return GetField(VT_MAX, 0.0f); } + int32_t num_bits() const { return GetField(VT_NUM_BITS, 0); } + bool narrow_range() const { return GetField(VT_NARROW_RANGE, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_MIN) && + VerifyField(verifier, VT_MAX) && VerifyField(verifier, VT_NUM_BITS) && + VerifyField(verifier, VT_NARROW_RANGE) && verifier.EndTable(); + } +}; + +struct FakeQuantOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_min(float min) { fbb_.AddElement(FakeQuantOptions::VT_MIN, min, 0.0f); } + void add_max(float max) { fbb_.AddElement(FakeQuantOptions::VT_MAX, max, 0.0f); } + void add_num_bits(int32_t num_bits) + { + fbb_.AddElement(FakeQuantOptions::VT_NUM_BITS, num_bits, 0); + } + void add_narrow_range(bool narrow_range) + { + fbb_.AddElement(FakeQuantOptions::VT_NARROW_RANGE, static_cast(narrow_range), + 0); + } + explicit FakeQuantOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FakeQuantOptionsBuilder &operator=(const FakeQuantOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateFakeQuantOptions(flatbuffers::FlatBufferBuilder &_fbb, float min = 0.0f, float max = 0.0f, + int32_t num_bits = 0, bool narrow_range = false) +{ + FakeQuantOptionsBuilder builder_(_fbb); + builder_.add_num_bits(num_bits); + builder_.add_max(max); + builder_.add_min(min); + builder_.add_narrow_range(narrow_range); + return builder_.Finish(); +} + +struct PackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALUES_COUNT = 4, + VT_AXIS = 6 + }; + int32_t values_count() const { return GetField(VT_VALUES_COUNT, 0); } + int32_t axis() const { return GetField(VT_AXIS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_VALUES_COUNT) && + VerifyField(verifier, VT_AXIS) && verifier.EndTable(); + } +}; + +struct PackOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values_count(int32_t values_count) + { + fbb_.AddElement(PackOptions::VT_VALUES_COUNT, values_count, 0); + } + void add_axis(int32_t axis) { fbb_.AddElement(PackOptions::VT_AXIS, axis, 0); } + explicit PackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + PackOptionsBuilder &operator=(const PackOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreatePackOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t values_count = 0, int32_t axis = 0) +{ + PackOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + builder_.add_values_count(values_count); + return builder_.Finish(); +} + +struct LogicalOrOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LogicalOrOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogicalOrOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LogicalOrOptionsBuilder &operator=(const LogicalOrOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLogicalOrOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LogicalOrOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct OneHotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_AXIS = 4 + }; + int32_t axis() const { return GetField(VT_AXIS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_AXIS) && + verifier.EndTable(); + } +}; + +struct OneHotOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(int32_t axis) { fbb_.AddElement(OneHotOptions::VT_AXIS, axis, 0); } + explicit OneHotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + OneHotOptionsBuilder &operator=(const OneHotOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateOneHotOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t axis = 0) +{ + OneHotOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + return builder_.Finish(); +} + +struct AbsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct AbsOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit AbsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + AbsOptionsBuilder &operator=(const AbsOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAbsOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + AbsOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct HardSwishOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct HardSwishOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit HardSwishOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + HardSwishOptionsBuilder &operator=(const HardSwishOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateHardSwishOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + HardSwishOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LogicalAndOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LogicalAndOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogicalAndOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LogicalAndOptionsBuilder &operator=(const LogicalAndOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLogicalAndOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LogicalAndOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LogicalNotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LogicalNotOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogicalNotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LogicalNotOptionsBuilder &operator=(const LogicalNotOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLogicalNotOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LogicalNotOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct UnpackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NUM = 4, + VT_AXIS = 6 + }; + int32_t num() const { return GetField(VT_NUM, 0); } + int32_t axis() const { return GetField(VT_AXIS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NUM) && + VerifyField(verifier, VT_AXIS) && verifier.EndTable(); + } +}; + +struct UnpackOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num(int32_t num) { fbb_.AddElement(UnpackOptions::VT_NUM, num, 0); } + void add_axis(int32_t axis) { fbb_.AddElement(UnpackOptions::VT_AXIS, axis, 0); } + explicit UnpackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + UnpackOptionsBuilder &operator=(const UnpackOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUnpackOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t num = 0, int32_t axis = 0) +{ + UnpackOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + builder_.add_num(num); + return builder_.Finish(); +} + +struct FloorDivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct FloorDivOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit FloorDivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FloorDivOptionsBuilder &operator=(const FloorDivOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateFloorDivOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + FloorDivOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SquareOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SquareOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SquareOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SquareOptionsBuilder &operator=(const SquareOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSquareOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SquareOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ZerosLikeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ZerosLikeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ZerosLikeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ZerosLikeOptionsBuilder &operator=(const ZerosLikeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateZerosLikeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + ZerosLikeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct FillOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct FillOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit FillOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FillOptionsBuilder &operator=(const FillOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFillOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + FillOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct FloorModOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct FloorModOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit FloorModOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FloorModOptionsBuilder &operator=(const FloorModOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateFloorModOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + FloorModOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct RangeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct RangeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit RangeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + RangeOptionsBuilder &operator=(const RangeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRangeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + RangeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LeakyReluOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_ALPHA = 4 + }; + float alpha() const { return GetField(VT_ALPHA, 0.0f); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_ALPHA) && + verifier.EndTable(); + } +}; + +struct LeakyReluOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_alpha(float alpha) { fbb_.AddElement(LeakyReluOptions::VT_ALPHA, alpha, 0.0f); } + explicit LeakyReluOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LeakyReluOptionsBuilder &operator=(const LeakyReluOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLeakyReluOptions(flatbuffers::FlatBufferBuilder &_fbb, float alpha = 0.0f) +{ + LeakyReluOptionsBuilder builder_(_fbb); + builder_.add_alpha(alpha); + return builder_.Finish(); +} + +struct SquaredDifferenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SquaredDifferenceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SquaredDifferenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SquaredDifferenceOptionsBuilder &operator=(const SquaredDifferenceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSquaredDifferenceOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SquaredDifferenceOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct MirrorPadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_MODE = 4 + }; + MirrorPadMode mode() const { return static_cast(GetField(VT_MODE, 0)); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_MODE) && + verifier.EndTable(); + } +}; + +struct MirrorPadOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_mode(MirrorPadMode mode) + { + fbb_.AddElement(MirrorPadOptions::VT_MODE, static_cast(mode), 0); + } + explicit MirrorPadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MirrorPadOptionsBuilder &operator=(const MirrorPadOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMirrorPadOptions(flatbuffers::FlatBufferBuilder &_fbb, + MirrorPadMode mode = MirrorPadMode_REFLECT) +{ + MirrorPadOptionsBuilder builder_(_fbb); + builder_.add_mode(mode); + return builder_.Finish(); +} + +struct UniqueOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_IDX_OUT_TYPE = 4 + }; + TensorType idx_out_type() const + { + return static_cast(GetField(VT_IDX_OUT_TYPE, 2)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_IDX_OUT_TYPE) && + verifier.EndTable(); + } +}; + +struct UniqueOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_idx_out_type(TensorType idx_out_type) + { + fbb_.AddElement(UniqueOptions::VT_IDX_OUT_TYPE, static_cast(idx_out_type), 2); + } + explicit UniqueOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + UniqueOptionsBuilder &operator=(const UniqueOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateUniqueOptions(flatbuffers::FlatBufferBuilder &_fbb, + TensorType idx_out_type = TensorType_INT32) +{ + UniqueOptionsBuilder builder_(_fbb); + builder_.add_idx_out_type(idx_out_type); + return builder_.Finish(); +} + +struct ReverseV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ReverseV2OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ReverseV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ReverseV2OptionsBuilder &operator=(const ReverseV2OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateReverseV2Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + ReverseV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct AddNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct AddNOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit AddNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + AddNOptionsBuilder &operator=(const AddNOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAddNOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + AddNOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct GatherNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct GatherNdOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit GatherNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + GatherNdOptionsBuilder &operator=(const GatherNdOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateGatherNdOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + GatherNdOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct WhereOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct WhereOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit WhereOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + WhereOptionsBuilder &operator=(const WhereOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateWhereOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + WhereOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ReverseSequenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_SEQ_DIM = 4, + VT_BATCH_DIM = 6 + }; + int32_t seq_dim() const { return GetField(VT_SEQ_DIM, 0); } + int32_t batch_dim() const { return GetField(VT_BATCH_DIM, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_SEQ_DIM) && + VerifyField(verifier, VT_BATCH_DIM) && verifier.EndTable(); + } +}; + +struct ReverseSequenceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_seq_dim(int32_t seq_dim) + { + fbb_.AddElement(ReverseSequenceOptions::VT_SEQ_DIM, seq_dim, 0); + } + void add_batch_dim(int32_t batch_dim) + { + fbb_.AddElement(ReverseSequenceOptions::VT_BATCH_DIM, batch_dim, 0); + } + explicit ReverseSequenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ReverseSequenceOptionsBuilder &operator=(const ReverseSequenceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateReverseSequenceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t seq_dim = 0, + int32_t batch_dim = 0) +{ + ReverseSequenceOptionsBuilder builder_(_fbb); + builder_.add_batch_dim(batch_dim); + builder_.add_seq_dim(seq_dim); + return builder_.Finish(); +} + +struct MatrixDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct MatrixDiagOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit MatrixDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MatrixDiagOptionsBuilder &operator=(const MatrixDiagOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMatrixDiagOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + MatrixDiagOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct QuantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct QuantizeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit QuantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + QuantizeOptionsBuilder &operator=(const QuantizeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateQuantizeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + QuantizeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct MatrixSetDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct MatrixSetDiagOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit MatrixSetDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MatrixSetDiagOptionsBuilder &operator=(const MatrixSetDiagOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMatrixSetDiagOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + MatrixSetDiagOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct IfOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_THEN_SUBGRAPH_INDEX = 4, + VT_ELSE_SUBGRAPH_INDEX = 6 + }; + int32_t then_subgraph_index() const { return GetField(VT_THEN_SUBGRAPH_INDEX, 0); } + int32_t else_subgraph_index() const { return GetField(VT_ELSE_SUBGRAPH_INDEX, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_THEN_SUBGRAPH_INDEX) && + VerifyField(verifier, VT_ELSE_SUBGRAPH_INDEX) && verifier.EndTable(); + } +}; + +struct IfOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_then_subgraph_index(int32_t then_subgraph_index) + { + fbb_.AddElement(IfOptions::VT_THEN_SUBGRAPH_INDEX, then_subgraph_index, 0); + } + void add_else_subgraph_index(int32_t else_subgraph_index) + { + fbb_.AddElement(IfOptions::VT_ELSE_SUBGRAPH_INDEX, else_subgraph_index, 0); + } + explicit IfOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + IfOptionsBuilder &operator=(const IfOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateIfOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t then_subgraph_index = 0, + int32_t else_subgraph_index = 0) +{ + IfOptionsBuilder builder_(_fbb); + builder_.add_else_subgraph_index(else_subgraph_index); + builder_.add_then_subgraph_index(then_subgraph_index); + return builder_.Finish(); +} + +struct WhileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_COND_SUBGRAPH_INDEX = 4, + VT_BODY_SUBGRAPH_INDEX = 6 + }; + int32_t cond_subgraph_index() const { return GetField(VT_COND_SUBGRAPH_INDEX, 0); } + int32_t body_subgraph_index() const { return GetField(VT_BODY_SUBGRAPH_INDEX, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_COND_SUBGRAPH_INDEX) && + VerifyField(verifier, VT_BODY_SUBGRAPH_INDEX) && verifier.EndTable(); + } +}; + +struct WhileOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_cond_subgraph_index(int32_t cond_subgraph_index) + { + fbb_.AddElement(WhileOptions::VT_COND_SUBGRAPH_INDEX, cond_subgraph_index, 0); + } + void add_body_subgraph_index(int32_t body_subgraph_index) + { + fbb_.AddElement(WhileOptions::VT_BODY_SUBGRAPH_INDEX, body_subgraph_index, 0); + } + explicit WhileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + WhileOptionsBuilder &operator=(const WhileOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateWhileOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t cond_subgraph_index = 0, + int32_t body_subgraph_index = 0) +{ + WhileOptionsBuilder builder_(_fbb); + builder_.add_body_subgraph_index(body_subgraph_index); + builder_.add_cond_subgraph_index(cond_subgraph_index); + return builder_.Finish(); +} + +struct NonMaxSuppressionV4Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct NonMaxSuppressionV4OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NonMaxSuppressionV4OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + NonMaxSuppressionV4OptionsBuilder &operator=(const NonMaxSuppressionV4OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateNonMaxSuppressionV4Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + NonMaxSuppressionV4OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct NonMaxSuppressionV5Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct NonMaxSuppressionV5OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NonMaxSuppressionV5OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + NonMaxSuppressionV5OptionsBuilder &operator=(const NonMaxSuppressionV5OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateNonMaxSuppressionV5Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + NonMaxSuppressionV5OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ScatterNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ScatterNdOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ScatterNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ScatterNdOptionsBuilder &operator=(const ScatterNdOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateScatterNdOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + ScatterNdOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SelectV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SelectV2OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SelectV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SelectV2OptionsBuilder &operator=(const SelectV2OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSelectV2Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + SelectV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct DensifyOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct DensifyOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit DensifyOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DensifyOptionsBuilder &operator=(const DensifyOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDensifyOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + DensifyOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SegmentSumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SegmentSumOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SegmentSumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SegmentSumOptionsBuilder &operator=(const SegmentSumOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSegmentSumOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SegmentSumOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct BatchMatMulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_ADJOINT_LHS = 4, + VT_ADJOINT_RHS = 6 + }; + bool adjoint_lhs() const { return GetField(VT_ADJOINT_LHS, 0) != 0; } + bool adjoint_rhs() const { return GetField(VT_ADJOINT_RHS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_ADJOINT_LHS) && + VerifyField(verifier, VT_ADJOINT_RHS) && verifier.EndTable(); + } +}; + +struct BatchMatMulOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_adjoint_lhs(bool adjoint_lhs) + { + fbb_.AddElement(BatchMatMulOptions::VT_ADJOINT_LHS, static_cast(adjoint_lhs), + 0); + } + void add_adjoint_rhs(bool adjoint_rhs) + { + fbb_.AddElement(BatchMatMulOptions::VT_ADJOINT_RHS, static_cast(adjoint_rhs), + 0); + } + explicit BatchMatMulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BatchMatMulOptionsBuilder &operator=(const BatchMatMulOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateBatchMatMulOptions(flatbuffers::FlatBufferBuilder &_fbb, bool adjoint_lhs = false, + bool adjoint_rhs = false) +{ + BatchMatMulOptionsBuilder builder_(_fbb); + builder_.add_adjoint_rhs(adjoint_rhs); + builder_.add_adjoint_lhs(adjoint_lhs); + return builder_.Finish(); +} + +struct InstanceNormOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_EPSILON = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6 + }; + float epsilon() const { return GetField(VT_EPSILON, 0.0f); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_EPSILON) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct InstanceNormOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_epsilon(float epsilon) + { + fbb_.AddElement(InstanceNormOptions::VT_EPSILON, epsilon, 0.0f); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(InstanceNormOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit InstanceNormOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + InstanceNormOptionsBuilder &operator=(const InstanceNormOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateInstanceNormOptions( + flatbuffers::FlatBufferBuilder &_fbb, float epsilon = 0.0f, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + InstanceNormOptionsBuilder builder_(_fbb); + builder_.add_epsilon(epsilon); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct OperatorCode FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BUILTIN_CODE = 4, + VT_CUSTOM_CODE = 6, + VT_VERSION = 8 + }; + BuiltinOperator builtin_code() const + { + return static_cast(GetField(VT_BUILTIN_CODE, 0)); + } + const flatbuffers::String *custom_code() const + { + return GetPointer(VT_CUSTOM_CODE); + } + int32_t version() const { return GetField(VT_VERSION, 1); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BUILTIN_CODE) && + VerifyOffset(verifier, VT_CUSTOM_CODE) && verifier.VerifyString(custom_code()) && + VerifyField(verifier, VT_VERSION) && verifier.EndTable(); + } +}; + +struct OperatorCodeBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_builtin_code(BuiltinOperator builtin_code) + { + fbb_.AddElement(OperatorCode::VT_BUILTIN_CODE, static_cast(builtin_code), 0); + } + void add_custom_code(flatbuffers::Offset custom_code) + { + fbb_.AddOffset(OperatorCode::VT_CUSTOM_CODE, custom_code); + } + void add_version(int32_t version) + { + fbb_.AddElement(OperatorCode::VT_VERSION, version, 1); + } + explicit OperatorCodeBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + OperatorCodeBuilder &operator=(const OperatorCodeBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateOperatorCode(flatbuffers::FlatBufferBuilder &_fbb, + BuiltinOperator builtin_code = BuiltinOperator_ADD, + flatbuffers::Offset custom_code = 0, int32_t version = 1) +{ + OperatorCodeBuilder builder_(_fbb); + builder_.add_version(version); + builder_.add_custom_code(custom_code); + builder_.add_builtin_code(builtin_code); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateOperatorCodeDirect(flatbuffers::FlatBufferBuilder &_fbb, + BuiltinOperator builtin_code = BuiltinOperator_ADD, + const char *custom_code = nullptr, int32_t version = 1) +{ + return circle::CreateOperatorCode(_fbb, builtin_code, + custom_code ? _fbb.CreateString(custom_code) : 0, version); +} + +struct Operator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_OPCODE_INDEX = 4, + VT_INPUTS = 6, + VT_OUTPUTS = 8, + VT_BUILTIN_OPTIONS_TYPE = 10, + VT_BUILTIN_OPTIONS = 12, + VT_CUSTOM_OPTIONS = 14, + VT_CUSTOM_OPTIONS_FORMAT = 16, + VT_MUTATING_VARIABLE_INPUTS = 18, + VT_INTERMEDIATES = 20 + }; + uint32_t opcode_index() const { return GetField(VT_OPCODE_INDEX, 0); } + const flatbuffers::Vector *inputs() const + { + return GetPointer *>(VT_INPUTS); + } + const flatbuffers::Vector *outputs() const + { + return GetPointer *>(VT_OUTPUTS); + } + BuiltinOptions builtin_options_type() const + { + return static_cast(GetField(VT_BUILTIN_OPTIONS_TYPE, 0)); + } + const void *builtin_options() const { return GetPointer(VT_BUILTIN_OPTIONS); } + template const T *builtin_options_as() const; + const Conv2DOptions *builtin_options_as_Conv2DOptions() const + { + return builtin_options_type() == BuiltinOptions_Conv2DOptions + ? static_cast(builtin_options()) + : nullptr; + } + const DepthwiseConv2DOptions *builtin_options_as_DepthwiseConv2DOptions() const + { + return builtin_options_type() == BuiltinOptions_DepthwiseConv2DOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ConcatEmbeddingsOptions *builtin_options_as_ConcatEmbeddingsOptions() const + { + return builtin_options_type() == BuiltinOptions_ConcatEmbeddingsOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LSHProjectionOptions *builtin_options_as_LSHProjectionOptions() const + { + return builtin_options_type() == BuiltinOptions_LSHProjectionOptions + ? static_cast(builtin_options()) + : nullptr; + } + const Pool2DOptions *builtin_options_as_Pool2DOptions() const + { + return builtin_options_type() == BuiltinOptions_Pool2DOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SVDFOptions *builtin_options_as_SVDFOptions() const + { + return builtin_options_type() == BuiltinOptions_SVDFOptions + ? static_cast(builtin_options()) + : nullptr; + } + const RNNOptions *builtin_options_as_RNNOptions() const + { + return builtin_options_type() == BuiltinOptions_RNNOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FullyConnectedOptions *builtin_options_as_FullyConnectedOptions() const + { + return builtin_options_type() == BuiltinOptions_FullyConnectedOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SoftmaxOptions *builtin_options_as_SoftmaxOptions() const + { + return builtin_options_type() == BuiltinOptions_SoftmaxOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ConcatenationOptions *builtin_options_as_ConcatenationOptions() const + { + return builtin_options_type() == BuiltinOptions_ConcatenationOptions + ? static_cast(builtin_options()) + : nullptr; + } + const AddOptions *builtin_options_as_AddOptions() const + { + return builtin_options_type() == BuiltinOptions_AddOptions + ? static_cast(builtin_options()) + : nullptr; + } + const L2NormOptions *builtin_options_as_L2NormOptions() const + { + return builtin_options_type() == BuiltinOptions_L2NormOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LocalResponseNormalizationOptions * + builtin_options_as_LocalResponseNormalizationOptions() const + { + return builtin_options_type() == BuiltinOptions_LocalResponseNormalizationOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LSTMOptions *builtin_options_as_LSTMOptions() const + { + return builtin_options_type() == BuiltinOptions_LSTMOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ResizeBilinearOptions *builtin_options_as_ResizeBilinearOptions() const + { + return builtin_options_type() == BuiltinOptions_ResizeBilinearOptions + ? static_cast(builtin_options()) + : nullptr; + } + const CallOptions *builtin_options_as_CallOptions() const + { + return builtin_options_type() == BuiltinOptions_CallOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ReshapeOptions *builtin_options_as_ReshapeOptions() const + { + return builtin_options_type() == BuiltinOptions_ReshapeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SkipGramOptions *builtin_options_as_SkipGramOptions() const + { + return builtin_options_type() == BuiltinOptions_SkipGramOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SpaceToDepthOptions *builtin_options_as_SpaceToDepthOptions() const + { + return builtin_options_type() == BuiltinOptions_SpaceToDepthOptions + ? static_cast(builtin_options()) + : nullptr; + } + const EmbeddingLookupSparseOptions *builtin_options_as_EmbeddingLookupSparseOptions() const + { + return builtin_options_type() == BuiltinOptions_EmbeddingLookupSparseOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MulOptions *builtin_options_as_MulOptions() const + { + return builtin_options_type() == BuiltinOptions_MulOptions + ? static_cast(builtin_options()) + : nullptr; + } + const PadOptions *builtin_options_as_PadOptions() const + { + return builtin_options_type() == BuiltinOptions_PadOptions + ? static_cast(builtin_options()) + : nullptr; + } + const GatherOptions *builtin_options_as_GatherOptions() const + { + return builtin_options_type() == BuiltinOptions_GatherOptions + ? static_cast(builtin_options()) + : nullptr; + } + const BatchToSpaceNDOptions *builtin_options_as_BatchToSpaceNDOptions() const + { + return builtin_options_type() == BuiltinOptions_BatchToSpaceNDOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SpaceToBatchNDOptions *builtin_options_as_SpaceToBatchNDOptions() const + { + return builtin_options_type() == BuiltinOptions_SpaceToBatchNDOptions + ? static_cast(builtin_options()) + : nullptr; + } + const TransposeOptions *builtin_options_as_TransposeOptions() const + { + return builtin_options_type() == BuiltinOptions_TransposeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ReducerOptions *builtin_options_as_ReducerOptions() const + { + return builtin_options_type() == BuiltinOptions_ReducerOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SubOptions *builtin_options_as_SubOptions() const + { + return builtin_options_type() == BuiltinOptions_SubOptions + ? static_cast(builtin_options()) + : nullptr; + } + const DivOptions *builtin_options_as_DivOptions() const + { + return builtin_options_type() == BuiltinOptions_DivOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SqueezeOptions *builtin_options_as_SqueezeOptions() const + { + return builtin_options_type() == BuiltinOptions_SqueezeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SequenceRNNOptions *builtin_options_as_SequenceRNNOptions() const + { + return builtin_options_type() == BuiltinOptions_SequenceRNNOptions + ? static_cast(builtin_options()) + : nullptr; + } + const StridedSliceOptions *builtin_options_as_StridedSliceOptions() const + { + return builtin_options_type() == BuiltinOptions_StridedSliceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ExpOptions *builtin_options_as_ExpOptions() const + { + return builtin_options_type() == BuiltinOptions_ExpOptions + ? static_cast(builtin_options()) + : nullptr; + } + const TopKV2Options *builtin_options_as_TopKV2Options() const + { + return builtin_options_type() == BuiltinOptions_TopKV2Options + ? static_cast(builtin_options()) + : nullptr; + } + const SplitOptions *builtin_options_as_SplitOptions() const + { + return builtin_options_type() == BuiltinOptions_SplitOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LogSoftmaxOptions *builtin_options_as_LogSoftmaxOptions() const + { + return builtin_options_type() == BuiltinOptions_LogSoftmaxOptions + ? static_cast(builtin_options()) + : nullptr; + } + const CastOptions *builtin_options_as_CastOptions() const + { + return builtin_options_type() == BuiltinOptions_CastOptions + ? static_cast(builtin_options()) + : nullptr; + } + const DequantizeOptions *builtin_options_as_DequantizeOptions() const + { + return builtin_options_type() == BuiltinOptions_DequantizeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MaximumMinimumOptions *builtin_options_as_MaximumMinimumOptions() const + { + return builtin_options_type() == BuiltinOptions_MaximumMinimumOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ArgMaxOptions *builtin_options_as_ArgMaxOptions() const + { + return builtin_options_type() == BuiltinOptions_ArgMaxOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LessOptions *builtin_options_as_LessOptions() const + { + return builtin_options_type() == BuiltinOptions_LessOptions + ? static_cast(builtin_options()) + : nullptr; + } + const NegOptions *builtin_options_as_NegOptions() const + { + return builtin_options_type() == BuiltinOptions_NegOptions + ? static_cast(builtin_options()) + : nullptr; + } + const PadV2Options *builtin_options_as_PadV2Options() const + { + return builtin_options_type() == BuiltinOptions_PadV2Options + ? static_cast(builtin_options()) + : nullptr; + } + const GreaterOptions *builtin_options_as_GreaterOptions() const + { + return builtin_options_type() == BuiltinOptions_GreaterOptions + ? static_cast(builtin_options()) + : nullptr; + } + const GreaterEqualOptions *builtin_options_as_GreaterEqualOptions() const + { + return builtin_options_type() == BuiltinOptions_GreaterEqualOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LessEqualOptions *builtin_options_as_LessEqualOptions() const + { + return builtin_options_type() == BuiltinOptions_LessEqualOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SelectOptions *builtin_options_as_SelectOptions() const + { + return builtin_options_type() == BuiltinOptions_SelectOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SliceOptions *builtin_options_as_SliceOptions() const + { + return builtin_options_type() == BuiltinOptions_SliceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const TransposeConvOptions *builtin_options_as_TransposeConvOptions() const + { + return builtin_options_type() == BuiltinOptions_TransposeConvOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SparseToDenseOptions *builtin_options_as_SparseToDenseOptions() const + { + return builtin_options_type() == BuiltinOptions_SparseToDenseOptions + ? static_cast(builtin_options()) + : nullptr; + } + const TileOptions *builtin_options_as_TileOptions() const + { + return builtin_options_type() == BuiltinOptions_TileOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ExpandDimsOptions *builtin_options_as_ExpandDimsOptions() const + { + return builtin_options_type() == BuiltinOptions_ExpandDimsOptions + ? static_cast(builtin_options()) + : nullptr; + } + const EqualOptions *builtin_options_as_EqualOptions() const + { + return builtin_options_type() == BuiltinOptions_EqualOptions + ? static_cast(builtin_options()) + : nullptr; + } + const NotEqualOptions *builtin_options_as_NotEqualOptions() const + { + return builtin_options_type() == BuiltinOptions_NotEqualOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ShapeOptions *builtin_options_as_ShapeOptions() const + { + return builtin_options_type() == BuiltinOptions_ShapeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const PowOptions *builtin_options_as_PowOptions() const + { + return builtin_options_type() == BuiltinOptions_PowOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ArgMinOptions *builtin_options_as_ArgMinOptions() const + { + return builtin_options_type() == BuiltinOptions_ArgMinOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FakeQuantOptions *builtin_options_as_FakeQuantOptions() const + { + return builtin_options_type() == BuiltinOptions_FakeQuantOptions + ? static_cast(builtin_options()) + : nullptr; + } + const PackOptions *builtin_options_as_PackOptions() const + { + return builtin_options_type() == BuiltinOptions_PackOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LogicalOrOptions *builtin_options_as_LogicalOrOptions() const + { + return builtin_options_type() == BuiltinOptions_LogicalOrOptions + ? static_cast(builtin_options()) + : nullptr; + } + const OneHotOptions *builtin_options_as_OneHotOptions() const + { + return builtin_options_type() == BuiltinOptions_OneHotOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LogicalAndOptions *builtin_options_as_LogicalAndOptions() const + { + return builtin_options_type() == BuiltinOptions_LogicalAndOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LogicalNotOptions *builtin_options_as_LogicalNotOptions() const + { + return builtin_options_type() == BuiltinOptions_LogicalNotOptions + ? static_cast(builtin_options()) + : nullptr; + } + const UnpackOptions *builtin_options_as_UnpackOptions() const + { + return builtin_options_type() == BuiltinOptions_UnpackOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FloorDivOptions *builtin_options_as_FloorDivOptions() const + { + return builtin_options_type() == BuiltinOptions_FloorDivOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SquareOptions *builtin_options_as_SquareOptions() const + { + return builtin_options_type() == BuiltinOptions_SquareOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ZerosLikeOptions *builtin_options_as_ZerosLikeOptions() const + { + return builtin_options_type() == BuiltinOptions_ZerosLikeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FillOptions *builtin_options_as_FillOptions() const + { + return builtin_options_type() == BuiltinOptions_FillOptions + ? static_cast(builtin_options()) + : nullptr; + } + const BidirectionalSequenceLSTMOptions * + builtin_options_as_BidirectionalSequenceLSTMOptions() const + { + return builtin_options_type() == BuiltinOptions_BidirectionalSequenceLSTMOptions + ? static_cast(builtin_options()) + : nullptr; + } + const BidirectionalSequenceRNNOptions *builtin_options_as_BidirectionalSequenceRNNOptions() const + { + return builtin_options_type() == BuiltinOptions_BidirectionalSequenceRNNOptions + ? static_cast(builtin_options()) + : nullptr; + } + const UnidirectionalSequenceLSTMOptions * + builtin_options_as_UnidirectionalSequenceLSTMOptions() const + { + return builtin_options_type() == BuiltinOptions_UnidirectionalSequenceLSTMOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FloorModOptions *builtin_options_as_FloorModOptions() const + { + return builtin_options_type() == BuiltinOptions_FloorModOptions + ? static_cast(builtin_options()) + : nullptr; + } + const RangeOptions *builtin_options_as_RangeOptions() const + { + return builtin_options_type() == BuiltinOptions_RangeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ResizeNearestNeighborOptions *builtin_options_as_ResizeNearestNeighborOptions() const + { + return builtin_options_type() == BuiltinOptions_ResizeNearestNeighborOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LeakyReluOptions *builtin_options_as_LeakyReluOptions() const + { + return builtin_options_type() == BuiltinOptions_LeakyReluOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SquaredDifferenceOptions *builtin_options_as_SquaredDifferenceOptions() const + { + return builtin_options_type() == BuiltinOptions_SquaredDifferenceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MirrorPadOptions *builtin_options_as_MirrorPadOptions() const + { + return builtin_options_type() == BuiltinOptions_MirrorPadOptions + ? static_cast(builtin_options()) + : nullptr; + } + const AbsOptions *builtin_options_as_AbsOptions() const + { + return builtin_options_type() == BuiltinOptions_AbsOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SplitVOptions *builtin_options_as_SplitVOptions() const + { + return builtin_options_type() == BuiltinOptions_SplitVOptions + ? static_cast(builtin_options()) + : nullptr; + } + const UniqueOptions *builtin_options_as_UniqueOptions() const + { + return builtin_options_type() == BuiltinOptions_UniqueOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ReverseV2Options *builtin_options_as_ReverseV2Options() const + { + return builtin_options_type() == BuiltinOptions_ReverseV2Options + ? static_cast(builtin_options()) + : nullptr; + } + const AddNOptions *builtin_options_as_AddNOptions() const + { + return builtin_options_type() == BuiltinOptions_AddNOptions + ? static_cast(builtin_options()) + : nullptr; + } + const GatherNdOptions *builtin_options_as_GatherNdOptions() const + { + return builtin_options_type() == BuiltinOptions_GatherNdOptions + ? static_cast(builtin_options()) + : nullptr; + } + const CosOptions *builtin_options_as_CosOptions() const + { + return builtin_options_type() == BuiltinOptions_CosOptions + ? static_cast(builtin_options()) + : nullptr; + } + const WhereOptions *builtin_options_as_WhereOptions() const + { + return builtin_options_type() == BuiltinOptions_WhereOptions + ? static_cast(builtin_options()) + : nullptr; + } + const RankOptions *builtin_options_as_RankOptions() const + { + return builtin_options_type() == BuiltinOptions_RankOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ReverseSequenceOptions *builtin_options_as_ReverseSequenceOptions() const + { + return builtin_options_type() == BuiltinOptions_ReverseSequenceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MatrixDiagOptions *builtin_options_as_MatrixDiagOptions() const + { + return builtin_options_type() == BuiltinOptions_MatrixDiagOptions + ? static_cast(builtin_options()) + : nullptr; + } + const QuantizeOptions *builtin_options_as_QuantizeOptions() const + { + return builtin_options_type() == BuiltinOptions_QuantizeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MatrixSetDiagOptions *builtin_options_as_MatrixSetDiagOptions() const + { + return builtin_options_type() == BuiltinOptions_MatrixSetDiagOptions + ? static_cast(builtin_options()) + : nullptr; + } + const HardSwishOptions *builtin_options_as_HardSwishOptions() const + { + return builtin_options_type() == BuiltinOptions_HardSwishOptions + ? static_cast(builtin_options()) + : nullptr; + } + const IfOptions *builtin_options_as_IfOptions() const + { + return builtin_options_type() == BuiltinOptions_IfOptions + ? static_cast(builtin_options()) + : nullptr; + } + const WhileOptions *builtin_options_as_WhileOptions() const + { + return builtin_options_type() == BuiltinOptions_WhileOptions + ? static_cast(builtin_options()) + : nullptr; + } + const DepthToSpaceOptions *builtin_options_as_DepthToSpaceOptions() const + { + return builtin_options_type() == BuiltinOptions_DepthToSpaceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const NonMaxSuppressionV4Options *builtin_options_as_NonMaxSuppressionV4Options() const + { + return builtin_options_type() == BuiltinOptions_NonMaxSuppressionV4Options + ? static_cast(builtin_options()) + : nullptr; + } + const NonMaxSuppressionV5Options *builtin_options_as_NonMaxSuppressionV5Options() const + { + return builtin_options_type() == BuiltinOptions_NonMaxSuppressionV5Options + ? static_cast(builtin_options()) + : nullptr; + } + const ScatterNdOptions *builtin_options_as_ScatterNdOptions() const + { + return builtin_options_type() == BuiltinOptions_ScatterNdOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SelectV2Options *builtin_options_as_SelectV2Options() const + { + return builtin_options_type() == BuiltinOptions_SelectV2Options + ? static_cast(builtin_options()) + : nullptr; + } + const DensifyOptions *builtin_options_as_DensifyOptions() const + { + return builtin_options_type() == BuiltinOptions_DensifyOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SegmentSumOptions *builtin_options_as_SegmentSumOptions() const + { + return builtin_options_type() == BuiltinOptions_SegmentSumOptions + ? static_cast(builtin_options()) + : nullptr; + } + const BatchMatMulOptions *builtin_options_as_BatchMatMulOptions() const + { + return builtin_options_type() == BuiltinOptions_BatchMatMulOptions + ? static_cast(builtin_options()) + : nullptr; + } + const InstanceNormOptions *builtin_options_as_InstanceNormOptions() const + { + return builtin_options_type() == BuiltinOptions_InstanceNormOptions + ? static_cast(builtin_options()) + : nullptr; + } + const flatbuffers::Vector *custom_options() const + { + return GetPointer *>(VT_CUSTOM_OPTIONS); + } + CustomOptionsFormat custom_options_format() const + { + return static_cast(GetField(VT_CUSTOM_OPTIONS_FORMAT, 0)); + } + const flatbuffers::Vector *mutating_variable_inputs() const + { + return GetPointer *>(VT_MUTATING_VARIABLE_INPUTS); + } + const flatbuffers::Vector *intermediates() const + { + return GetPointer *>(VT_INTERMEDIATES); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_OPCODE_INDEX) && + VerifyOffset(verifier, VT_INPUTS) && verifier.VerifyVector(inputs()) && + VerifyOffset(verifier, VT_OUTPUTS) && verifier.VerifyVector(outputs()) && + VerifyField(verifier, VT_BUILTIN_OPTIONS_TYPE) && + VerifyOffset(verifier, VT_BUILTIN_OPTIONS) && + VerifyBuiltinOptions(verifier, builtin_options(), builtin_options_type()) && + VerifyOffset(verifier, VT_CUSTOM_OPTIONS) && verifier.VerifyVector(custom_options()) && + VerifyField(verifier, VT_CUSTOM_OPTIONS_FORMAT) && + VerifyOffset(verifier, VT_MUTATING_VARIABLE_INPUTS) && + verifier.VerifyVector(mutating_variable_inputs()) && + VerifyOffset(verifier, VT_INTERMEDIATES) && verifier.VerifyVector(intermediates()) && + verifier.EndTable(); + } +}; + +template <> inline const Conv2DOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_Conv2DOptions(); +} + +template <> +inline const DepthwiseConv2DOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DepthwiseConv2DOptions(); +} + +template <> +inline const ConcatEmbeddingsOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ConcatEmbeddingsOptions(); +} + +template <> +inline const LSHProjectionOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LSHProjectionOptions(); +} + +template <> inline const Pool2DOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_Pool2DOptions(); +} + +template <> inline const SVDFOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SVDFOptions(); +} + +template <> inline const RNNOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_RNNOptions(); +} + +template <> +inline const FullyConnectedOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FullyConnectedOptions(); +} + +template <> inline const SoftmaxOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SoftmaxOptions(); +} + +template <> +inline const ConcatenationOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ConcatenationOptions(); +} + +template <> inline const AddOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_AddOptions(); +} + +template <> inline const L2NormOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_L2NormOptions(); +} + +template <> +inline const LocalResponseNormalizationOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_LocalResponseNormalizationOptions(); +} + +template <> inline const LSTMOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LSTMOptions(); +} + +template <> +inline const ResizeBilinearOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ResizeBilinearOptions(); +} + +template <> inline const CallOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_CallOptions(); +} + +template <> inline const ReshapeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ReshapeOptions(); +} + +template <> inline const SkipGramOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SkipGramOptions(); +} + +template <> +inline const SpaceToDepthOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SpaceToDepthOptions(); +} + +template <> +inline const EmbeddingLookupSparseOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_EmbeddingLookupSparseOptions(); +} + +template <> inline const MulOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MulOptions(); +} + +template <> inline const PadOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_PadOptions(); +} + +template <> inline const GatherOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_GatherOptions(); +} + +template <> +inline const BatchToSpaceNDOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_BatchToSpaceNDOptions(); +} + +template <> +inline const SpaceToBatchNDOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SpaceToBatchNDOptions(); +} + +template <> inline const TransposeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_TransposeOptions(); +} + +template <> inline const ReducerOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ReducerOptions(); +} + +template <> inline const SubOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SubOptions(); +} + +template <> inline const DivOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DivOptions(); +} + +template <> inline const SqueezeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SqueezeOptions(); +} + +template <> +inline const SequenceRNNOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SequenceRNNOptions(); +} + +template <> +inline const StridedSliceOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_StridedSliceOptions(); +} + +template <> inline const ExpOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ExpOptions(); +} + +template <> inline const TopKV2Options *Operator::builtin_options_as() const +{ + return builtin_options_as_TopKV2Options(); +} + +template <> inline const SplitOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SplitOptions(); +} + +template <> inline const LogSoftmaxOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LogSoftmaxOptions(); +} + +template <> inline const CastOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_CastOptions(); +} + +template <> inline const DequantizeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DequantizeOptions(); +} + +template <> +inline const MaximumMinimumOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MaximumMinimumOptions(); +} + +template <> inline const ArgMaxOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ArgMaxOptions(); +} + +template <> inline const LessOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LessOptions(); +} + +template <> inline const NegOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_NegOptions(); +} + +template <> inline const PadV2Options *Operator::builtin_options_as() const +{ + return builtin_options_as_PadV2Options(); +} + +template <> inline const GreaterOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_GreaterOptions(); +} + +template <> +inline const GreaterEqualOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_GreaterEqualOptions(); +} + +template <> inline const LessEqualOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LessEqualOptions(); +} + +template <> inline const SelectOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SelectOptions(); +} + +template <> inline const SliceOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SliceOptions(); +} + +template <> +inline const TransposeConvOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_TransposeConvOptions(); +} + +template <> +inline const SparseToDenseOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SparseToDenseOptions(); +} + +template <> inline const TileOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_TileOptions(); +} + +template <> inline const ExpandDimsOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ExpandDimsOptions(); +} + +template <> inline const EqualOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_EqualOptions(); +} + +template <> inline const NotEqualOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_NotEqualOptions(); +} + +template <> inline const ShapeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ShapeOptions(); +} + +template <> inline const PowOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_PowOptions(); +} + +template <> inline const ArgMinOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ArgMinOptions(); +} + +template <> inline const FakeQuantOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FakeQuantOptions(); +} + +template <> inline const PackOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_PackOptions(); +} + +template <> inline const LogicalOrOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LogicalOrOptions(); +} + +template <> inline const OneHotOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_OneHotOptions(); +} + +template <> inline const LogicalAndOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LogicalAndOptions(); +} + +template <> inline const LogicalNotOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LogicalNotOptions(); +} + +template <> inline const UnpackOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_UnpackOptions(); +} + +template <> inline const FloorDivOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FloorDivOptions(); +} + +template <> inline const SquareOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SquareOptions(); +} + +template <> inline const ZerosLikeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ZerosLikeOptions(); +} + +template <> inline const FillOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FillOptions(); +} + +template <> +inline const BidirectionalSequenceLSTMOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_BidirectionalSequenceLSTMOptions(); +} + +template <> +inline const BidirectionalSequenceRNNOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_BidirectionalSequenceRNNOptions(); +} + +template <> +inline const UnidirectionalSequenceLSTMOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_UnidirectionalSequenceLSTMOptions(); +} + +template <> inline const FloorModOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FloorModOptions(); +} + +template <> inline const RangeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_RangeOptions(); +} + +template <> +inline const ResizeNearestNeighborOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_ResizeNearestNeighborOptions(); +} + +template <> inline const LeakyReluOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LeakyReluOptions(); +} + +template <> +inline const SquaredDifferenceOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_SquaredDifferenceOptions(); +} + +template <> inline const MirrorPadOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MirrorPadOptions(); +} + +template <> inline const AbsOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_AbsOptions(); +} + +template <> inline const SplitVOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SplitVOptions(); +} + +template <> inline const UniqueOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_UniqueOptions(); +} + +template <> inline const ReverseV2Options *Operator::builtin_options_as() const +{ + return builtin_options_as_ReverseV2Options(); +} + +template <> inline const AddNOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_AddNOptions(); +} + +template <> inline const GatherNdOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_GatherNdOptions(); +} + +template <> inline const CosOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_CosOptions(); +} + +template <> inline const WhereOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_WhereOptions(); +} + +template <> inline const RankOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_RankOptions(); +} + +template <> +inline const ReverseSequenceOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ReverseSequenceOptions(); +} + +template <> inline const MatrixDiagOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MatrixDiagOptions(); +} + +template <> inline const QuantizeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_QuantizeOptions(); +} + +template <> +inline const MatrixSetDiagOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MatrixSetDiagOptions(); +} + +template <> inline const HardSwishOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_HardSwishOptions(); +} + +template <> inline const IfOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_IfOptions(); +} + +template <> inline const WhileOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_WhileOptions(); +} + +template <> +inline const DepthToSpaceOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DepthToSpaceOptions(); +} + +template <> +inline const NonMaxSuppressionV4Options * +Operator::builtin_options_as() const +{ + return builtin_options_as_NonMaxSuppressionV4Options(); +} + +template <> +inline const NonMaxSuppressionV5Options * +Operator::builtin_options_as() const +{ + return builtin_options_as_NonMaxSuppressionV5Options(); +} + +template <> inline const ScatterNdOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ScatterNdOptions(); +} + +template <> inline const SelectV2Options *Operator::builtin_options_as() const +{ + return builtin_options_as_SelectV2Options(); +} + +template <> inline const DensifyOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DensifyOptions(); +} + +template <> inline const SegmentSumOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SegmentSumOptions(); +} + +template <> +inline const BatchMatMulOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_BatchMatMulOptions(); +} + +template <> +inline const InstanceNormOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_InstanceNormOptions(); +} + +struct OperatorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_opcode_index(uint32_t opcode_index) + { + fbb_.AddElement(Operator::VT_OPCODE_INDEX, opcode_index, 0); + } + void add_inputs(flatbuffers::Offset> inputs) + { + fbb_.AddOffset(Operator::VT_INPUTS, inputs); + } + void add_outputs(flatbuffers::Offset> outputs) + { + fbb_.AddOffset(Operator::VT_OUTPUTS, outputs); + } + void add_builtin_options_type(BuiltinOptions builtin_options_type) + { + fbb_.AddElement(Operator::VT_BUILTIN_OPTIONS_TYPE, + static_cast(builtin_options_type), 0); + } + void add_builtin_options(flatbuffers::Offset builtin_options) + { + fbb_.AddOffset(Operator::VT_BUILTIN_OPTIONS, builtin_options); + } + void add_custom_options(flatbuffers::Offset> custom_options) + { + fbb_.AddOffset(Operator::VT_CUSTOM_OPTIONS, custom_options); + } + void add_custom_options_format(CustomOptionsFormat custom_options_format) + { + fbb_.AddElement(Operator::VT_CUSTOM_OPTIONS_FORMAT, + static_cast(custom_options_format), 0); + } + void add_mutating_variable_inputs( + flatbuffers::Offset> mutating_variable_inputs) + { + fbb_.AddOffset(Operator::VT_MUTATING_VARIABLE_INPUTS, mutating_variable_inputs); + } + void add_intermediates(flatbuffers::Offset> intermediates) + { + fbb_.AddOffset(Operator::VT_INTERMEDIATES, intermediates); + } + explicit OperatorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + OperatorBuilder &operator=(const OperatorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateOperator(flatbuffers::FlatBufferBuilder &_fbb, uint32_t opcode_index = 0, + flatbuffers::Offset> inputs = 0, + flatbuffers::Offset> outputs = 0, + BuiltinOptions builtin_options_type = BuiltinOptions_NONE, + flatbuffers::Offset builtin_options = 0, + flatbuffers::Offset> custom_options = 0, + CustomOptionsFormat custom_options_format = CustomOptionsFormat_FLEXBUFFERS, + flatbuffers::Offset> mutating_variable_inputs = 0, + flatbuffers::Offset> intermediates = 0) +{ + OperatorBuilder builder_(_fbb); + builder_.add_intermediates(intermediates); + builder_.add_mutating_variable_inputs(mutating_variable_inputs); + builder_.add_custom_options(custom_options); + builder_.add_builtin_options(builtin_options); + builder_.add_outputs(outputs); + builder_.add_inputs(inputs); + builder_.add_opcode_index(opcode_index); + builder_.add_custom_options_format(custom_options_format); + builder_.add_builtin_options_type(builtin_options_type); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateOperatorDirect(flatbuffers::FlatBufferBuilder &_fbb, uint32_t opcode_index = 0, + const std::vector *inputs = nullptr, + const std::vector *outputs = nullptr, + BuiltinOptions builtin_options_type = BuiltinOptions_NONE, + flatbuffers::Offset builtin_options = 0, + const std::vector *custom_options = nullptr, + CustomOptionsFormat custom_options_format = CustomOptionsFormat_FLEXBUFFERS, + const std::vector *mutating_variable_inputs = nullptr, + const std::vector *intermediates = nullptr) +{ + return circle::CreateOperator( + _fbb, opcode_index, inputs ? _fbb.CreateVector(*inputs) : 0, + outputs ? _fbb.CreateVector(*outputs) : 0, builtin_options_type, builtin_options, + custom_options ? _fbb.CreateVector(*custom_options) : 0, custom_options_format, + mutating_variable_inputs ? _fbb.CreateVector(*mutating_variable_inputs) : 0, + intermediates ? _fbb.CreateVector(*intermediates) : 0); +} + +struct SubGraph FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TENSORS = 4, + VT_INPUTS = 6, + VT_OUTPUTS = 8, + VT_OPERATORS = 10, + VT_NAME = 12, + VT_DATA_FORMAT = 14 + }; + const flatbuffers::Vector> *tensors() const + { + return GetPointer> *>(VT_TENSORS); + } + const flatbuffers::Vector *inputs() const + { + return GetPointer *>(VT_INPUTS); + } + const flatbuffers::Vector *outputs() const + { + return GetPointer *>(VT_OUTPUTS); + } + const flatbuffers::Vector> *operators() const + { + return GetPointer> *>(VT_OPERATORS); + } + const flatbuffers::String *name() const + { + return GetPointer(VT_NAME); + } + DataFormat data_format() const + { + return static_cast(GetField(VT_DATA_FORMAT, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TENSORS) && + verifier.VerifyVector(tensors()) && verifier.VerifyVectorOfTables(tensors()) && + VerifyOffset(verifier, VT_INPUTS) && verifier.VerifyVector(inputs()) && + VerifyOffset(verifier, VT_OUTPUTS) && verifier.VerifyVector(outputs()) && + VerifyOffset(verifier, VT_OPERATORS) && verifier.VerifyVector(operators()) && + verifier.VerifyVectorOfTables(operators()) && VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && VerifyField(verifier, VT_DATA_FORMAT) && + verifier.EndTable(); + } +}; + +struct SubGraphBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_tensors(flatbuffers::Offset>> tensors) + { + fbb_.AddOffset(SubGraph::VT_TENSORS, tensors); + } + void add_inputs(flatbuffers::Offset> inputs) + { + fbb_.AddOffset(SubGraph::VT_INPUTS, inputs); + } + void add_outputs(flatbuffers::Offset> outputs) + { + fbb_.AddOffset(SubGraph::VT_OUTPUTS, outputs); + } + void + add_operators(flatbuffers::Offset>> operators) + { + fbb_.AddOffset(SubGraph::VT_OPERATORS, operators); + } + void add_name(flatbuffers::Offset name) + { + fbb_.AddOffset(SubGraph::VT_NAME, name); + } + void add_data_format(DataFormat data_format) + { + fbb_.AddElement(SubGraph::VT_DATA_FORMAT, static_cast(data_format), 0); + } + explicit SubGraphBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SubGraphBuilder &operator=(const SubGraphBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSubGraph( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset>> tensors = 0, + flatbuffers::Offset> inputs = 0, + flatbuffers::Offset> outputs = 0, + flatbuffers::Offset>> operators = 0, + flatbuffers::Offset name = 0, + DataFormat data_format = DataFormat_CHANNELS_LAST) +{ + SubGraphBuilder builder_(_fbb); + builder_.add_name(name); + builder_.add_operators(operators); + builder_.add_outputs(outputs); + builder_.add_inputs(inputs); + builder_.add_tensors(tensors); + builder_.add_data_format(data_format); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateSubGraphDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector> *tensors = nullptr, + const std::vector *inputs = nullptr, + const std::vector *outputs = nullptr, + const std::vector> *operators = nullptr, + const char *name = nullptr, DataFormat data_format = DataFormat_CHANNELS_LAST) +{ + return circle::CreateSubGraph( + _fbb, tensors ? _fbb.CreateVector>(*tensors) : 0, + inputs ? _fbb.CreateVector(*inputs) : 0, + outputs ? _fbb.CreateVector(*outputs) : 0, + operators ? _fbb.CreateVector>(*operators) : 0, + name ? _fbb.CreateString(name) : 0, data_format); +} + +struct Buffer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_DATA = 4 + }; + const flatbuffers::Vector *data() const + { + return GetPointer *>(VT_DATA); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_DATA) && + verifier.VerifyVector(data()) && verifier.EndTable(); + } +}; + +struct BufferBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_data(flatbuffers::Offset> data) + { + fbb_.AddOffset(Buffer::VT_DATA, data); + } + explicit BufferBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BufferBuilder &operator=(const BufferBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateBuffer(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> data = 0) +{ + BufferBuilder builder_(_fbb); + builder_.add_data(data); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateBufferDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *data = nullptr) +{ + return circle::CreateBuffer(_fbb, data ? _fbb.CreateVector(*data) : 0); +} + +struct Metadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NAME = 4, + VT_BUFFER = 6 + }; + const flatbuffers::String *name() const + { + return GetPointer(VT_NAME); + } + uint32_t buffer() const { return GetField(VT_BUFFER, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && VerifyField(verifier, VT_BUFFER) && + verifier.EndTable(); + } +}; + +struct MetadataBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) + { + fbb_.AddOffset(Metadata::VT_NAME, name); + } + void add_buffer(uint32_t buffer) { fbb_.AddElement(Metadata::VT_BUFFER, buffer, 0); } + explicit MetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MetadataBuilder &operator=(const MetadataBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMetadata(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, uint32_t buffer = 0) +{ + MetadataBuilder builder_(_fbb); + builder_.add_buffer(buffer); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateMetadataDirect(flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + uint32_t buffer = 0) +{ + return circle::CreateMetadata(_fbb, name ? _fbb.CreateString(name) : 0, buffer); +} + +struct Model FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VERSION = 4, + VT_OPERATOR_CODES = 6, + VT_SUBGRAPHS = 8, + VT_DESCRIPTION = 10, + VT_BUFFERS = 12, + VT_METADATA_BUFFER = 14, + VT_METADATA = 16 + }; + uint32_t version() const { return GetField(VT_VERSION, 0); } + const flatbuffers::Vector> *operator_codes() const + { + return GetPointer> *>( + VT_OPERATOR_CODES); + } + const flatbuffers::Vector> *subgraphs() const + { + return GetPointer> *>(VT_SUBGRAPHS); + } + const flatbuffers::String *description() const + { + return GetPointer(VT_DESCRIPTION); + } + const flatbuffers::Vector> *buffers() const + { + return GetPointer> *>(VT_BUFFERS); + } + const flatbuffers::Vector *metadata_buffer() const + { + return GetPointer *>(VT_METADATA_BUFFER); + } + const flatbuffers::Vector> *metadata() const + { + return GetPointer> *>(VT_METADATA); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_VERSION) && + VerifyOffset(verifier, VT_OPERATOR_CODES) && verifier.VerifyVector(operator_codes()) && + verifier.VerifyVectorOfTables(operator_codes()) && + VerifyOffset(verifier, VT_SUBGRAPHS) && verifier.VerifyVector(subgraphs()) && + verifier.VerifyVectorOfTables(subgraphs()) && VerifyOffset(verifier, VT_DESCRIPTION) && + verifier.VerifyString(description()) && VerifyOffset(verifier, VT_BUFFERS) && + verifier.VerifyVector(buffers()) && verifier.VerifyVectorOfTables(buffers()) && + VerifyOffset(verifier, VT_METADATA_BUFFER) && verifier.VerifyVector(metadata_buffer()) && + VerifyOffset(verifier, VT_METADATA) && verifier.VerifyVector(metadata()) && + verifier.VerifyVectorOfTables(metadata()) && verifier.EndTable(); + } +}; + +struct ModelBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_version(uint32_t version) { fbb_.AddElement(Model::VT_VERSION, version, 0); } + void add_operator_codes( + flatbuffers::Offset>> operator_codes) + { + fbb_.AddOffset(Model::VT_OPERATOR_CODES, operator_codes); + } + void + add_subgraphs(flatbuffers::Offset>> subgraphs) + { + fbb_.AddOffset(Model::VT_SUBGRAPHS, subgraphs); + } + void add_description(flatbuffers::Offset description) + { + fbb_.AddOffset(Model::VT_DESCRIPTION, description); + } + void add_buffers(flatbuffers::Offset>> buffers) + { + fbb_.AddOffset(Model::VT_BUFFERS, buffers); + } + void add_metadata_buffer(flatbuffers::Offset> metadata_buffer) + { + fbb_.AddOffset(Model::VT_METADATA_BUFFER, metadata_buffer); + } + void + add_metadata(flatbuffers::Offset>> metadata) + { + fbb_.AddOffset(Model::VT_METADATA, metadata); + } + explicit ModelBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ModelBuilder &operator=(const ModelBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateModel( + flatbuffers::FlatBufferBuilder &_fbb, uint32_t version = 0, + flatbuffers::Offset>> operator_codes = 0, + flatbuffers::Offset>> subgraphs = 0, + flatbuffers::Offset description = 0, + flatbuffers::Offset>> buffers = 0, + flatbuffers::Offset> metadata_buffer = 0, + flatbuffers::Offset>> metadata = 0) +{ + ModelBuilder builder_(_fbb); + builder_.add_metadata(metadata); + builder_.add_metadata_buffer(metadata_buffer); + builder_.add_buffers(buffers); + builder_.add_description(description); + builder_.add_subgraphs(subgraphs); + builder_.add_operator_codes(operator_codes); + builder_.add_version(version); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateModelDirect(flatbuffers::FlatBufferBuilder &_fbb, uint32_t version = 0, + const std::vector> *operator_codes = nullptr, + const std::vector> *subgraphs = nullptr, + const char *description = nullptr, + const std::vector> *buffers = nullptr, + const std::vector *metadata_buffer = nullptr, + const std::vector> *metadata = nullptr) +{ + return circle::CreateModel( + _fbb, version, + operator_codes ? _fbb.CreateVector>(*operator_codes) : 0, + subgraphs ? _fbb.CreateVector>(*subgraphs) : 0, + description ? _fbb.CreateString(description) : 0, + buffers ? _fbb.CreateVector>(*buffers) : 0, + metadata_buffer ? _fbb.CreateVector(*metadata_buffer) : 0, + metadata ? _fbb.CreateVector>(*metadata) : 0); +} + +inline bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj, + QuantizationDetails type) +{ + switch (type) + { + case QuantizationDetails_NONE: + { + return true; + } + case QuantizationDetails_CustomQuantization: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: + return false; + } +} + +inline bool +VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types) +{ + if (!values || !types) + return !values && !types; + if (values->size() != types->size()) + return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) + { + if (!VerifyQuantizationDetails(verifier, values->Get(i), + types->GetEnum(i))) + { + return false; + } + } + return true; +} + +inline bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj, + SparseIndexVector type) +{ + switch (type) + { + case SparseIndexVector_NONE: + { + return true; + } + case SparseIndexVector_Int32Vector: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case SparseIndexVector_Uint16Vector: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case SparseIndexVector_Uint8Vector: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: + return false; + } +} + +inline bool +VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types) +{ + if (!values || !types) + return !values && !types; + if (values->size() != types->size()) + return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) + { + if (!VerifySparseIndexVector(verifier, values->Get(i), types->GetEnum(i))) + { + return false; + } + } + return true; +} + +inline bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, + BuiltinOptions type) +{ + switch (type) + { + case BuiltinOptions_NONE: + { + return true; + } + case BuiltinOptions_Conv2DOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DepthwiseConv2DOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ConcatEmbeddingsOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LSHProjectionOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_Pool2DOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SVDFOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RNNOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FullyConnectedOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SoftmaxOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ConcatenationOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AddOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_L2NormOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LocalResponseNormalizationOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LSTMOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ResizeBilinearOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CallOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReshapeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SkipGramOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SpaceToDepthOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_EmbeddingLookupSparseOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MulOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PadOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GatherOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BatchToSpaceNDOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SpaceToBatchNDOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TransposeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReducerOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SubOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DivOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SqueezeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SequenceRNNOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_StridedSliceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ExpOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TopKV2Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SplitOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogSoftmaxOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CastOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DequantizeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MaximumMinimumOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ArgMaxOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LessOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NegOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PadV2Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GreaterOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GreaterEqualOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LessEqualOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SelectOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SliceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TransposeConvOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SparseToDenseOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TileOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ExpandDimsOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_EqualOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NotEqualOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ShapeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PowOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ArgMinOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FakeQuantOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PackOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogicalOrOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_OneHotOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogicalAndOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogicalNotOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnpackOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FloorDivOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SquareOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ZerosLikeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FillOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BidirectionalSequenceLSTMOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BidirectionalSequenceRNNOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnidirectionalSequenceLSTMOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FloorModOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RangeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ResizeNearestNeighborOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LeakyReluOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SquaredDifferenceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MirrorPadOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AbsOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SplitVOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UniqueOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReverseV2Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AddNOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GatherNdOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CosOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_WhereOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RankOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReverseSequenceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MatrixDiagOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_QuantizeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MatrixSetDiagOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_HardSwishOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_IfOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_WhileOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DepthToSpaceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NonMaxSuppressionV4Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NonMaxSuppressionV5Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ScatterNdOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SelectV2Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DensifyOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SegmentSumOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BatchMatMulOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_InstanceNormOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: + return false; + } +} + +inline bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types) +{ + if (!values || !types) + return !values && !types; + if (values->size() != types->size()) + return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) + { + if (!VerifyBuiltinOptions(verifier, values->Get(i), types->GetEnum(i))) + { + return false; + } + } + return true; +} + +inline const circle::Model *GetModel(const void *buf) +{ + return flatbuffers::GetRoot(buf); +} + +inline const circle::Model *GetSizePrefixedModel(const void *buf) +{ + return flatbuffers::GetSizePrefixedRoot(buf); +} + +inline const char *ModelIdentifier() { return "CIR0"; } + +inline bool ModelBufferHasIdentifier(const void *buf) +{ + return flatbuffers::BufferHasIdentifier(buf, ModelIdentifier()); +} + +inline bool VerifyModelBuffer(flatbuffers::Verifier &verifier) +{ + return verifier.VerifyBuffer(ModelIdentifier()); +} + +inline bool VerifySizePrefixedModelBuffer(flatbuffers::Verifier &verifier) +{ + return verifier.VerifySizePrefixedBuffer(ModelIdentifier()); +} + +inline const char *ModelExtension() { return "circle"; } + +inline void FinishModelBuffer(flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) +{ + fbb.Finish(root, ModelIdentifier()); +} + +inline void FinishSizePrefixedModelBuffer(flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) +{ + fbb.FinishSizePrefixed(root, ModelIdentifier()); +} + +} // namespace circle + +#endif // FLATBUFFERS_GENERATED_CIRCLESCHEMA_CIRCLE_H_ diff --git a/runtime/onert/frontend/nnapi/ANeuralNetworksModel.test.cc b/runtime/onert/frontend/nnapi/ANeuralNetworksModel.test.cc new file mode 100644 index 000000000..15a279a7e --- /dev/null +++ b/runtime/onert/frontend/nnapi/ANeuralNetworksModel.test.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "wrapper/ANeuralNetworksModel.h" + +TEST(MODEL, model_build) +{ + ANeuralNetworksModel model; + ASSERT_EQ(model.isFinished(), false); +} diff --git a/runtime/onert/frontend/nnapi/CMakeLists.txt b/runtime/onert/frontend/nnapi/CMakeLists.txt new file mode 100644 index 000000000..b66b32e89 --- /dev/null +++ b/runtime/onert/frontend/nnapi/CMakeLists.txt @@ -0,0 +1,27 @@ +file(GLOB_RECURSE SOURCES_FRONTEND "*.cc") +file(GLOB_RECURSE TESTS_FRONTEND "*.test.cc") +list(REMOVE_ITEM SOURCES_FRONTEND ${TESTS_FRONTEND}) + +set(LIB_ONERT onert) + +add_library(${LIB_ONERT} SHARED ${SOURCES_FRONTEND}) +target_link_libraries(${LIB_ONERT} PUBLIC nnfw-nnapi-header) +target_link_libraries(${LIB_ONERT} PUBLIC onert_core) # TODO Link PRIVATE onert_core +target_link_libraries(${LIB_ONERT} PRIVATE nnfw_common) +target_link_libraries(${LIB_ONERT} PRIVATE nnfw_coverage) + +set_target_properties(${LIB_ONERT} PROPERTIES OUTPUT_NAME neuralnetworks) + +install(TARGETS ${LIB_ONERT} DESTINATION lib) + +if(NOT ENABLE_TEST) + return() +endif(NOT ENABLE_TEST) + +add_executable(test_onert_frontend_nnapi ${TESTS_FRONTEND}) + +target_link_libraries(test_onert_frontend_nnapi PRIVATE ${LIB_ONERT} dl) +target_link_libraries(test_onert_frontend_nnapi PRIVATE gtest) +target_link_libraries(test_onert_frontend_nnapi PRIVATE gtest_main) + +install(TARGETS test_onert_frontend_nnapi DESTINATION unittest) diff --git a/runtime/onert/frontend/nnapi/compilation.cc b/runtime/onert/frontend/nnapi/compilation.cc new file mode 100644 index 000000000..0823cb456 --- /dev/null +++ b/runtime/onert/frontend/nnapi/compilation.cc @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "wrapper/ANeuralNetworksModel.h" +#include "wrapper/ANeuralNetworksCompilation.h" +#include "util/logging.h" + +// +// NNAPI Implementation +// +int ANeuralNetworksCompilation_create(ANeuralNetworksModel *model, + ANeuralNetworksCompilation **compilation) +{ + if ((model == nullptr) || (compilation == nullptr)) + { + VERBOSE(NNAPI::Compilation) << "create: Incorrect null pointer parameter(s)" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (!model->isFinished()) + { + VERBOSE(NNAPI::Compilation) << "create: Model define is not finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + std::shared_ptr internal; + + model->release(internal); + + *compilation = new (std::nothrow) ANeuralNetworksCompilation(internal); + if (*compilation == nullptr) + { + VERBOSE(NNAPI::Compilation) << "create: ail to create compilation object" << std::endl; + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksCompilation_finish(ANeuralNetworksCompilation *compilation) +{ + if (compilation == nullptr) + { + VERBOSE(NNAPI::Compilation) << "finish: Incorrect null pointer parameter" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (compilation->state() != ::onert::compiler::State::CREATED) + { + VERBOSE(NNAPI::Compilation) << "finish: Already finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + if (!compilation->finish()) + { + VERBOSE(NNAPI::Compilation) << "finish: Fail to compile" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksCompilation_free(ANeuralNetworksCompilation *compilation) +{ + delete compilation; +} + +int ANeuralNetworksCompilation_setPreference(ANeuralNetworksCompilation *compilation, + int32_t preference) +{ + if (compilation == nullptr) + { + VERBOSE(NNAPI::Compilation) << "setPreference: Incorrect null pointer parameter" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (compilation->state() != ::onert::compiler::State::CREATED) + { + VERBOSE(NNAPI::Compilation) << "setPreference: Already finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + const PreferenceCode FIRST_PREFERENCE_CODE = ANEURALNETWORKS_PREFER_LOW_POWER; + const PreferenceCode LAST_PREFERENCE_CODE = ANEURALNETWORKS_PREFER_SUSTAINED_SPEED; + if ((preference < FIRST_PREFERENCE_CODE) || (preference > LAST_PREFERENCE_CODE)) + { + VERBOSE(NNAPI::Compilation) << "setPreference: Incorrect preference code" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + // NYI: nothing to set + return ANEURALNETWORKS_NO_ERROR; +} diff --git a/runtime/onert/frontend/nnapi/event.cc b/runtime/onert/frontend/nnapi/event.cc new file mode 100644 index 000000000..593b74e90 --- /dev/null +++ b/runtime/onert/frontend/nnapi/event.cc @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "wrapper/ANeuralNetworksEvent.h" + +int ANeuralNetworksEvent_wait(ANeuralNetworksEvent *event) +{ + if (event == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (!event->waitFinish()) + { + return ANEURALNETWORKS_BAD_STATE; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksEvent_free(ANeuralNetworksEvent *event) { delete event; } diff --git a/runtime/onert/frontend/nnapi/execution.cc b/runtime/onert/frontend/nnapi/execution.cc new file mode 100644 index 000000000..6aaca1b4c --- /dev/null +++ b/runtime/onert/frontend/nnapi/execution.cc @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "wrapper/ANeuralNetworksCompilation.h" +#include "wrapper/ANeuralNetworksExecution.h" +#include "wrapper/ANeuralNetworksMemory.h" +#include "wrapper/ANeuralNetworksEvent.h" +#include "wrapper/NNAPIConvert.h" +#include "util/logging.h" + +// +// NNAPI Implementation +// +int ANeuralNetworksExecution_create(ANeuralNetworksCompilation *compilation, + ANeuralNetworksExecution **execution) +{ + if ((compilation == nullptr) || (execution == nullptr)) + { + VERBOSE(NNAPI::Execution) << "create: Incorrect null pointer parameter(s)" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + std::shared_ptr executor; + + compilation->publish(executor); + + if (executor == nullptr) + { + VERBOSE(NNAPI::Execution) << "create: Never compiled yet" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + *execution = new (std::nothrow) ANeuralNetworksExecution{executor}; + if (*execution == nullptr) + { + VERBOSE(NNAPI::Execution) << "create: Fail to create execution object" << std::endl; + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +// NOTE Handle optional input +// Unspecified shape on model build +// Optional and omitted input on execution: skip input setting (workaround for LSTM) +// Optional but not omitted input on execution: cannot handle +// Normal input on execution: cannot handle +// Fully specified shape on model build +// Optional input on execution: cannot handle +// Normal input: handle normally +int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution *execution, int32_t index, + const ANeuralNetworksOperandType *type, const void *buffer, + size_t length) +{ + // Don't check type + // Comment about ANeuralNetworksOperandType in NeuralNetworks.h: + // If the input or output is optional and omitted then it need not have a fully specified tensor + // operand type + if ((execution == nullptr) || ((buffer == nullptr) && (length != 0))) + { + VERBOSE(NNAPI::Execution) << "setInput: Incorrect null pointer parameter(s)" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if ((buffer != nullptr) && (length == 0)) + { + VERBOSE(NNAPI::Execution) << "setInput: Zero length input" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + const auto operand_index = execution->getInputOperandIndex(index); + if (!operand_index.valid()) + { + VERBOSE(NNAPI::Execution) << "setInput: Invalid input index" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + // Omitted optional input + // LSTM operation's some inputs can be optional input + if ((buffer == nullptr) && (length == 0)) + { + if (execution->haveUnspecifiedDims(operand_index)) + { + return ANEURALNETWORKS_NO_ERROR; + } + else + { + VERBOSE(NNAPI::Execution) << "setInput: Cannot handle fully-specified shape on model build " + "but omitted input on execution" + << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + + if (type != nullptr) + { + if (!execution->compareDataType(type, operand_index)) + { + VERBOSE(NNAPI::Execution) << "setInput: Data type mismatch" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!execution->compareShape(type, operand_index)) + { + VERBOSE(NNAPI::Execution) << "setInput: Shape mismatch" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (NNAPIConvert::calculateSizeFromType(type) != length) + { + VERBOSE(NNAPI::Execution) << "setInput: Invalid length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + else + { + if (execution->haveUnspecifiedDims(operand_index)) + { + VERBOSE(NNAPI::Execution) << "setInput: Unspecified dimension value" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (execution->getOperandSize(operand_index) != length) + { + VERBOSE(NNAPI::Execution) << "setInput: Invalid length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + + if (!execution->setInput(index, type, buffer, length)) + { + VERBOSE(NNAPI::Execution) << "setInput: Fail to set input" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution *execution, int32_t index, + const ANeuralNetworksOperandType *type, void *buffer, + size_t length) +{ + // Don't check type + // Comment about ANeuralNetworksOperandType in NeuralNetworks.h: + // If the input or output is optional and omitted then it need not have a fully specified tensor + // operand type + if ((execution == nullptr) || ((buffer == nullptr) && (length != 0))) + { + VERBOSE(NNAPI::Execution) << "setOutput: Incorrect null pointer parameter(s)" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if ((buffer != nullptr) && (length == 0)) + { + VERBOSE(NNAPI::Execution) << "setOutput: Zero length output" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + // Handle optional output + if (buffer == nullptr) + { + return ANEURALNETWORKS_NO_ERROR; + } + + const auto operand_index = execution->getOutputOperandIndex(index); + if (!operand_index.valid()) + { + VERBOSE(NNAPI::Execution) << "setOutput: Invalid output index" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (type != nullptr) + { + if (!execution->compareDataType(type, operand_index)) + { + VERBOSE(NNAPI::Execution) << "setOutput: Data type mismatch" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!execution->compareShape(type, operand_index)) + { + VERBOSE(NNAPI::Execution) << "setOutput: Shape mismatch" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (NNAPIConvert::calculateSizeFromType(type) != length) + { + VERBOSE(NNAPI::Execution) << "setOutput: Invalid length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + else + { + if (execution->haveUnspecifiedDims(operand_index)) + { + VERBOSE(NNAPI::Execution) << "setOutput: Unspecified dimension value" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (execution->getOperandSize(operand_index) != length) + { + VERBOSE(NNAPI::Execution) << "setInput: Invalid length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + + if (!execution->setOutput(index, type, buffer, length)) + { + VERBOSE(NNAPI::Execution) << "setOutput: Fail to set output" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution, + ANeuralNetworksEvent **event) +{ + if ((execution == nullptr) || (event == nullptr)) + { + VERBOSE(NNAPI::Execution) << "startCompute: Incorrect null pointer parameter(s)" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + // TODO: Handle event + auto instance = execution->instance(); + *event = new (std::nothrow) ANeuralNetworksEvent{instance}; + if (*event == nullptr) + { + VERBOSE(NNAPI::Execution) << "startCompute: Fail to create event" << std::endl; + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + + if (!execution->startExecute()) + { + VERBOSE(NNAPI::Execution) << "startCompute: Fail to start execution" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksExecution_compute(ANeuralNetworksExecution *execution) +{ + if (execution == nullptr) + { + VERBOSE(NNAPI::Execution) << "Compute: Incorrect null pointer parameter" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (!execution->execute()) + { + VERBOSE(NNAPI::Execution) << "Compute: Fail to execution" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksExecution_free(ANeuralNetworksExecution *execution) { delete execution; } + +int ANeuralNetworksExecution_setInputFromMemory(ANeuralNetworksExecution *execution, int32_t index, + const ANeuralNetworksOperandType *type, + const ANeuralNetworksMemory *memory, size_t offset, + size_t length) +{ + if ((execution == nullptr) || (memory == nullptr)) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Incorrect null pointer parameter(s)" + << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (length == 0) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Zero length input" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + const auto operand_index = execution->getInputOperandIndex(index); + if (!operand_index.valid()) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Invalid input index" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (type != nullptr) + { + if (!execution->compareDataType(type, operand_index)) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Data type mismatch" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!execution->compareShape(type, operand_index)) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Shape mismatch" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (NNAPIConvert::calculateSizeFromType(type) != length) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Invalid length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + else + { + if (execution->haveUnspecifiedDims(operand_index)) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Unspecified dimension value" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (execution->getOperandSize(operand_index) != length) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Invalid length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + + if (!memory->vaildAccess(offset, length)) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Invalid memory access" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!execution->setInput(index, type, reinterpret_cast(memory->base() + offset), + length)) + { + VERBOSE(NNAPI::Execution) << "setInputFromMemory: Fail to set input" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksExecution_setOutputFromMemory(ANeuralNetworksExecution *execution, int32_t index, + const ANeuralNetworksOperandType *type, + const ANeuralNetworksMemory *memory, size_t offset, + size_t length) +{ + if ((execution == nullptr) || (memory == nullptr)) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Incorrect null pointer parameter(s)" + << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (length == 0) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Zero length input" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + const auto operand_index = execution->getOutputOperandIndex(index); + if (!operand_index.valid()) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Invalid output index" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (type != nullptr) + { + if (!execution->compareDataType(type, operand_index)) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Data type mismatch" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!execution->compareShape(type, operand_index)) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Shape mismatch" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (NNAPIConvert::calculateSizeFromType(type) != length) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Invalid length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + else + { + if (execution->haveUnspecifiedDims(operand_index)) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Unspecified dimension value" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (execution->getOperandSize(operand_index) != length) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Invalid length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + + if (!memory->vaildAccess(offset, length)) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Invalid memory access" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!execution->setOutput(index, type, reinterpret_cast(memory->base() + offset), length)) + { + VERBOSE(NNAPI::Execution) << "setOutputFromMemory: Fail to set input" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksExecution_getOutputOperandRank(ANeuralNetworksExecution *execution, + int32_t index, uint32_t *rank) +{ + if ((execution == nullptr) || (rank == nullptr)) + { + VERBOSE(NNAPI::Execution) << "getOutputOperandRank: Incorrect null pointer parameter(s)" + << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + const auto operand_index = execution->getOutputOperandIndex(index); + if (!operand_index.valid()) + { + VERBOSE(NNAPI::Execution) << "getOutputOperandRank: Invalid output index" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!execution->getOutputOperandRank(index, rank)) + { + VERBOSE(NNAPI::Execution) << "getOutputOperandRank: Fail to get rank" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksExecution_getOutputOperandDimensions(ANeuralNetworksExecution *execution, + int32_t index, uint32_t *dimensions) +{ + if ((execution == nullptr) || (dimensions == nullptr)) + { + VERBOSE(NNAPI::Execution) << "getOutputOperandDimensions: Incorrect null pointer parameter(s)" + << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + const auto operand_index = execution->getOutputOperandIndex(index); + if (!operand_index.valid()) + { + VERBOSE(NNAPI::Execution) << "getOutputOperandDimensions: Invalid output index" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!execution->getOutputOperandDimensions(index, dimensions)) + { + VERBOSE(NNAPI::Execution) << "getOutputOperandDimensions: Fail to get rank" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + return ANEURALNETWORKS_NO_ERROR; +} diff --git a/runtime/onert/frontend/nnapi/memory.cc b/runtime/onert/frontend/nnapi/memory.cc new file mode 100644 index 000000000..6e568a926 --- /dev/null +++ b/runtime/onert/frontend/nnapi/memory.cc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include +#include "wrapper/ANeuralNetworksMemory.h" + +int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset, + ANeuralNetworksMemory **memory) +{ + if (memory == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + *memory = new (std::nothrow) ANeuralNetworksMemory{size, protect, fd, offset}; + if (*memory == nullptr) + { + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksMemory_free(ANeuralNetworksMemory *memory) { delete memory; } diff --git a/runtime/onert/frontend/nnapi/model.cc b/runtime/onert/frontend/nnapi/model.cc new file mode 100644 index 000000000..e201a6753 --- /dev/null +++ b/runtime/onert/frontend/nnapi/model.cc @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include "wrapper/ANeuralNetworksModel.h" +#include "wrapper/ANeuralNetworksMemory.h" +#include "util/logging.h" + +int ANeuralNetworksModel_create(ANeuralNetworksModel **model) +{ + if (model == nullptr) + { + VERBOSE(NNAPI::Model) << "create: Incorrect null pointer parameter" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + *model = new (std::nothrow) ANeuralNetworksModel{}; + if (*model == nullptr) + { + VERBOSE(NNAPI::Model) << "create: Fail to create model object" << std::endl; + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksModel_free(ANeuralNetworksModel *model) { delete model; } + +int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model, + const ANeuralNetworksOperandType *type) +{ + if ((model == nullptr) || (type == nullptr)) + { + VERBOSE(NNAPI::Model) << "addOperand: Incorrect null pointer parameter(s)" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + VERBOSE(NNAPI::Model) << "addOperand: Already finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + // scale and zeroPoint should be zero for scalars and non-fixed point tensors + // Quantized: + // scale: a 32 bit floating point value greater than zero + // zeroPoint: a 32 bit integer, in range [0, 255] + if (type->type == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) + { + if (!(type->scale > 0.0f)) + { + VERBOSE(NNAPI::Model) << "addOperand: Incorrect scale value for quantization" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if ((type->zeroPoint < 0) || (type->zeroPoint > 255)) + { + VERBOSE(NNAPI::Model) << "addOperand: Incorrect zeroPoint value for quantization" + << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + // NOTE Validation of scale and zeroPoint would be skipped for a while. + // We do not know whether scalar type can have scale and zeroPoint. + // To pass ValidationTest and GeneratedTest, this validation code + // would not be implemented until we can define this issue clearly. + // + // scale and zeroPoint should be zero for scalars and non-fixed point tensors + // else if ((type->scale != 0.0f) || (type->zeroPoint != 0)) + // { + // return ANEURALNETWORKS_BAD_DATA; + // } + + // dimensionCount should be zero for scalars + if ((type->dimensionCount != 0) && + ((type->type == ANEURALNETWORKS_FLOAT32) || (type->type == ANEURALNETWORKS_INT32) || + (type->type == ANEURALNETWORKS_UINT32))) + { + VERBOSE(NNAPI::Model) << "addOperand: Incorrect data type" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!model->addOperand(type)) + { + VERBOSE(NNAPI::Model) << "addOperand: Fail to add operand" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index, + const void *buffer, size_t length) +{ + const bool optional_operand = ((buffer == nullptr) && (length == 0)); + + if ((model == nullptr) || ((buffer == nullptr) && (length != 0))) + { + VERBOSE(NNAPI::Model) << "setOperandValue: Incorrect null pointer parameter(s)" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + VERBOSE(NNAPI::Model) << "setOperandValue: Already finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + // Negative index value is not allowed + if (index < 0) + { + VERBOSE(NNAPI::Model) << "setOperandValue: Invalid index value (negative)" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + // NOTE OperandIndex uses uint32_t as its underlying type as various NNAPI + // functions such as ANeuralNetworksModel_addOperation use uint32_t to represent operand + // index + // ANeuralNetworksModel_setOperandValue, however, uses int32_t to represent operand index. + // + // Below, static_cast(...) is introduced to eliminate compiler warning. + uint32_t ind = static_cast(index); + + if (!model->isExistOperand(ind)) + { + VERBOSE(NNAPI::Model) << "setOperandValue: Invalid index value (not exist)" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!optional_operand && (model->operandSize(ind) != length)) + { + VERBOSE(NNAPI::Model) << "setOperandValue: Invalid data length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (model->isUsageSet(ind)) + { + VERBOSE(NNAPI::Model) << "setOperandValue: Already set operand" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + // NNAPI spec in NeuralNetworks.h + // For values of length greater than ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES, + // the application is responsible for not changing the content of this region + // until all executions using this model have completed + bool copy_value = false; + if (length <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES) + { + copy_value = true; + } + + if (!model->setOperandValue(ind, buffer, length, optional_operand, copy_value)) + { + VERBOSE(NNAPI::Model) << "setOperandValue: Fail to set operand value" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model, int32_t index, + const ANeuralNetworksMemory *memory, + size_t offset, size_t length) +{ + if ((model == nullptr) || (memory == nullptr)) + { + VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Incorrect null pointer parameter(s)" + << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Already finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + // Negative index value is not allowed + if (index < 0) + { + VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Invalid index value (negative)" + << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + // NOTE OperandIndex uses uint32_t as its underlying type as various NNAPI + // functions such as ANeuralNetworksModel_addOperation use uint32_t to represent operand + // index + // ANeuralNetworksModel_setOperandValue, however, uses int32_t to represent operand index. + // + // Below, static_cast(...) is introduced to eliminate compiler warning. + uint32_t ind = static_cast(index); + + if (!model->isExistOperand(ind)) + { + VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Invalid index value (not exist)" + << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if ((model->operandSize(ind) != length) || (memory->size() < (offset + length))) + { + VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Invalid data length" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (model->isUsageSet(ind)) + { + VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Already set operand" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!model->setOperandValue(ind, memory->base() + offset, length)) + { + VERBOSE(NNAPI::Model) << "setOperandValueFromMemory: Fail to set operand value" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model, + ANeuralNetworksOperationType type, uint32_t inputCount, + const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr)) + { + VERBOSE(NNAPI::Model) << "addOperation: Incorrect null pointer parameter(s)" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + VERBOSE(NNAPI::Model) << "addOperation: Already finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + const ANeuralNetworksOperationType FIRST_OPERATION = ANEURALNETWORKS_ADD; + const ANeuralNetworksOperationType LAST_OPERATION = ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR; + if ((type < FIRST_OPERATION) || (type > LAST_OPERATION)) + { + return ANEURALNETWORKS_BAD_DATA; + } + + for (uint32_t i = 0; i < outputCount; i++) + { + if (model->isUsageSet(outputs[i])) + { + VERBOSE(NNAPI::Model) << "addOperation: Already set output operand" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + + if (!model->addOperation(type, inputCount, inputs, outputCount, outputs)) + { + VERBOSE(NNAPI::Model) << "addOperation: Fail to add operation" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model, + ANeuralNetworksOperationTypeEx type, uint32_t inputCount, + const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr)) + { + VERBOSE(NNAPI::Model) << "addOperation: Incorrect null pointer parameter(s)" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + VERBOSE(NNAPI::Model) << "addOperation: Already finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + const ANeuralNetworksOperationTypeEx FIRST_OPERATION = ANEURALNETWORKS_CAST_EX; + const ANeuralNetworksOperationTypeEx LAST_OPERATION = ANEURALNETWORKS_SHAPE_EX; + if ((type < FIRST_OPERATION) || (type > LAST_OPERATION)) + { + VERBOSE(NNAPI::Model) << "addOperation: Invalid operation type" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + for (uint32_t i = 0; i < outputCount; i++) + { + if (model->isUsageSet(outputs[i])) + { + VERBOSE(NNAPI::Model) << "addOperation: Already set output operand" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + + if (!model->addOperationEx(type, inputCount, inputs, outputCount, outputs)) + { + VERBOSE(NNAPI::Model) << "addOperation: Fail to add operation" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount, + const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr)) + { + VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Incorrect null pointer parameter(s)" + << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Already finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + for (uint32_t n = 0; n < inputCount; ++n) + { + uint32_t ind = inputs[n]; + if (model->isUsageSet(ind)) + { + VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Already set input operand" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!model->addModelInput(ind)) + { + VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Fail to add input" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + + for (uint32_t n = 0; n < outputCount; ++n) + { + uint32_t ind = outputs[n]; + + if (!model->isOperationOutput(ind)) + { + VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Need to set output operand" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + + if (!model->addModelOutput(ind)) + { + VERBOSE(NNAPI::Model) << "identifyInputsAndOutputs: Fail to add output" << std::endl; + return ANEURALNETWORKS_BAD_DATA; + } + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_finish(ANeuralNetworksModel *model) +{ + if (model == nullptr) + { + VERBOSE(NNAPI::Model) << "finish: Incorrect null pointer parameter" << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + VERBOSE(NNAPI::Model) << "finish: Already finished" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + if (!model->finish()) + { + VERBOSE(NNAPI::Model) << "finish: Fail to generate internal graph" << std::endl; + return ANEURALNETWORKS_BAD_STATE; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_relaxComputationFloat32toFloat16(ANeuralNetworksModel *model, bool) +{ + if (model == nullptr) + { + VERBOSE(NNAPI::Model) << "relaxComputationFloat32toFloat16: Incorrect null pointer parameter" + << std::endl; + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + // NYI: nothing to set + VERBOSE(NNAPI::Model) << "relaxComputationFloat32toFloat16: Do nothing yet" << std::endl; + + return ANEURALNETWORKS_NO_ERROR; +} diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc new file mode 100644 index 000000000..03518a88a --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.cc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ANeuralNetworksCompilation.h" + +#include "util/logging.h" + +ANeuralNetworksCompilation::ANeuralNetworksCompilation( + const std::shared_ptr &model) noexcept + : _compiler{new onert::compiler::Compiler{model}} +{ + // DO NOTHING +} + +bool ANeuralNetworksCompilation::finish() noexcept +{ + try + { + _compiler->compile(); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h new file mode 100644 index 000000000..8d72441b2 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksCompilation.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COMPILATION_H__ +#define __COMPILATION_H__ + +#include "compiler/Compiler.h" +#include "ir/Graph.h" +#include "exec/IExecutor.h" + +struct ANeuralNetworksCompilation +{ +public: + ANeuralNetworksCompilation(const std::shared_ptr &graph) noexcept; + +public: + bool finish() noexcept; + + onert::compiler::State state(void) noexcept { return _compiler->state(); } + void publish(std::shared_ptr &executor) noexcept + { + _compiler->release(executor); + } + +private: + std::shared_ptr _compiler; +}; + +#endif diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc new file mode 100644 index 000000000..2bea729be --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.cc @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ANeuralNetworksEvent.h" + +#include "exec/Execution.h" +#include "util/logging.h" + +ANeuralNetworksEvent::ANeuralNetworksEvent(const std::shared_ptr &execution) + : _execution{execution} +{ + // DO NOTHING +} + +bool ANeuralNetworksEvent::waitFinish(void) noexcept +{ + try + { + _execution->waitFinish(); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.h new file mode 100644 index 000000000..7b462d3d6 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksEvent.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __EVENT_H__ +#define __EVENT_H__ + +#include + +#include + +namespace onert +{ +namespace exec +{ +class Execution; +} // namespace exec +} // namespace onert + +struct ANeuralNetworksEvent +{ +public: + ANeuralNetworksEvent(const std::shared_ptr &execution); + +public: + bool waitFinish(void) noexcept; + +private: + const std::shared_ptr _execution; +}; + +#endif diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc new file mode 100644 index 000000000..15eb088c6 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.cc @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ANeuralNetworksExecution.h" +#include "NNAPIConvert.h" +#include "util/logging.h" + +const onert::ir::OperandIndex ANeuralNetworksExecution::getInputOperandIndex(int32_t index) noexcept +{ + if (index < 0) + { + // Negative index: return invalid index + return onert::ir::OperandIndex{}; + } + + uint32_t cast_index = static_cast(index); + if (cast_index >= _execution->graph().getInputs().size()) + { + // Return invalid index + return onert::ir::OperandIndex{}; + } + + onert::ir::IOIndex input_index{cast_index}; + const auto operand_index = _execution->graph().getInputs().at(input_index); + return operand_index; +} + +const onert::ir::OperandIndex +ANeuralNetworksExecution::getOutputOperandIndex(int32_t index) noexcept +{ + if (index < 0) + { + // Negative index: return invalid index + return onert::ir::OperandIndex{}; + } + + uint32_t cast_index = static_cast(index); + if (cast_index >= _execution->graph().getOutputs().size()) + { + // Return invalid index + return onert::ir::OperandIndex{}; + } + + onert::ir::IOIndex output_index{cast_index}; + const auto operand_index = _execution->graph().getOutputs().at(output_index); + return operand_index; +} + +bool ANeuralNetworksExecution::compareDataType(const ANeuralNetworksOperandType *type, + const onert::ir::OperandIndex index) noexcept +{ + try + { + const auto operand_type = _execution->graph().operands().at(index).typeInfo(); + const auto typeInfo = NNAPIConvert::getTypeInfo(type); + + if (operand_type != typeInfo) + { + // Data type mismatch + return false; + } + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +bool ANeuralNetworksExecution::compareShape(const ANeuralNetworksOperandType *type, + const onert::ir::OperandIndex index) noexcept +{ + // Passed shape should be specified + if (haveUnspecifiedDims(index)) + { + return false; + } + + const auto &operand_shape = _execution->graph().operands().at(index).shape(); + const auto &shape_from_type = NNAPIConvert::getShape(type); + + return operand_shape == shape_from_type; +} + +bool ANeuralNetworksExecution::haveUnspecifiedDims(const onert::ir::OperandIndex index) noexcept +{ + const auto operand_shape = _execution->graph().operands().at(index).shape(); + + return operand_shape.num_elements() == 0; +} + +size_t ANeuralNetworksExecution::getOperandSize(const onert::ir::OperandIndex index) noexcept +{ + try + { + return _execution->graph().operands().at(index).operandSize(); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return 0; + } +} + +bool ANeuralNetworksExecution::setInput(uint32_t index, const ANeuralNetworksOperandType *type, + const void *buffer, size_t length) noexcept +{ + try + { + onert::ir::IOIndex input_index{index}; + const auto operand_index = getInputOperandIndex(index); + + const auto type_info = _execution->graph().operands().at(operand_index).typeInfo(); + const auto shape = (type != nullptr) ? NNAPIConvert::getShape(type) + : _execution->graph().operands().at(operand_index).shape(); + + // NOTE The nnapi does not provide setting io_layout and not support changing layout. In other + // words, we can assume that io_layout from nnapi always is the same as layout of the used + // model. + // TODO Set layout of model + _execution->setInput(input_index, type_info, shape, buffer, length, onert::ir::Layout::NHWC); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +bool ANeuralNetworksExecution::setOutput(uint32_t index, const ANeuralNetworksOperandType *type, + void *buffer, size_t length) noexcept +{ + try + { + onert::ir::IOIndex output_index{index}; + const auto operand_index = getOutputOperandIndex(index); + + const auto type_info = _execution->graph().operands().at(operand_index).typeInfo(); + const auto shape = (type != nullptr) ? NNAPIConvert::getShape(type) + : _execution->graph().operands().at(operand_index).shape(); + + // NOTE The nnapi does not provide setting io_layout and not support changing layout. In other + // words, we can assume that io_layout from nnapi always is the same as layout of the used + // model. + // TODO Set layout of model + _execution->setOutput(output_index, type_info, shape, buffer, length, onert::ir::Layout::NHWC); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +bool ANeuralNetworksExecution::startExecute(void) noexcept +{ + try + { + _execution->startExecute(); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +bool ANeuralNetworksExecution::execute(void) noexcept +{ + try + { + _execution->execute(); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +const std::shared_ptr ANeuralNetworksExecution::instance(void) noexcept +{ + return _execution; +} + +bool ANeuralNetworksExecution::getOutputOperandRank(uint32_t index, uint32_t *rank) noexcept +{ + try + { + onert::ir::IOIndex output_index{index}; + const auto operand_index = getOutputOperandIndex(index); + bool unspecified = haveUnspecifiedDims(operand_index); + + // TODO Get unspecified output operand's rank + if (unspecified) + { + throw std::runtime_error{"Unsupport feature"}; + } + + // Check execution is finished + // Output rank and shape may be decided after execution if output is unspecified operand + if (!_execution->isFinished()) + { + return false; + } + + *rank = _execution->graph().operands().at(operand_index).shape().rank(); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +bool ANeuralNetworksExecution::getOutputOperandDimensions(uint32_t index, uint32_t *dimensions) +{ + try + { + onert::ir::IOIndex output_index{index}; + const auto operand_index = getOutputOperandIndex(index); + bool unspecified = haveUnspecifiedDims(operand_index); + if (unspecified) + { + throw std::runtime_error{"NYI: Models with unspecified output dimensions"}; + } + + // Check execution is finished + // Output rank and shape may be decided after execution if output is unspecified operand + if (!_execution->isFinished()) + { + return false; + } + + auto shape = _execution->graph().operands().at(operand_index).shape(); + for (int i = 0; i < shape.rank(); i++) + { + auto dim = shape.dim(i); + + if (dim <= 0) + { + throw std::runtime_error{"Invalid dimension value"}; + } + + dimensions[i] = static_cast(dim); + } + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h new file mode 100644 index 000000000..af2465a81 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksExecution.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __EXECUTION_H__ +#define __EXECUTION_H__ + +#include + +#include + +#include "exec/Execution.h" + +struct ANeuralNetworksExecution +{ +public: + ANeuralNetworksExecution(const std::shared_ptr &executor) + : _execution{std::make_shared(executor)} + { + // DO NOTHING + } + +public: + bool setInput(uint32_t index, const ANeuralNetworksOperandType *type, const void *buffer, + size_t length) noexcept; + bool setOutput(uint32_t index, const ANeuralNetworksOperandType *type, void *buffer, + size_t length) noexcept; + bool startExecute(void) noexcept; + bool execute(void) noexcept; + + const onert::ir::OperandIndex getInputOperandIndex(int32_t index) noexcept; + const onert::ir::OperandIndex getOutputOperandIndex(int32_t index) noexcept; + bool compareDataType(const ANeuralNetworksOperandType *type, + const onert::ir::OperandIndex index) noexcept; + bool compareShape(const ANeuralNetworksOperandType *type, + const onert::ir::OperandIndex index) noexcept; + bool haveUnspecifiedDims(const onert::ir::OperandIndex index) noexcept; + size_t getOperandSize(const onert::ir::OperandIndex index) noexcept; + const std::shared_ptr instance(void) noexcept; + + /** + * @brief Get output operand's rank + * @param[in] index Output index + * @param[out] rank Output operand's rank + * @return @c true if success to get rank, otherwise @c false + */ + bool getOutputOperandRank(uint32_t index, uint32_t *rank) noexcept; + /** + * @brief Get dimensions of the output operand + * @param[in] index Output index + * @param[out] dimensions Output operand's dimensions + * @return @c true if success to get rank, otherwise @c false + * @note This must be called after execution is finished to get resolved output shape + * unspecified in model + */ + bool getOutputOperandDimensions(uint32_t index, uint32_t *dimensions); + +private: + std::shared_ptr _execution; +}; + +#endif diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.cc new file mode 100644 index 000000000..9cc100585 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.cc @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "ANeuralNetworksMemory.h" + +// +// ANeuralNetworksMemory +// +ANeuralNetworksMemory::ANeuralNetworksMemory(size_t size, int protect, int fd, size_t offset) +{ + _base = reinterpret_cast(mmap(nullptr, size, protect, MAP_PRIVATE, fd, offset)); + _size = size; +} + +ANeuralNetworksMemory::~ANeuralNetworksMemory() { munmap(reinterpret_cast(_base), _size); } + +bool ANeuralNetworksMemory::vaildAccess(size_t offset, size_t length) const +{ + if ((offset >= _size) || (length > _size)) + { + return false; + } + + if ((offset + length) >= _size) + { + return false; + } + + return true; +} diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.h new file mode 100644 index 000000000..48a1bc5fc --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksMemory.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +#include + +struct ANeuralNetworksMemory +{ +public: + ANeuralNetworksMemory(size_t size, int protect, int fd, size_t offset); + ~ANeuralNetworksMemory(); + +public: + size_t size(void) const { return _size; } + uint8_t *base(void) { return _base; } + uint8_t *base(void) const { return _base; } + bool vaildAccess(size_t offset, size_t length) const; + +private: + size_t _size; + uint8_t *_base; +}; + +#endif // __MEMORY_H__ diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc new file mode 100644 index 000000000..d2d699ae1 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.cc @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ANeuralNetworksModel.h" +#include "OperationFactory.h" +#include "NNAPIConvert.h" + +#include "ir/Operations.Include.h" +#include "util/logging.h" + +#include + +// +// ANeuralNetworksModel +// +ANeuralNetworksModel::ANeuralNetworksModel() noexcept : _optional_operands{}, _operand_usages{} +{ + _graph = std::make_shared(); +} + +bool ANeuralNetworksModel::addOperand(const ANeuralNetworksOperandType *type) noexcept +{ + try + { + const auto shape = NNAPIConvert::getShape(type); + const auto typeInfo = NNAPIConvert::getTypeInfo(type); + _graph->addOperand(shape, typeInfo); + _operand_usages.emplace_back(OperandUsage::NOT_DEFINED); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +bool ANeuralNetworksModel::setOperandValue(uint32_t index, const void *buffer, size_t length, + bool optional, bool copy) noexcept +{ + const onert::ir::OperandIndex ind{index}; + + try + { + _operand_usages[index] = OperandUsage::CONSTANT; + + // Remain operands.at(ind).data()->base() as nullptr for optional operand + // This will be filled when model finished + if (optional) + { + setOptionalOperand(ind); + } + + using onert::ir::CachedData; + using onert::ir::ExternalData; + if (copy) + { + _graph->operands().at(ind).data( + std::make_unique(reinterpret_cast(buffer), length)); + } + else + { + _graph->operands().at(ind).data( + std::make_unique(reinterpret_cast(buffer), length)); + } + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +bool ANeuralNetworksModel::addOperation(ANeuralNetworksOperationType type, uint32_t inputCount, + const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) noexcept +{ + try + { + for (uint32_t i = 0; i < outputCount; i++) + { + _operand_usages[outputs[i]] = OperandUsage::OPERATION_OUTPUT; + } + + auto &factory = OperationFactory::get(); + OperationFactory::Param param{inputCount, inputs, outputCount, outputs}; + + auto node = factory.create(type, param, _graph->operands()); + _graph->addOperation(std::unique_ptr{node}); + + // TODO Move these codes to delegate.cpp + if (type == ANEURALNETWORKS_FULLY_CONNECTED) + { + const auto &input_operand = + _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::INPUT)); + auto &weights_operand = + _graph->operands().at(node->getInputs().at(onert::ir::operation::FullyConnected::WEIGHT)); + if (input_operand.typeInfo().type() == onert::ir::DataType::FLOAT32 && + weights_operand.typeInfo().type() == onert::ir::DataType::QUANT8_ASYMM) + { + weights_operand.type(onert::ir::DataType::QUANT8_SYMM); + } + } + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +bool ANeuralNetworksModel::addOperationEx(ANeuralNetworksOperationTypeEx type, uint32_t inputCount, + const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) noexcept +{ + try + { + for (uint32_t i = 0; i < outputCount; i++) + { + _operand_usages[outputs[i]] = OperandUsage::OPERATION_OUTPUT; + } + + auto &factory = OperationFactory::get(); + OperationFactory::Param param{inputCount, inputs, outputCount, outputs}; + + auto node = factory.create(type, param, _graph->operands()); + _graph->addOperation(std::unique_ptr{node}); + } + catch (const std::exception &e) + { + return false; + } + return true; +} + +bool ANeuralNetworksModel::addModelInput(uint32_t index) noexcept +{ + try + { + _operand_usages[index] = OperandUsage::MODEL_INPUT; + + const onert::ir::OperandIndex ind{index}; + _graph->addInput(ind); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} +bool ANeuralNetworksModel::addModelOutput(uint32_t index) noexcept +{ + try + { + const onert::ir::OperandIndex ind{index}; + + // Duplicated output is not allowed + if (_graph->getOutputs().contains(ind)) + { + return false; + } + + _graph->addOutput(ind); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << std::endl; + + return false; + } + + return true; +} + +bool ANeuralNetworksModel::finish() noexcept +{ + try + { + fillOptionalOperand(); + + _graph->finishBuilding(); + + _operand_usages.clear(); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << '\n'; + + return false; + } + + return true; +} + +bool ANeuralNetworksModel::isFinished() noexcept { return !_graph->isBuildingPhase(); } + +bool ANeuralNetworksModel::isExistOperand(uint32_t index) noexcept +{ + return _graph->operands().exist(onert::ir::OperandIndex{index}); +} + +size_t ANeuralNetworksModel::operandSize(uint32_t index) noexcept +{ + try + { + return _graph->operands().at(onert::ir::OperandIndex{index}).operandSize(); + } + catch (const std::exception &e) + { + VERBOSE(EXCEPTION) << e.what() << '\n'; + + return 0; + } +} + +bool ANeuralNetworksModel::isUsageSet(uint32_t index) noexcept +{ + return (_operand_usages[index] != OperandUsage::NOT_DEFINED); +} + +bool ANeuralNetworksModel::isOperationOutput(uint32_t index) noexcept +{ + return (_operand_usages[index] == OperandUsage::OPERATION_OUTPUT); +} + +void ANeuralNetworksModel::setOptionalOperand(const onert::ir::OperandIndex idx) +{ + _optional_operands.insert(idx); +} + +void ANeuralNetworksModel::fillOptionalOperand(void) +{ + _graph->operations().iterate([&](const onert::ir::OperationIndex &, onert::ir::Operation &node) { + for (auto input : node.getInputs()) + { + // TODO fill default value for optional operands + if (_optional_operands.find(input) != _optional_operands.end()) + { + throw std::runtime_error{"Optional operand is not supported yet"}; + } + } + }); +} diff --git a/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h new file mode 100644 index 000000000..3ccd941c7 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/ANeuralNetworksModel.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MODEL_H__ +#define __MODEL_H__ + +#include +#include +#include + +#include "ir/Graph.h" + +struct ANeuralNetworksModel +{ +public: + enum class OperandUsage + { + NOT_DEFINED = 0, + MODEL_INPUT, + CONSTANT, + OPERATION_OUTPUT, + }; + +public: + ANeuralNetworksModel() noexcept; + +public: + bool addOperand(const ANeuralNetworksOperandType *type) noexcept; + bool setOperandValue(uint32_t index, const void *buffer, size_t length, bool optional = false, + bool copy = false) noexcept; + bool addOperation(ANeuralNetworksOperationType type, uint32_t inputCount, const uint32_t *inputs, + uint32_t outputCount, const uint32_t *outputs) noexcept; + bool addOperationEx(ANeuralNetworksOperationTypeEx type, uint32_t inputCount, + const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) noexcept; + bool addModelInput(uint32_t index) noexcept; + bool addModelOutput(uint32_t index) noexcept; + bool finish() noexcept; + + onert::ir::Graph &deref(void) { return *_graph; } + bool isFinished() noexcept; + bool isExistOperand(uint32_t index) noexcept; + size_t operandSize(uint32_t index) noexcept; + bool isUsageSet(uint32_t index) noexcept; + bool isOperationOutput(uint32_t index) noexcept; + void release(std::shared_ptr &graph) { graph = _graph; } + +private: + void setOptionalOperand(const onert::ir::OperandIndex idx); + void fillOptionalOperand(void); + +private: + std::shared_ptr _graph; + std::unordered_set _optional_operands; + std::vector _operand_usages; +}; + +#endif // __MODEL_H__ diff --git a/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc new file mode 100644 index 000000000..e07297241 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.cc @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NNAPIConvert.h" + +#include + +using namespace onert::ir; + +DataType NNAPIConvert::getDataType(OperandCode type) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + return DataType::FLOAT32; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + return DataType::INT32; + case ANEURALNETWORKS_UINT32: + return DataType::UINT32; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + return DataType::QUANT8_ASYMM; + case ANEURALNETWORKS_TENSOR_QUANT8_SYMM: + return DataType::QUANT8_SYMM; + case ANEURALNETWORKS_BOOL: + case ANEURALNETWORKS_TENSOR_BOOL8: + return DataType::BOOL8; + default: + throw std::runtime_error("Unsupported type"); + } +} + +TypeInfo NNAPIConvert::getTypeInfo(const ANeuralNetworksOperandType *type) +{ + return TypeInfo(getDataType((OperandCode)(type->type)), type->scale, type->zeroPoint); +} + +Shape NNAPIConvert::getShape(const ANeuralNetworksOperandType *type) +{ + Shape shape(type->dimensionCount); + + for (uint32_t axis = 0; axis < type->dimensionCount; ++axis) + { + shape.dim(axis) = type->dimensions[axis]; + } + + return shape; +} + +size_t NNAPIConvert::calculateSizeFromType(const ANeuralNetworksOperandType *type) +{ + auto shape = getShape(type); + auto data_type = getDataType((OperandCode)(type->type)); + + return shape.num_elements() * sizeOfDataType(data_type); +} + +Activation NNAPIConvert::getFusedActivation(FuseCode act) +{ + switch (act) + { + case ANEURALNETWORKS_FUSED_NONE: + return Activation::NONE; + case ANEURALNETWORKS_FUSED_RELU: + return Activation::RELU; + case ANEURALNETWORKS_FUSED_RELU1: + return Activation::RELU1; + case ANEURALNETWORKS_FUSED_RELU6: + return Activation::RELU6; + default: + throw std::runtime_error("Unsupported activation type"); + } +} + +PaddingType NNAPIConvert::getPaddingType(PaddingCode type) +{ + switch (type) + { + case ANEURALNETWORKS_PADDING_SAME: + return PaddingType::SAME; + case ANEURALNETWORKS_PADDING_VALID: + return PaddingType::VALID; + default: + throw std::runtime_error("Unsupported type"); + } +} diff --git a/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.h b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.h new file mode 100644 index 000000000..4fd985e6e --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/NNAPIConvert.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file NNAPIConvert.h + * @brief This file contains convereter(s)\n + * from NNAPI frontend's struct to onert's internal struct + */ +#ifndef __ONERT_NNAPI_CONVERT_H__ +#define __ONERT_NNAPI_CONVERT_H__ + +#include + +#include +#include +#include +#include + +class NNAPIConvert +{ + +public: + /** + * @brief Convert data type from NNAPI to internal data type + * @param[in] type NNAPI's data type + * @return onert's internal data type + */ + static onert::ir::DataType getDataType(OperandCode type); + + /** + * @brief Convert operand type info from NNAPI to interanl operand type info + * @param[in] type NNAPI's operand type + * @return onert's internal operand type info + */ + static onert::ir::TypeInfo getTypeInfo(const ANeuralNetworksOperandType *type); + + /** + * @brief Convert operand shape info from NNAPI to internal operand shape + * @param[in] type NNAPI's operand type + * @return onert's internal operand shape + */ + static onert::ir::Shape getShape(const ANeuralNetworksOperandType *type); + + /** + * @brief Calcaulate operand size from NNAPI type + * @param[in] type NNAPI's operand type + * @return Operand size + */ + static size_t calculateSizeFromType(const ANeuralNetworksOperandType *type); + + /** + * @brief Convert NNAPI FuseCode to internal activation type + * @param[in] act NNAPI's FuseCode type + * @return onert's internal activation type + */ + static onert::ir::Activation getFusedActivation(FuseCode act); + + /** + * @brief Convert NNAPI PaddingCode to internal padding type + * @param[in] type NNAPI's PaddingCode type + * @return onert's internal padding type + */ + static onert::ir::PaddingType getPaddingType(PaddingCode type); +}; + +#endif // __ONERT_NNAPI_CONVERT_H__ diff --git a/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc new file mode 100644 index 000000000..10e7c0341 --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.cc @@ -0,0 +1,1899 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "OperationFactory.h" +#include "NNAPIConvert.h" + +#include +#include + +namespace +{ +using namespace onert::ir; + +void replaceDataType(Operands &operands, const OperandIndex &index, const DataType type) +{ + assert(operands.exist(index)); + operands.at(index).type(type); +} + +ExplicitPadding makeExplicitPadding(Operands &operands, const OperandIndex &left_index, + const OperandIndex &right_index, const OperandIndex &top_index, + const OperandIndex &bottom_index) +{ + auto left = operands.at(left_index).asScalar(); + auto right = operands.at(right_index).asScalar(); + auto top = operands.at(top_index).asScalar(); + auto bottom = operands.at(bottom_index).asScalar(); + + if (left < 0 || right < 0 || top < 0 || bottom < 0) + { + throw std::runtime_error{"Cannot handle negative explicit padding value"}; + } + + ExplicitPadding param; + param.left = static_cast(left); + param.right = static_cast(right); + param.top = static_cast(top); + param.bottom = static_cast(bottom); + + return param; +} + +Stride makeStride(Operands &operands, const OperandIndex &horizontal_index, + const OperandIndex &vertical_index) +{ + auto horizontal = operands.at(horizontal_index).asScalar(); + auto vertical = operands.at(vertical_index).asScalar(); + + if (vertical < 0 || horizontal < 0) + { + throw std::runtime_error{"Cannot handle negative stride value"}; + } + + Stride stride; + stride.horizontal = static_cast(horizontal); + stride.vertical = static_cast(vertical); + + return stride; +} + +uint32_t getUint32Scalar(Operands &operands, const OperandIndex index) +{ + auto int32_value = operands.at(index).asScalar(); + if (int32_value < 0) + { + throw std::runtime_error{"Cannot handle negative value"}; + } + + return static_cast(int32_value); +} + +} // namespace + +OperationFactory &OperationFactory::get() +{ + static OperationFactory factory; + return factory; +} + +OperationFactory::OperationFactory() +{ + _map[ANEURALNETWORKS_BATCH_TO_SPACE_ND] = [](const OperationFactory::Param &init_param, + Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Block size Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + return new operation::BatchToSpaceND{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_DEPTHWISE_CONV_2D] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert((init_param.input_count == 8 || init_param.input_count == 11) && + init_param.output_count == 1); + + // In common + // 0 -> IFM Tensor Index + // 1 -> Kernel Tensor Index + // 2 -> Bias Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + operation::DepthwiseConv2D::Param param; + if (init_param.input_count == 8) + { + // Imlicit Padding case + // Each input should be interpreted as follows: + // + // 3 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 4 -> Stride (width) Index + // 5 -> Stride (height) INdex + // 6 -> Depthwise multiplier + // 7 -> Activation Index + + const auto padding_index = OperandIndex{init_param.inputs[3]}; + const auto hstride_index = OperandIndex{init_param.inputs[4]}; + const auto vstride_index = OperandIndex{init_param.inputs[5]}; + const auto multiplier_index = OperandIndex{init_param.inputs[6]}; + const auto activation_index = OperandIndex{init_param.inputs[7]}; + + param.padding.type = + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar()); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.multiplier = getUint32Scalar(operands, multiplier_index); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + else + { + // Explicit Padding case + // Each input should be interpreted as follows: + // + // 3 -> Padding On the Left + // 4 -> Padding On the Right + // 5 -> Padding On the Top + // 6 -> Padding On the Bottom + // 7 -> Stride (width) Index + // 8 -> Stride (height) Index + // 9 -> Depthwise multiplier + // 10-> Activation Index + + const auto padding_left_index = OperandIndex{init_param.inputs[3]}; + const auto padding_right_index = OperandIndex{init_param.inputs[4]}; + const auto padding_top_index = OperandIndex{init_param.inputs[5]}; + const auto padding_bottom_index = OperandIndex{init_param.inputs[6]}; + const auto hstride_index = OperandIndex{init_param.inputs[7]}; + const auto vstride_index = OperandIndex{init_param.inputs[8]}; + const auto multiplier_index = OperandIndex{init_param.inputs[9]}; + const auto activation_index = OperandIndex{init_param.inputs[10]}; + + param.padding.type = PaddingType::EXPLICIT; + param.padding.param = makeExplicitPadding(operands, padding_left_index, padding_right_index, + padding_top_index, padding_bottom_index); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.multiplier = getUint32Scalar(operands, multiplier_index); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + + return new operation::DepthwiseConv2D{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_MAX_POOL_2D] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 7 || init_param.input_count == 10); + assert(init_param.output_count == 1); + + // In common + // 0 -> IFM Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + operation::MaxPool2D::Param param; + if (init_param.input_count == 7) // support implicit padding + { + // Each input should be interpreted as follows: + // + // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 2 -> Horizontal (over width) Stride Index + // 3 -> Vertial (over height) Stride Index + // 4 -> Filter Width Index + // 5 -> Filter Height Index + // 6 -> FuseCode (activation) Index + + const auto padding_index = OperandIndex{init_param.inputs[1]}; + const auto hstride_index = OperandIndex{init_param.inputs[2]}; + const auto vstride_index = OperandIndex{init_param.inputs[3]}; + const auto kw_index = OperandIndex{init_param.inputs[4]}; + const auto kh_index = OperandIndex{init_param.inputs[5]}; + const auto activation_index = OperandIndex{init_param.inputs[6]}; + + param.padding.type = + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar()); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.kw = getUint32Scalar(operands, kw_index); + param.kh = operands.at(kh_index).asScalar(); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + else if (init_param.input_count == 10) // support explicit padding + { + // Each input should be interpreted as follows: + // + // 1 -> Padding_left index + // 2 -> Padding_right index + // 3 -> Padding_top index + // 4 -> Padding_bottom index + // 5 -> Horizontal (over width) Stride Index + // 6 -> Vertial (over height) Stride Index + // 7 -> Filter Width Index + // 8 -> Filter Height Index + // 9 -> FuseCode (activation) Index + + const auto padding_left_index = OperandIndex{init_param.inputs[1]}; + const auto padding_right_index = OperandIndex{init_param.inputs[2]}; + const auto padding_top_index = OperandIndex{init_param.inputs[3]}; + const auto padding_bottom_index = OperandIndex{init_param.inputs[4]}; + const auto hstride_index = OperandIndex{init_param.inputs[5]}; + const auto vstride_index = OperandIndex{init_param.inputs[6]}; + const auto kw_index = OperandIndex{init_param.inputs[7]}; + const auto kh_index = OperandIndex{init_param.inputs[8]}; + const auto activation_index = OperandIndex{init_param.inputs[9]}; + + param.padding.type = PaddingType::EXPLICIT; + param.padding.param = makeExplicitPadding(operands, padding_left_index, padding_right_index, + padding_top_index, padding_bottom_index); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.kw = getUint32Scalar(operands, kw_index); + param.kh = getUint32Scalar(operands, kh_index); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + return new operation::MaxPool2D{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_AVERAGE_POOL_2D] = [](const OperationFactory::Param &init_param, + Operands &operands) { + // TODO We may reuse code here for MAX_POOL_2D. Seems like these two are identical + assert(init_param.input_count == 7 || init_param.input_count == 10); + assert(init_param.output_count == 1); + + // In common + // 0 -> IFM Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + operation::AvgPool2D::Param param; + if (init_param.input_count == 7) // support implicit padding + { + // Each input should be interpreted as follows: + // + // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 2 -> Horizontal (over width) Stride Index + // 3 -> Vertial (over height) Stride Index + // 4 -> Filter Width Index + // 5 -> Filter Height Index + // 6 -> FuseCode (activation) Index + + const auto padding_index = OperandIndex{init_param.inputs[1]}; + const auto hstride_index = OperandIndex{init_param.inputs[2]}; + const auto vstride_index = OperandIndex{init_param.inputs[3]}; + const auto kw_index = OperandIndex{init_param.inputs[4]}; + const auto kh_index = OperandIndex{init_param.inputs[5]}; + const auto activation_index = OperandIndex{init_param.inputs[6]}; + + param.padding.type = + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar()); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.kw = getUint32Scalar(operands, kw_index); + param.kh = getUint32Scalar(operands, kh_index); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + else if (init_param.input_count == 10) // support explicit padding + { + // Each input should be interpreted as follows: + // + // 1 -> Padding_left index + // 2 -> Padding_right index + // 3 -> Padding_top index + // 4 -> Padding_bottom index + // 5 -> Horizontal (over width) Stride Index + // 6 -> Vertial (over height) Stride Index + // 7 -> Filter Width Index + // 8 -> Filter Height Index + // 9 -> FuseCode (activation) Index + + const auto padding_left_index = OperandIndex{init_param.inputs[1]}; + const auto padding_right_index = OperandIndex{init_param.inputs[2]}; + const auto padding_top_index = OperandIndex{init_param.inputs[3]}; + const auto padding_bottom_index = OperandIndex{init_param.inputs[4]}; + const auto hstride_index = OperandIndex{init_param.inputs[5]}; + const auto vstride_index = OperandIndex{init_param.inputs[6]}; + const auto kw_index = OperandIndex{init_param.inputs[7]}; + const auto kh_index = OperandIndex{init_param.inputs[8]}; + const auto activation_index = OperandIndex{init_param.inputs[9]}; + + param.padding.type = PaddingType::EXPLICIT; + param.padding.param = makeExplicitPadding(operands, padding_left_index, padding_right_index, + padding_top_index, padding_bottom_index); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.kw = getUint32Scalar(operands, kw_index); + param.kh = getUint32Scalar(operands, kh_index); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + + return new operation::AvgPool2D{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_CONCATENATION] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count >= 2); // At least one one input tensor and axis + assert(init_param.output_count == 1); + + // When there are N + 1 inputs, each input should be interpreted as follows: + // + // [0, N) -> Input tensors + // N -> Axis + // + + OperandIndexSequence inputs; + for (uint32_t n = 0; n < init_param.input_count - 1; ++n) + { + inputs.append(OperandIndex{init_param.inputs[n]}); + } + OperandIndexSequence outputs{init_param.outputs[0]}; + + operation::Concat::Param param; + const OperandIndex axis_index{init_param.inputs[init_param.input_count - 1]}; + param.axis = operands.at(axis_index).asScalar(); + param.rank = operands.at(outputs.at(0)).shape().rank(); + + return new operation::Concat{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_RESHAPE] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + // Each input should be interpreted as follows: + // + // 0 -> A tensor, specifying the tensor to be reshaped. + // 1 -> A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32, defining the shape of the output + // tensor + + // TODO Second input should be shape tensor (init_param.inputs[1]) + // Currently unused since assume that it is same with output tensor size + OperandIndexSequence inputs{init_param.inputs[0] /* , init_param.inputs[1] */}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + return new operation::Reshape{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_FULLY_CONNECTED] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 4 && init_param.output_count == 1); + + // Each input should be interpreted as follows: + // + // 0 -> A tensor, specifying the input. + // 1 -> A 2-D tensor, specifying the weights + // 2 -> A 1-D tensor, specifying the bias + // 3 -> An INT32 value, and has to be one of the FuseCode values + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + operation::FullyConnected::Param param; + const auto activation_index = OperandIndex{init_param.inputs[3]}; + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + + return new operation::FullyConnected{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_SOFTMAX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + // Each input should be interpreted as follows: + // + // 0 -> A 2-D or 4-D tensor, specifying the tensor to be reshaped. + // 1 -> FLOAT32 value, specifying the positive scaling factor for the exponent, beta. + + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + const auto beta_index = OperandIndex{init_param.inputs[1]}; + + operation::Softmax::Param param; + param.beta = operands.at(beta_index).asScalar(); + + return new operation::Softmax{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_CAST] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // 0 -> input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + // NNAPI uses QUANT8_ASYMM to represent UINT8 type for ANEURALNETWORKS_CAST's input/output + if (operands.at(inputs.at(0)).typeInfo().type() == DataType::QUANT8_ASYMM) + { + replaceDataType(operands, inputs.at(0), DataType::UINT8); + } + if (operands.at(outputs.at(0)).typeInfo().type() == DataType::QUANT8_ASYMM) + { + replaceDataType(operands, outputs.at(0), DataType::UINT8); + } + + return new operation::Cast{inputs, outputs}; + }; + + // ANEURALNETWORKS_CAST_EX is deprecated + // TODO Remove ANEURALNETWORKS_CAST_EX + _map[ANEURALNETWORKS_CAST_EX] = _map[ANEURALNETWORKS_CAST]; + + _map[ANEURALNETWORKS_CONV_2D] = [](const OperationFactory::Param &init_param, + Operands &operands) { + using operation::Conv2D; + + // inputCount is either 7 or 10 acccording to NN API specification. + // - Padding is implicit when inputCount is 7 + // - Padding is explicit when inputCount is 10 + assert(init_param.input_count == 7 || init_param.input_count == 10); + assert(init_param.output_count == 1); + + // 0 -> IFM Tensor Index + // 1 -> Kernel Tensor Index + // 2 -> Bias Tensor Index + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + Conv2D::Param param; + + if (init_param.input_count == 7) // support implicit padding + { + // Each input should be interpreted as follows: + // + // 3 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 4 -> Stride (width) Index + // 5 -> Stride (height) INdex + // 6 -> Activation Index + + const auto padding_index = OperandIndex{init_param.inputs[3]}; + const auto hstride_index = OperandIndex{init_param.inputs[4]}; + const auto vstride_index = OperandIndex{init_param.inputs[5]}; + const auto activation_index = OperandIndex{init_param.inputs[6]}; + + param.padding.type = + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar()); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + else if (init_param.input_count == 10) // support explicit padding + { + // Each input should be interpreted as follows: + // + // 3 -> Padding_left index + // 4 -> Padding_right index + // 5 -> Padding_top index + // 6 -> Padding_bottom index + // 7 -> Stride (width) Index + // 8 -> Stride (height) INdex + // 9 -> Activation Index + + const auto padding_left_index = OperandIndex{init_param.inputs[3]}; + const auto padding_right_index = OperandIndex{init_param.inputs[4]}; + const auto padding_top_index = OperandIndex{init_param.inputs[5]}; + const auto padding_bottom_index = OperandIndex{init_param.inputs[6]}; + const auto hstride_index = OperandIndex{init_param.inputs[7]}; + const auto vstride_index = OperandIndex{init_param.inputs[8]}; + const auto activation_index = OperandIndex{init_param.inputs[9]}; + + param.padding.type = PaddingType::EXPLICIT; + param.padding.param = makeExplicitPadding(operands, padding_left_index, padding_right_index, + padding_top_index, padding_bottom_index); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + + return new Conv2D{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_ADD] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 3); + assert(init_param.output_count == 1); + + // Each input should be interpreted as follows: + // + // 0 -> Lefthand side operand + // 1 -> Righthand side operand + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + operation::Add::Param param; + + const auto activation_index = OperandIndex{init_param.inputs[2]}; + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + + return new operation::Add{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_REDUCE_SUM] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 3); + assert(init_param.output_count == 1); + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Reduced Axes Tensor Index + // 2 -> keep_dims Index + + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + std::vector axes = + operands.at(OperandIndex{init_param.inputs[1]}).asVector(); + + operation::ReduceSum::Param param; + param.axes.assign(axes.cbegin(), axes.cend()); + param.keep_dims = operands.at(OperandIndex{init_param.inputs[2]}).asScalar() != 0; + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::ReduceSum{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_REDUCE_SUM_EX is deprecated + // TODO Remove ANEURALNETWORKS_REDUCE_SUM_EX + _map[ANEURALNETWORKS_REDUCE_SUM_EX] = _map[ANEURALNETWORKS_REDUCE_SUM]; + + _map[ANEURALNETWORKS_SUB] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 3); + assert(init_param.output_count == 1); + + // Each input should be interpreted as follows: + // + // 0 -> Lefthand side operand + // 1 -> Righthand side operand + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + operation::Sub::Param param; + + const auto activation_index = OperandIndex{init_param.inputs[2]}; + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + + return new operation::Sub{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_SLICE] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Begins Tensor Index + // 2 -> Sizes Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]}; + + operation::Slice::Param param; + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::Slice{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_STRIDED_SLICE] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 7 && init_param.output_count == 1); + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2], + init_param.inputs[3]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 1 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the starts of + // the dimensions of the input tensor to be sliced. The length must be + // of rank(input0). + // 2 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the ends of + // the dimensions of the input tensor to be sliced. The length must be + // of rank(input0). + // 3 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the strides of + // the dimensions of the input tensor to be sliced. The length must be + // of rank(input0). + // 4 -> An {@link ANEURALNETWORKS_INT32} scalar, begin_mask. If the ith bit + // of begin_mask is set, begin[i] is ignored and the fullest possible + // range in that dimension is used instead. + // 5 -> An {@link ANEURALNETWORKS_INT32} scalar, end_mask. If the ith bit of + // end_mask is set, end[i] is ignored and the fullest possible range in + // that dimension is used instead. + // 6 -> An {@link ANEURALNETWORKS_INT32} scalar, shrink_axis_mask. An int32 + // mask. If the ith bit of shrink_axis_mask is set, it implies that the + // ith specification shrinks the dimensionality by 1. A slice of size 1 + // starting from begin[i] in the dimension must be preserved. + + operation::StridedSlice::Param param; + + param.begin_mask = operands.at(OperandIndex{init_param.inputs[4]}).asScalar(); + param.end_mask = operands.at(OperandIndex{init_param.inputs[5]}).asScalar(); + param.shrink_axis_mask = + operands.at(OperandIndex{init_param.inputs[6]}).asScalar(); + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::StridedSlice{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_TRANSPOSE] = [](const OperationFactory::Param &init_param, + Operands &operands) { + // TODO make this work with init_param.input_count == 1 (when permutation vector is optional) + + // Inputs + // 0: An n-D tensor, specifying the tensor to be transposed. + // 1: An optional 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, + // the permutation of the dimensions of the input tensor. + // The returned tensor's dimension i corresponds to the input dimension + // perm[i]. If perm is not given, it is set to (n-1...0), where n is the + // rank of the input tensor. Hence by default, this operation performs a + // regular matrix transpose on 2-D input Tensors. + assert(init_param.input_count == 2); + assert(init_param.output_count == 1); + + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + std::vector perm = + operands.at(OperandIndex{init_param.inputs[1]}).asVector(); + + operation::Transpose::Param param; + param.perm.assign(perm.cbegin(), perm.cend()); + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::Transpose{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_MUL] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> LHS Tensor Index + // 1 -> RHS Tensor Index + // 2 -> Activation Index + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Mul::Param param; + + const auto activation_index = OperandIndex{init_param.inputs[2]}; + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + + return new operation::Mul{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_SQUEEZE] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 1 || init_param.input_count == 2); + assert(init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> An n-D tensor, the tensor to be squeezed. + // 1 -> An optional 1-D tensor of ANEURALNETWORKS_TENSOR_INT32. The dimensions to squeeze. + // If specified only squeezes the dimensions listed. Otherwise, squeezes all dimensions. + // The dimension index starts at 0. An error must be reported if squeezing a dimension that + // is not 1. + + // Add mandatory input index + OperandIndexSequence inputs{init_param.inputs[0]}; + + // Add dims index if specified + operation::Squeeze::Param param{}; + if (init_param.input_count == 2) + { + auto squeeze_dims_idx = OperandIndex{init_param.inputs[1]}; + assert(operands.at(squeeze_dims_idx).shape().rank() == 1); + assert(operands.at(squeeze_dims_idx).shape().dim(0) >= 0); + assert(static_cast(operands.at(squeeze_dims_idx).shape().dim(0)) <= + sizeof(param.dims)); + param.ndim = operands.at(squeeze_dims_idx).shape().dim(0); + if (param.ndim > 0) + { + assert(operands.at(squeeze_dims_idx).data()); + memcpy(param.dims, operands.at(squeeze_dims_idx).data()->base(), + param.ndim * sizeof(param.dims[0])); + } + } + + return new operation::Squeeze{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_TANH] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::Tanh{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_LOGISTIC] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::Logistic{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_DIV] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> LHS Tensor Index + // 1 -> RHS Tensor Index + // 2 -> Activation Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Div::Param param; + + const auto activation_index = OperandIndex{init_param.inputs[2]}; + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + + return new operation::Div{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_EXP] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::Exp{inputs, outputs}; + }; + + // ANEURALNETWORKS_EXP_EX is deprecated + // TODO Remove ANEURALNETWORKS_EXP_EX + _map[ANEURALNETWORKS_EXP_EX] = _map[ANEURALNETWORKS_EXP]; + + _map[ANEURALNETWORKS_GREATER] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::Greater; + + return new operation::Comparison{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_GREATER_EQUAL] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::GreaterEqual; + + return new operation::Comparison{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_GREATER_EQUAL_EX is deprecated + // TODO Remove ANEURALNETWORKS_GREATER_EQUAL_EX + _map[ANEURALNETWORKS_GREATER_EQUAL_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::GreaterEqual; + + // Output operand type must be boolean + replaceDataType(operands, outputs.at(0), DataType::BOOL8); + + return new operation::Comparison{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_LESS] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::Less; + + return new operation::Comparison{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_LESS_EQUAL] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::LessEqual; + + return new operation::Comparison{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_LESS_EX is deprecated + // TODO Remove ANEURALNETWORKS_LESS_EX + _map[ANEURALNETWORKS_LESS_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::Less; + + // Output operand type must be boolean + replaceDataType(operands, outputs.at(0), DataType::BOOL8); + + return new operation::Comparison{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_REDUCE_MAX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Axis Tensor Index + // 2 -> keep_dims Index + OperandIndexSequence inputs{init_param.inputs[0]}; + std::vector axes = + operands.at(OperandIndex{init_param.inputs[1]}).asVector(); + + operation::ReduceMax::Param param; + param.axes.assign(axes.cbegin(), axes.cend()); + param.keep_dims = operands.at(OperandIndex{init_param.inputs[2]}).asScalar() != 0; + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::ReduceMax{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_REDUCE_MAX_EX is deprecated + // TODO Remove ANEURALNETWORKS_REDUCE_MAX_EX + _map[ANEURALNETWORKS_REDUCE_MAX_EX] = _map[ANEURALNETWORKS_REDUCE_MAX]; + + _map[ANEURALNETWORKS_NOT_EQUAL] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input1 Tensor Index + // 1 -> input2 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::NotEqual; + + return new operation::Comparison{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_NOT_EQUAL_EX is deprecated + // TODO Remove ANEURALNETWORKS_NOT_EQUAL_EX + _map[ANEURALNETWORKS_NOT_EQUAL_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input1 Tensor Index + // 1 -> input2 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::NotEqual; + + // Output operand type must be boolean + replaceDataType(operands, outputs.at(0), DataType::BOOL8); + + return new operation::Comparison{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_LOGICAL_AND] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + return new operation::LogicalAnd{inputs, outputs}; + }; + + // ANEURALNETWORKS_LOGICAL_AND_EX is deprecated + // TODO Remove ANEURALNETWORKS_LOGICAL_AND_EX + _map[ANEURALNETWORKS_LOGICAL_AND_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + // This operation's operands must be boolean type. + replaceDataType(operands, inputs.at(0), DataType::BOOL8); + replaceDataType(operands, inputs.at(1), DataType::BOOL8); + replaceDataType(operands, outputs.at(0), DataType::BOOL8); + + return new operation::LogicalAnd{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_RSQRT] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::RSQRT{inputs, outputs}; + }; + + // ANEURALNETWORKS_RSQRT_EX is deprecated + // TODO Remove ANEURALNETWORKS_RSQRT_EX + _map[ANEURALNETWORKS_RSQRT_EX] = _map[ANEURALNETWORKS_RSQRT]; + + _map[ANEURALNETWORKS_RELU] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::ReLU{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_RESIZE_BILINEAR] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Index + // 1 -> Height Index + // 2 -> Width Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + operation::ResizeBilinear::Param param; + param.height_out = operands.at(OperandIndex{init_param.inputs[1]}).asScalar(); + param.width_out = operands.at(OperandIndex{init_param.inputs[2]}).asScalar(); + + return new operation::ResizeBilinear{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_RELU1] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::ReLU1{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_RELU6] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::ReLU6{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_RNN] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 6 && init_param.output_count == 2); + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Weights Tensor Index + // 2 -> Recurrent Weights Tensor Index + // 3 -> Bias Tensor Index + // 4 -> Hidden state (in) Index + // 5 -> Activation Index + + OperandIndexSequence inputs; + for (uint32_t n = 0; n < init_param.input_count - 1; ++n) + { + inputs.append(OperandIndex{init_param.inputs[n]}); + } + OperandIndexSequence outputs; + for (uint32_t n = 0; n < init_param.output_count; ++n) + { + outputs.append(OperandIndex{init_param.outputs[n]}); + } + + operation::RNN::Param param; + const auto activation_index = OperandIndex{init_param.inputs[5]}; + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + + return new operation::RNN{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_FLOOR] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // 0 -> input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::Floor{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_SPACE_TO_BATCH_ND] = [](const OperationFactory::Param &init_param, + Operands &) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Block size Index + // 2 -> Paddings Index + OperandIndexSequence inputs; + for (uint32_t n = 0; n < init_param.input_count; ++n) + { + inputs.append(OperandIndex{init_param.inputs[n]}); + } + + return new operation::SpaceToBatchND{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_SPACE_TO_DEPTH] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Block size Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + operation::SpaceToDepth::Param param; + param.block_size = operands.at(OperandIndex{init_param.inputs[1]}).asScalar(); + + return new operation::SpaceToDepth{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_L2_POOL_2D] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 10 || init_param.input_count == 7); + assert(init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + operation::L2Pool2D::Param param; + + if (init_param.input_count == 7) // Imlicit Padding case + { + // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 2 -> Horizontal (over width) Stride Index + // 3 -> Vertial (over height) Stride Index + // 4 -> Filter Width Index + // 5 -> Filter Height Index + // 6 -> FuseCode (activation) Index + const auto padding_index = OperandIndex{init_param.inputs[1]}; + const auto hstride_index = OperandIndex{init_param.inputs[2]}; + const auto vstride_index = OperandIndex{init_param.inputs[3]}; + const auto kw_index = OperandIndex{init_param.inputs[4]}; + const auto kh_index = OperandIndex{init_param.inputs[5]}; + const auto activation_index = OperandIndex{init_param.inputs[6]}; + + param.padding.type = + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar()); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.kw = getUint32Scalar(operands, kw_index); + param.kh = getUint32Scalar(operands, kh_index); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + else // Explicit Padding case + { + // 1 -> Padding_left index + // 2 -> Padding_right index + // 3 -> Padding_top index + // 4 -> Padding_bottom index + // 5 -> Horizontal (over width) Stride Index + // 6 -> Vertial (over height) Stride Index + // 7 -> Filter Width Index + // 8 -> Filter Height Index + // 9 -> FuseCode (activation) Index + const auto padding_left_index = OperandIndex{init_param.inputs[1]}; + const auto padding_right_index = OperandIndex{init_param.inputs[2]}; + const auto padding_top_index = OperandIndex{init_param.inputs[3]}; + const auto padding_bottom_index = OperandIndex{init_param.inputs[4]}; + const auto hstride_index = OperandIndex{init_param.inputs[5]}; + const auto vstride_index = OperandIndex{init_param.inputs[6]}; + const auto kw_index = OperandIndex{init_param.inputs[7]}; + const auto kh_index = OperandIndex{init_param.inputs[8]}; + const auto activation_index = OperandIndex{init_param.inputs[9]}; + + param.padding.type = PaddingType::EXPLICIT; + param.padding.param = makeExplicitPadding(operands, padding_left_index, padding_right_index, + padding_top_index, padding_bottom_index); + param.stride = makeStride(operands, hstride_index, vstride_index); + param.kw = getUint32Scalar(operands, kw_index); + param.kh = getUint32Scalar(operands, kh_index); + param.activation = + NNAPIConvert::getFusedActivation(operands.at(activation_index).asScalar()); + } + + return new operation::L2Pool2D{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_EMBEDDING_LOOKUP] = [](const OperationFactory::Param &init_param, + Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Lookups Index + // 1 -> Values Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + return new operation::EmbeddingLookup{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_L2_NORMALIZATION] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // 0 -> input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + operation::L2Normalization::Param param; + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::L2Normalization{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_HASHTABLE_LOOKUP] = [](const OperationFactory::Param &init_param, + Operands &) { + assert(init_param.input_count == 3 && init_param.output_count == 2); + + // Each output should be interpreted as follows: + // + // 0 -> Output Index + // 1 -> Hits Index + OperandIndexSequence outputs{init_param.outputs[0], init_param.outputs[1]}; + + // Each input should be interpreted as follows: + // + // 0 -> Lookups Index + // 1 -> Keys Index + // 2 -> Values Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]}; + + return new operation::HashtableLookup{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_PRELU] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + // 1 -> alpha Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + return new operation::PReLU{inputs, outputs}; + }; + + // ANEURALNETWORKS_PRELU_EX is deprecated + // TODO Remove ANEURALNETWORKS_PRELU_EX + _map[ANEURALNETWORKS_PRELU_EX] = _map[ANEURALNETWORKS_PRELU]; + + _map[ANEURALNETWORKS_TRANSPOSE_CONV_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 6 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Output Shape Index + // 1 -> Weights Index + // 2 -> Input Tensor Index + // 3 -> Padding Type + // 4 -> Stride width + // 5 -> Stride height + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]}; + + operation::TransposeConv::Param param; + + const auto padding_index = OperandIndex{init_param.inputs[3]}; + const auto hstride_index = OperandIndex{init_param.inputs[4]}; + const auto vstride_index = OperandIndex{init_param.inputs[5]}; + + param.padding.type = + NNAPIConvert::getPaddingType(operands.at(padding_index).asScalar()); + param.stride = makeStride(operands, hstride_index, vstride_index); + + return new operation::TransposeConv{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_SQRT] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // 0 -> input Tensor Index + + OperandIndexSequence inputs{init_param.inputs[0]}; + return new operation::SQRT{inputs, outputs}; + }; + + // ANEURALNETWORKS_SQRT_EX is deprecated + // TODO Remove ANEURALNETWORKS_SQRT_EX + _map[ANEURALNETWORKS_SQRT_EX] = _map[ANEURALNETWORKS_SQRT]; + + _map[ANEURALNETWORKS_LOGICAL_OR] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + return new operation::LogicalOr{inputs, outputs}; + }; + + // ANEURALNETWORKS_LOGICAL_OR_EX is deprecated + // TODO Remove ANEURALNETWORKS_LOGICAL_OR_EX + _map[ANEURALNETWORKS_LOGICAL_OR_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + // This operation's operands must be boolean type. + replaceDataType(operands, inputs.at(0), DataType::BOOL8); + replaceDataType(operands, inputs.at(1), DataType::BOOL8); + replaceDataType(operands, outputs.at(0), DataType::BOOL8); + + return new operation::LogicalOr{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_LOGICAL_NOT] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::LogicalNot{inputs, outputs}; + }; + + // ANEURALNETWORKS_LOGICAL_NOT_EX is deprecated + // TODO Remove ANEURALNETWORKS_LOGICAL_NOT_EX + _map[ANEURALNETWORKS_LOGICAL_NOT_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + // This operation's operands must be boolean type. + replaceDataType(operands, inputs.at(0), DataType::BOOL8); + replaceDataType(operands, outputs.at(0), DataType::BOOL8); + + return new operation::LogicalNot{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_LSTM] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 23 && init_param.output_count == 4); + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Input to Input Tensor Index + // 2 -> Input to Forget Tensor Index + // 3 -> Input to Cell Tensor Index + // 4 -> Input to Output Tensor Index + // 5 -> Recurrent to Input Weights Tensor Index + // 6 -> Recurrent to Forget Weights Tensor Index + // 7 -> Recurrent to Cell Weights Tensor Index + // 8 -> Recurrent to Output Weights Tensor Index + // 9 -> Cell to Input Weights Tensor Index + // 10 -> Cell to Forget Weights Tensor Index + // 11 -> Cell to Output Weights Tensor Index + // 12 -> Input Gate Bias Tensor Index + // 13 -> Forget Gate Bias Tensor Index + // 14 -> Cell Bias Tensor Index + // 15 -> Output Gate Bias Tensor Index + // 16 -> Projection Weights Tensor Index + // 17 -> Projection Bias Tensor Index + // 18 -> Output State In Tensor Index + // 19 -> Cell State In Tensor Index + OperandIndexSequence inputs; + for (uint32_t n = 0; n < init_param.input_count - 3; ++n) + { + inputs.append(OperandIndex{init_param.inputs[n]}); + } + + // Each output should be interpreted as follows: + // + // 0 -> Scratch Buffer Tensor Index + // 1 -> Output State Out Tensor Index + // 2 -> Cell State Out Tensor Index + // 3 -> Output Tensor Index + OperandIndexSequence outputs; + for (uint32_t n = 0; n < init_param.output_count; ++n) + { + outputs.append(OperandIndex{init_param.outputs[n]}); + } + + operation::LSTM::Param param; + const auto activation_index = OperandIndex{init_param.inputs[20]}; + switch (operands.at(activation_index).asScalar()) + { + case 0: + param.activation = Activation::NONE; + break; + case 1: + param.activation = Activation::RELU; + break; + case 2: + param.activation = Activation::RELU1; + break; + case 3: + param.activation = Activation::RELU6; + break; + case 4: + param.activation = Activation::TANH; + break; + case 6: + param.activation = Activation::SIGMOID; + break; + default: + throw std::runtime_error("Unsupported activation type"); + break; + } + param.cell_threshold = operands.at(OperandIndex{init_param.inputs[21]}).asScalar(); + param.projection_threshold = operands.at(OperandIndex{init_param.inputs[22]}).asScalar(); + + return new operation::LSTM{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_EQUAL] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::Equal; + + return new operation::Comparison{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_EQUAL_EX is deprecated + // TODO Remove ANEURALNETWORKS_EQUAL_EX + _map[ANEURALNETWORKS_EQUAL_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input0 Tensor Index + // 1 -> input1 Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + operation::Comparison::Param param; + param.comparison_type = operation::Comparison::ComparisonType::Equal; + + // Output operand type must be boolean + replaceDataType(operands, outputs.at(0), DataType::BOOL8); + + return new operation::Comparison{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_SQUARED_DIFFERENCE_EX] = [](const OperationFactory::Param &init_param, + Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> LHS Tensor Index + // 1 -> RHS Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + + return new operation::SquaredDifference{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_TOPK_V2] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 2); + + // Each output should be interpreted as follows: + // + // 0 -> Index for Output Values + // 1 -> Index for Output Indices + OperandIndexSequence outputs{init_param.outputs[0], init_param.outputs[1]}; + + // Each input should be interpreted as follows: + // + // 0 -> Index for Input Data + // 1 -> Index for K + OperandIndexSequence inputs{init_param.inputs[0]}; + + operation::TopKV2::Param param; + param.k = operands.at(OperandIndex{init_param.inputs[1]}).asScalar(); + + return new operation::TopKV2{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_CAST_EX is deprecated + // TODO Remove ANEURALNETWORKS_CAST_EX + _map[ANEURALNETWORKS_TOPK_V2_EX] = _map[ANEURALNETWORKS_TOPK_V2]; + + _map[ANEURALNETWORKS_GATHER] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + // 1 -> axis Index + // 2 -> indices Tensor Index + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[2]}; + + operation::Gather::Param param; + param.axis = operands.at(OperandIndex{init_param.inputs[1]}).asScalar(); + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::Gather{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_GATHER_EX is deprecated + // TODO Remove ANEURALNETWORKS_GATHER_EX + _map[ANEURALNETWORKS_GATHER_EX] = _map[ANEURALNETWORKS_GATHER]; + + _map[ANEURALNETWORKS_NEG] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::Neg{inputs, outputs}; + }; + + // ANEURALNETWORKS_NEG_EX is deprecated + // TODO Remove ANEURALNETWORKS_NEG_EX + _map[ANEURALNETWORKS_NEG_EX] = _map[ANEURALNETWORKS_NEG]; + + _map[ANEURALNETWORKS_ABS] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::Abs{inputs, outputs}; + }; + + // ANEURALNETWORKS_ABS_EX is deprecated + // TODO Remove ANEURALNETWORKS_ABS_EX + _map[ANEURALNETWORKS_ABS_EX] = _map[ANEURALNETWORKS_ABS]; + + _map[ANEURALNETWORKS_ARGMAX] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Axis Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + operation::ArgMax::Param param; + param.axis = operands.at(OperandIndex{init_param.inputs[1]}).asScalar(); + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::ArgMax{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_ARGMAX_EX is deprecated + // TODO Remove ANEURALNETWORKS_ARGMAX_EX + _map[ANEURALNETWORKS_ARGMAX_EX] = _map[ANEURALNETWORKS_ARGMAX]; + + _map[ANEURALNETWORKS_DEQUANTIZE] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + return new operation::Dequantize{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_MEAN] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> ifm Tensor Index + // 1 -> axis Tensor Index + // 2 -> keep_dims Index + OperandIndexSequence inputs{init_param.inputs[0]}; + std::vector axes = + operands.at(OperandIndex{init_param.inputs[1]}).asVector(); + + operation::Mean::Param param; + param.axes.assign(axes.cbegin(), axes.cend()); + param.keep_dims = operands.at(OperandIndex{init_param.inputs[2]}).asScalar() != 0; + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::Mean{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 5 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + OperandIndexSequence inputs{init_param.inputs[0]}; + + operation::LocalResponseNormalization::Param param; + param.radius = operands.at(OperandIndex{init_param.inputs[1]}).asScalar(); + param.bias = operands.at(OperandIndex{init_param.inputs[2]}).asScalar(); + param.alpha = operands.at(OperandIndex{init_param.inputs[3]}).asScalar(); + param.beta = operands.at(OperandIndex{init_param.inputs[4]}).asScalar(); + + return new operation::LocalResponseNormalization{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_DEPTH_TO_SPACE] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Block size Index + OperandIndexSequence inputs{init_param.inputs[0]}; + + operation::DepthToSpace::Param param; + param.block_size = operands.at(OperandIndex{init_param.inputs[1]}).asScalar(); + + return new operation::DepthToSpace{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_PACK_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count >= 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + OperandIndexSequence inputs; + for (uint32_t n = 0; n < init_param.input_count - 2; ++n) + { + inputs.append(OperandIndex{init_param.inputs[n]}); + } + + operation::Pack::Param param; + const auto num_index = OperandIndex{init_param.inputs[init_param.input_count - 2]}; + const auto axis_index = OperandIndex{init_param.inputs[init_param.input_count - 1]}; + param.num = operands.at(num_index).asScalar(); + param.axis = operands.at(axis_index).asScalar(); + param.rank = operands.at(outputs.at(0)).shape().rank(); + + return new operation::Pack{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_REDUCE_MIN] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 3 && init_param.output_count == 1); + + OperandIndexSequence outputs{init_param.outputs[0]}; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Axis Tensor Index + // 2 -> keep_dims Index + OperandIndexSequence inputs{init_param.inputs[0]}; + std::vector axes = + operands.at(OperandIndex{init_param.inputs[1]}).asVector(); + + operation::ReduceMin::Param param; + param.axes.assign(axes.cbegin(), axes.cend()); + param.keep_dims = operands.at(OperandIndex{init_param.inputs[2]}).asScalar() != 0; + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::ReduceMin{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_REDUCE_MIN_EX is deprecated + // TODO Remove ANEURALNETWORKS_REDUCE_MIN_EX + _map[ANEURALNETWORKS_REDUCE_MIN_EX] = _map[ANEURALNETWORKS_REDUCE_MIN]; + + _map[ANEURALNETWORKS_SPLIT] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 3); + assert(init_param.output_count >= 1); // At least one output tensor and axis + + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs; + for (uint32_t n = 0; n < init_param.output_count; ++n) + { + outputs.append(OperandIndex{init_param.outputs[n]}); + } + + operation::Split::Param param; + param.axis = operands.at(OperandIndex{init_param.inputs[1]}).asScalar(); + param.num_splits = operands.at(OperandIndex{init_param.inputs[2]}).asScalar(); + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::Split{inputs, outputs, param}; + }; + + // ANEURALNETWORKS_SPLIT_EX is deprecated + // TODO Remove ANEURALNETWORKS_SPLIT_EX + _map[ANEURALNETWORKS_SPLIT_EX] = _map[ANEURALNETWORKS_SPLIT]; + + _map[ANEURALNETWORKS_UNPACK_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 3 && init_param.output_count >= 1); + + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs; + for (uint32_t n = 0; n < init_param.output_count; ++n) + { + outputs.append(OperandIndex{init_param.outputs[n]}); + } + + operation::Unpack::Param param; + const auto num_index = OperandIndex{init_param.inputs[1]}; + const auto axis_index = OperandIndex{init_param.inputs[2]}; + param.num = operands.at(num_index).asScalar(); + param.axis = operands.at(axis_index).asScalar(); + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::Unpack{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_PAD] = [](const OperationFactory::Param &init_param, Operands &operands) { + assert(init_param.input_count == 2 && init_param.output_count >= 1); + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + operation::Pad::Param param; + param.rank = operands.at(inputs.at(0)).shape().rank(); + + return new operation::Pad{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_MINIMUM] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + return new operation::Min{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_MAXIMUM] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 2 && init_param.output_count == 1); + + OperandIndexSequence inputs{init_param.inputs[0], init_param.inputs[1]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + return new operation::Max{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_ONE_HOT_EX] = [](const OperationFactory::Param &init_param, + Operands &operands) { + assert(init_param.input_count == 5); + assert(init_param.output_count == 1); + // Each input should be interpreted as follows: + // + // 0 -> indices tensor + // 1 -> depth scalar + // 2 -> on_value scalar + // 3 -> off_value scalar + // 4 -> axis scalar + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + operation::OneHot::Param param; + param.depth = operands.at(OperandIndex{init_param.inputs[1]}).asScalar(); + param.on_value = operands.at(OperandIndex{init_param.inputs[2]}).asScalar(); + param.off_value = operands.at(OperandIndex{init_param.inputs[3]}).asScalar(); + param.axis = operands.at(OperandIndex{init_param.inputs[4]}).asScalar(); + + return new operation::OneHot{inputs, outputs, param}; + }; + + _map[ANEURALNETWORKS_SIN] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + return new operation::Sin{inputs, outputs}; + }; + + _map[ANEURALNETWORKS_SHAPE_EX] = [](const OperationFactory::Param &init_param, Operands &) { + assert(init_param.input_count == 1 && init_param.output_count == 1); + + OperandIndexSequence inputs{init_param.inputs[0]}; + OperandIndexSequence outputs{init_param.outputs[0]}; + + return new operation::Shape{inputs, outputs}; + }; +} + +Operation *OperationFactory::create(ANeuralNetworksOperationType type, + const OperationFactory::Param ¶m, Operands &operands) +{ + auto it = _map.find(type); + if (it == _map.end()) + { + throw std::runtime_error("Unsupported operation type: " + std::to_string(type)); + } + return it->second(param, operands); +} diff --git a/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h new file mode 100644 index 000000000..367cf74db --- /dev/null +++ b/runtime/onert/frontend/nnapi/wrapper/OperationFactory.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __OPERATION_FACTORY_H__ +#define __OPERATION_FACTORY_H__ + +#include + +#include "ir/Operands.h" +#include "ir/Operation.h" +#include "NeuralNetworks.h" +#include "NeuralNetworksEx.h" + +/** + * @brief A class to create a onert operation object from NN API input parameters + */ +class OperationFactory +{ +public: + struct Param + { + uint32_t input_count; + const uint32_t *inputs; + uint32_t output_count; + const uint32_t *outputs; + }; + +public: + using Generator = + std::function; + +public: + static OperationFactory &get(); + +private: + OperationFactory(); + +public: + onert::ir::Operation *create(ANeuralNetworksOperationType, const OperationFactory::Param ¶m, + onert::ir::Operands &operands); + // TODO add "register" method for separating registration, possibly supporting custom-ops + +private: + std::unordered_map _map; +}; + +#endif // __OPERATION_FACTORY_H__ diff --git a/runtime/onert/frontend/tflite/CMakeLists.txt b/runtime/onert/frontend/tflite/CMakeLists.txt new file mode 100644 index 000000000..229f04f32 --- /dev/null +++ b/runtime/onert/frontend/tflite/CMakeLists.txt @@ -0,0 +1,17 @@ +if(NOT BUILD_TFLITE_LOADER) + return() +endif(NOT BUILD_TFLITE_LOADER) + +nnfw_find_package(FlatBuffersSource REQUIRED) + +set(TFLITE_LOADER_SOURCES src/tflite_loader.cc) + +add_library(tflite_loader SHARED ${TFLITE_LOADER_SOURCES}) + +target_include_directories(tflite_loader PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_include_directories(tflite_loader PRIVATE ${FlatBuffersSource_DIR}/include) + +target_link_libraries(tflite_loader PUBLIC onert_core) +target_link_libraries(tflite_loader PRIVATE base_loader nnfw_common nnfw_coverage) + +install(TARGETS tflite_loader DESTINATION lib) diff --git a/runtime/onert/frontend/tflite/include/tflite_loader.h b/runtime/onert/frontend/tflite/include/tflite_loader.h new file mode 100644 index 000000000..d1816d47a --- /dev/null +++ b/runtime/onert/frontend/tflite/include/tflite_loader.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TFLITE_TFLITE_LOADER_H__ +#define __TFLITE_TFLITE_LOADER_H__ + +#include "ir/Graph.h" + +#include + +namespace onert +{ +namespace tflite_loader +{ + +std::unique_ptr loadModel(const char *filename); + +} // namespace tflite_loader +} // namespace onert + +#endif // __TFLITE_TFLITE_LOADER_H__ diff --git a/runtime/onert/frontend/tflite/src/tflite_loader.cc b/runtime/onert/frontend/tflite/src/tflite_loader.cc new file mode 100644 index 000000000..7ede4441a --- /dev/null +++ b/runtime/onert/frontend/tflite/src/tflite_loader.cc @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "tflite_loader.h" +#include "base_loader.h" +#include "tflite_schema_generated.h" + +namespace onert +{ +namespace tflite_loader +{ + +namespace +{ + +struct LoaderDomain +{ + using Verifier = flatbuffers::Verifier; + using ActivationFunctionType = onert_tflite::ActivationFunctionType; + using Buffer = onert_tflite::Buffer; + using BuiltinOperator = onert_tflite::BuiltinOperator; + using CustomOptionsFormat = onert_tflite::CustomOptionsFormat; + using Model = onert_tflite::Model; + using Operator = onert_tflite::Operator; + using Padding = onert_tflite::Padding; + using Pool2DOptions = onert_tflite::Pool2DOptions; + using Tensor = onert_tflite::Tensor; + using TensorType = onert_tflite::TensorType; + using SubGraph = onert_tflite::SubGraph; + + static const char *EnumNameBuiltinOperator(BuiltinOperator e) + { + return onert_tflite::EnumNameBuiltinOperator(e); + } + static const char *EnumNameActivationFunctionType(ActivationFunctionType e) + { + return onert_tflite::EnumNameActivationFunctionType(e); + } + static const char *EnumNameTensorType(TensorType e) + { + return onert_tflite::EnumNameTensorType(e); + } + static const Model *GetModel(const void *buf) { return onert_tflite::GetModel(buf); } + static bool VerifyModelBuffer(Verifier &verifier) + { + return onert_tflite::VerifyModelBuffer(verifier); + } +}; + +class TFLiteLoader final : public base_loader::BaseLoader +{ +public: + using BaseLoader::BaseLoader; + + std::unique_ptr loadSubgraph(const onert_tflite::SubGraph *tflite_subg) + { + auto subg = std::make_unique(); + // Load tensors + _tensor_to_operand.resize(tflite_subg->tensors()->size()); + for (flatbuffers::uoffset_t i = 0; i < tflite_subg->tensors()->size(); ++i) + { + _tensor_to_operand[i] = loadOperand(tflite_subg->tensors()->Get(i), *subg); + } + // Set inputs + for (const std::int32_t input_ind : *tflite_subg->inputs()) + { + subg->addInput(_tensor_to_operand[input_ind]); + } + // Set outputs + for (const std::int32_t output_ind : *tflite_subg->outputs()) + { + subg->addOutput(_tensor_to_operand[output_ind]); + } + // Create operations + for (const auto *op : *tflite_subg->operators()) + { + loadOperation(op, *subg); + } + + subg->finishBuilding(); + + return subg; + } +}; + +} // namespace + +std::unique_ptr loadModel(const char *filename) +{ + auto primary_subgraph = std::make_unique(); + TFLiteLoader loader(primary_subgraph); + loader.loadFromFile(filename); + return primary_subgraph; +} + +} // namespace tflite_loader +} // namespace onert diff --git a/runtime/onert/frontend/tflite/src/tflite_schema_generated.h b/runtime/onert/frontend/tflite/src/tflite_schema_generated.h new file mode 100644 index 000000000..c6e9147cd --- /dev/null +++ b/runtime/onert/frontend/tflite/src/tflite_schema_generated.h @@ -0,0 +1,9553 @@ +/* + * Copyright (c) 2019-2020 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2018 The TensorFlow Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// automatically generated by the FlatBuffers compiler, do not modify + +#ifndef FLATBUFFERS_GENERATED_TFLITESCHEMA_ONERT_TFLITE_H_ +#define FLATBUFFERS_GENERATED_TFLITESCHEMA_ONERT_TFLITE_H_ + +#include "flatbuffers/flatbuffers.h" + +namespace onert_tflite +{ + +struct CustomQuantization; + +struct QuantizationParameters; + +struct Int32Vector; + +struct Uint16Vector; + +struct Uint8Vector; + +struct DimensionMetadata; + +struct SparsityParameters; + +struct Tensor; + +struct Conv2DOptions; + +struct Pool2DOptions; + +struct DepthwiseConv2DOptions; + +struct ConcatEmbeddingsOptions; + +struct LSHProjectionOptions; + +struct SVDFOptions; + +struct RNNOptions; + +struct SequenceRNNOptions; + +struct BidirectionalSequenceRNNOptions; + +struct FullyConnectedOptions; + +struct SoftmaxOptions; + +struct ConcatenationOptions; + +struct AddOptions; + +struct MulOptions; + +struct L2NormOptions; + +struct LocalResponseNormalizationOptions; + +struct LSTMOptions; + +struct UnidirectionalSequenceLSTMOptions; + +struct BidirectionalSequenceLSTMOptions; + +struct ResizeBilinearOptions; + +struct ResizeNearestNeighborOptions; + +struct CallOptions; + +struct PadOptions; + +struct PadV2Options; + +struct ReshapeOptions; + +struct SpaceToBatchNDOptions; + +struct BatchToSpaceNDOptions; + +struct SkipGramOptions; + +struct SpaceToDepthOptions; + +struct DepthToSpaceOptions; + +struct SubOptions; + +struct DivOptions; + +struct TopKV2Options; + +struct EmbeddingLookupSparseOptions; + +struct GatherOptions; + +struct TransposeOptions; + +struct ExpOptions; + +struct CosOptions; + +struct ReducerOptions; + +struct SqueezeOptions; + +struct SplitOptions; + +struct SplitVOptions; + +struct StridedSliceOptions; + +struct LogSoftmaxOptions; + +struct CastOptions; + +struct DequantizeOptions; + +struct MaximumMinimumOptions; + +struct TileOptions; + +struct ArgMaxOptions; + +struct ArgMinOptions; + +struct GreaterOptions; + +struct GreaterEqualOptions; + +struct LessOptions; + +struct LessEqualOptions; + +struct NegOptions; + +struct SelectOptions; + +struct SliceOptions; + +struct TransposeConvOptions; + +struct ExpandDimsOptions; + +struct SparseToDenseOptions; + +struct EqualOptions; + +struct NotEqualOptions; + +struct ShapeOptions; + +struct RankOptions; + +struct PowOptions; + +struct FakeQuantOptions; + +struct PackOptions; + +struct LogicalOrOptions; + +struct OneHotOptions; + +struct AbsOptions; + +struct HardSwishOptions; + +struct LogicalAndOptions; + +struct LogicalNotOptions; + +struct UnpackOptions; + +struct FloorDivOptions; + +struct SquareOptions; + +struct ZerosLikeOptions; + +struct FillOptions; + +struct FloorModOptions; + +struct RangeOptions; + +struct LeakyReluOptions; + +struct SquaredDifferenceOptions; + +struct MirrorPadOptions; + +struct UniqueOptions; + +struct ReverseV2Options; + +struct AddNOptions; + +struct GatherNdOptions; + +struct WhereOptions; + +struct ReverseSequenceOptions; + +struct MatrixDiagOptions; + +struct QuantizeOptions; + +struct MatrixSetDiagOptions; + +struct IfOptions; + +struct WhileOptions; + +struct NonMaxSuppressionV4Options; + +struct NonMaxSuppressionV5Options; + +struct ScatterNdOptions; + +struct SelectV2Options; + +struct DensifyOptions; + +struct SegmentSumOptions; + +struct BatchMatMulOptions; + +struct OperatorCode; + +struct Operator; + +struct SubGraph; + +struct Buffer; + +struct Metadata; + +struct Model; + +enum TensorType +{ + TensorType_FLOAT32 = 0, + TensorType_FLOAT16 = 1, + TensorType_INT32 = 2, + TensorType_UINT8 = 3, + TensorType_INT64 = 4, + TensorType_STRING = 5, + TensorType_BOOL = 6, + TensorType_INT16 = 7, + TensorType_COMPLEX64 = 8, + TensorType_INT8 = 9, + TensorType_FLOAT64 = 10, + TensorType_MIN = TensorType_FLOAT32, + TensorType_MAX = TensorType_FLOAT64 +}; + +inline const TensorType (&EnumValuesTensorType())[11] +{ + static const TensorType values[] = {TensorType_FLOAT32, TensorType_FLOAT16, TensorType_INT32, + TensorType_UINT8, TensorType_INT64, TensorType_STRING, + TensorType_BOOL, TensorType_INT16, TensorType_COMPLEX64, + TensorType_INT8, TensorType_FLOAT64}; + return values; +} + +inline const char *const *EnumNamesTensorType() +{ + static const char *const names[] = {"FLOAT32", "FLOAT16", "INT32", "UINT8", + "INT64", "STRING", "BOOL", "INT16", + "COMPLEX64", "INT8", "FLOAT64", nullptr}; + return names; +} + +inline const char *EnumNameTensorType(TensorType e) +{ + const size_t index = static_cast(e); + return EnumNamesTensorType()[index]; +} + +enum QuantizationDetails +{ + QuantizationDetails_NONE = 0, + QuantizationDetails_CustomQuantization = 1, + QuantizationDetails_MIN = QuantizationDetails_NONE, + QuantizationDetails_MAX = QuantizationDetails_CustomQuantization +}; + +inline const QuantizationDetails (&EnumValuesQuantizationDetails())[2] +{ + static const QuantizationDetails values[] = {QuantizationDetails_NONE, + QuantizationDetails_CustomQuantization}; + return values; +} + +inline const char *const *EnumNamesQuantizationDetails() +{ + static const char *const names[] = {"NONE", "CustomQuantization", nullptr}; + return names; +} + +inline const char *EnumNameQuantizationDetails(QuantizationDetails e) +{ + const size_t index = static_cast(e); + return EnumNamesQuantizationDetails()[index]; +} + +template struct QuantizationDetailsTraits +{ + static const QuantizationDetails enum_value = QuantizationDetails_NONE; +}; + +template <> struct QuantizationDetailsTraits +{ + static const QuantizationDetails enum_value = QuantizationDetails_CustomQuantization; +}; + +bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj, + QuantizationDetails type); +bool VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types); + +enum DimensionType +{ + DimensionType_DENSE = 0, + DimensionType_SPARSE_CSR = 1, + DimensionType_MIN = DimensionType_DENSE, + DimensionType_MAX = DimensionType_SPARSE_CSR +}; + +inline const DimensionType (&EnumValuesDimensionType())[2] +{ + static const DimensionType values[] = {DimensionType_DENSE, DimensionType_SPARSE_CSR}; + return values; +} + +inline const char *const *EnumNamesDimensionType() +{ + static const char *const names[] = {"DENSE", "SPARSE_CSR", nullptr}; + return names; +} + +inline const char *EnumNameDimensionType(DimensionType e) +{ + const size_t index = static_cast(e); + return EnumNamesDimensionType()[index]; +} + +enum SparseIndexVector +{ + SparseIndexVector_NONE = 0, + SparseIndexVector_Int32Vector = 1, + SparseIndexVector_Uint16Vector = 2, + SparseIndexVector_Uint8Vector = 3, + SparseIndexVector_MIN = SparseIndexVector_NONE, + SparseIndexVector_MAX = SparseIndexVector_Uint8Vector +}; + +inline const SparseIndexVector (&EnumValuesSparseIndexVector())[4] +{ + static const SparseIndexVector values[] = {SparseIndexVector_NONE, SparseIndexVector_Int32Vector, + SparseIndexVector_Uint16Vector, + SparseIndexVector_Uint8Vector}; + return values; +} + +inline const char *const *EnumNamesSparseIndexVector() +{ + static const char *const names[] = {"NONE", "Int32Vector", "Uint16Vector", "Uint8Vector", + nullptr}; + return names; +} + +inline const char *EnumNameSparseIndexVector(SparseIndexVector e) +{ + const size_t index = static_cast(e); + return EnumNamesSparseIndexVector()[index]; +} + +template struct SparseIndexVectorTraits +{ + static const SparseIndexVector enum_value = SparseIndexVector_NONE; +}; + +template <> struct SparseIndexVectorTraits +{ + static const SparseIndexVector enum_value = SparseIndexVector_Int32Vector; +}; + +template <> struct SparseIndexVectorTraits +{ + static const SparseIndexVector enum_value = SparseIndexVector_Uint16Vector; +}; + +template <> struct SparseIndexVectorTraits +{ + static const SparseIndexVector enum_value = SparseIndexVector_Uint8Vector; +}; + +bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj, + SparseIndexVector type); +bool VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types); + +enum BuiltinOperator +{ + BuiltinOperator_ADD = 0, + BuiltinOperator_AVERAGE_POOL_2D = 1, + BuiltinOperator_CONCATENATION = 2, + BuiltinOperator_CONV_2D = 3, + BuiltinOperator_DEPTHWISE_CONV_2D = 4, + BuiltinOperator_DEPTH_TO_SPACE = 5, + BuiltinOperator_DEQUANTIZE = 6, + BuiltinOperator_EMBEDDING_LOOKUP = 7, + BuiltinOperator_FLOOR = 8, + BuiltinOperator_FULLY_CONNECTED = 9, + BuiltinOperator_HASHTABLE_LOOKUP = 10, + BuiltinOperator_L2_NORMALIZATION = 11, + BuiltinOperator_L2_POOL_2D = 12, + BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION = 13, + BuiltinOperator_LOGISTIC = 14, + BuiltinOperator_LSH_PROJECTION = 15, + BuiltinOperator_LSTM = 16, + BuiltinOperator_MAX_POOL_2D = 17, + BuiltinOperator_MUL = 18, + BuiltinOperator_RELU = 19, + BuiltinOperator_RELU_N1_TO_1 = 20, + BuiltinOperator_RELU6 = 21, + BuiltinOperator_RESHAPE = 22, + BuiltinOperator_RESIZE_BILINEAR = 23, + BuiltinOperator_RNN = 24, + BuiltinOperator_SOFTMAX = 25, + BuiltinOperator_SPACE_TO_DEPTH = 26, + BuiltinOperator_SVDF = 27, + BuiltinOperator_TANH = 28, + BuiltinOperator_CONCAT_EMBEDDINGS = 29, + BuiltinOperator_SKIP_GRAM = 30, + BuiltinOperator_CALL = 31, + BuiltinOperator_CUSTOM = 32, + BuiltinOperator_EMBEDDING_LOOKUP_SPARSE = 33, + BuiltinOperator_PAD = 34, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN = 35, + BuiltinOperator_GATHER = 36, + BuiltinOperator_BATCH_TO_SPACE_ND = 37, + BuiltinOperator_SPACE_TO_BATCH_ND = 38, + BuiltinOperator_TRANSPOSE = 39, + BuiltinOperator_MEAN = 40, + BuiltinOperator_SUB = 41, + BuiltinOperator_DIV = 42, + BuiltinOperator_SQUEEZE = 43, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + BuiltinOperator_STRIDED_SLICE = 45, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN = 46, + BuiltinOperator_EXP = 47, + BuiltinOperator_TOPK_V2 = 48, + BuiltinOperator_SPLIT = 49, + BuiltinOperator_LOG_SOFTMAX = 50, + BuiltinOperator_DELEGATE = 51, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM = 52, + BuiltinOperator_CAST = 53, + BuiltinOperator_PRELU = 54, + BuiltinOperator_MAXIMUM = 55, + BuiltinOperator_ARG_MAX = 56, + BuiltinOperator_MINIMUM = 57, + BuiltinOperator_LESS = 58, + BuiltinOperator_NEG = 59, + BuiltinOperator_PADV2 = 60, + BuiltinOperator_GREATER = 61, + BuiltinOperator_GREATER_EQUAL = 62, + BuiltinOperator_LESS_EQUAL = 63, + BuiltinOperator_SELECT = 64, + BuiltinOperator_SLICE = 65, + BuiltinOperator_SIN = 66, + BuiltinOperator_TRANSPOSE_CONV = 67, + BuiltinOperator_SPARSE_TO_DENSE = 68, + BuiltinOperator_TILE = 69, + BuiltinOperator_EXPAND_DIMS = 70, + BuiltinOperator_EQUAL = 71, + BuiltinOperator_NOT_EQUAL = 72, + BuiltinOperator_LOG = 73, + BuiltinOperator_SUM = 74, + BuiltinOperator_SQRT = 75, + BuiltinOperator_RSQRT = 76, + BuiltinOperator_SHAPE = 77, + BuiltinOperator_POW = 78, + BuiltinOperator_ARG_MIN = 79, + BuiltinOperator_FAKE_QUANT = 80, + BuiltinOperator_REDUCE_PROD = 81, + BuiltinOperator_REDUCE_MAX = 82, + BuiltinOperator_PACK = 83, + BuiltinOperator_LOGICAL_OR = 84, + BuiltinOperator_ONE_HOT = 85, + BuiltinOperator_LOGICAL_AND = 86, + BuiltinOperator_LOGICAL_NOT = 87, + BuiltinOperator_UNPACK = 88, + BuiltinOperator_REDUCE_MIN = 89, + BuiltinOperator_FLOOR_DIV = 90, + BuiltinOperator_REDUCE_ANY = 91, + BuiltinOperator_SQUARE = 92, + BuiltinOperator_ZEROS_LIKE = 93, + BuiltinOperator_FILL = 94, + BuiltinOperator_FLOOR_MOD = 95, + BuiltinOperator_RANGE = 96, + BuiltinOperator_RESIZE_NEAREST_NEIGHBOR = 97, + BuiltinOperator_LEAKY_RELU = 98, + BuiltinOperator_SQUARED_DIFFERENCE = 99, + BuiltinOperator_MIRROR_PAD = 100, + BuiltinOperator_ABS = 101, + BuiltinOperator_SPLIT_V = 102, + BuiltinOperator_UNIQUE = 103, + BuiltinOperator_CEIL = 104, + BuiltinOperator_REVERSE_V2 = 105, + BuiltinOperator_ADD_N = 106, + BuiltinOperator_GATHER_ND = 107, + BuiltinOperator_COS = 108, + BuiltinOperator_WHERE = 109, + BuiltinOperator_RANK = 110, + BuiltinOperator_ELU = 111, + BuiltinOperator_REVERSE_SEQUENCE = 112, + BuiltinOperator_MATRIX_DIAG = 113, + BuiltinOperator_QUANTIZE = 114, + BuiltinOperator_MATRIX_SET_DIAG = 115, + BuiltinOperator_ROUND = 116, + BuiltinOperator_HARD_SWISH = 117, + BuiltinOperator_IF = 118, + BuiltinOperator_WHILE = 119, + BuiltinOperator_NON_MAX_SUPPRESSION_V4 = 120, + BuiltinOperator_NON_MAX_SUPPRESSION_V5 = 121, + BuiltinOperator_SCATTER_ND = 122, + BuiltinOperator_SELECT_V2 = 123, + BuiltinOperator_DENSIFY = 124, + BuiltinOperator_SEGMENT_SUM = 125, + BuiltinOperator_BATCH_MATMUL = 126, + BuiltinOperator_MIN = BuiltinOperator_ADD, + BuiltinOperator_MAX = BuiltinOperator_BATCH_MATMUL +}; + +inline const BuiltinOperator (&EnumValuesBuiltinOperator())[127] +{ + static const BuiltinOperator values[] = {BuiltinOperator_ADD, + BuiltinOperator_AVERAGE_POOL_2D, + BuiltinOperator_CONCATENATION, + BuiltinOperator_CONV_2D, + BuiltinOperator_DEPTHWISE_CONV_2D, + BuiltinOperator_DEPTH_TO_SPACE, + BuiltinOperator_DEQUANTIZE, + BuiltinOperator_EMBEDDING_LOOKUP, + BuiltinOperator_FLOOR, + BuiltinOperator_FULLY_CONNECTED, + BuiltinOperator_HASHTABLE_LOOKUP, + BuiltinOperator_L2_NORMALIZATION, + BuiltinOperator_L2_POOL_2D, + BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION, + BuiltinOperator_LOGISTIC, + BuiltinOperator_LSH_PROJECTION, + BuiltinOperator_LSTM, + BuiltinOperator_MAX_POOL_2D, + BuiltinOperator_MUL, + BuiltinOperator_RELU, + BuiltinOperator_RELU_N1_TO_1, + BuiltinOperator_RELU6, + BuiltinOperator_RESHAPE, + BuiltinOperator_RESIZE_BILINEAR, + BuiltinOperator_RNN, + BuiltinOperator_SOFTMAX, + BuiltinOperator_SPACE_TO_DEPTH, + BuiltinOperator_SVDF, + BuiltinOperator_TANH, + BuiltinOperator_CONCAT_EMBEDDINGS, + BuiltinOperator_SKIP_GRAM, + BuiltinOperator_CALL, + BuiltinOperator_CUSTOM, + BuiltinOperator_EMBEDDING_LOOKUP_SPARSE, + BuiltinOperator_PAD, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN, + BuiltinOperator_GATHER, + BuiltinOperator_BATCH_TO_SPACE_ND, + BuiltinOperator_SPACE_TO_BATCH_ND, + BuiltinOperator_TRANSPOSE, + BuiltinOperator_MEAN, + BuiltinOperator_SUB, + BuiltinOperator_DIV, + BuiltinOperator_SQUEEZE, + BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM, + BuiltinOperator_STRIDED_SLICE, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN, + BuiltinOperator_EXP, + BuiltinOperator_TOPK_V2, + BuiltinOperator_SPLIT, + BuiltinOperator_LOG_SOFTMAX, + BuiltinOperator_DELEGATE, + BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM, + BuiltinOperator_CAST, + BuiltinOperator_PRELU, + BuiltinOperator_MAXIMUM, + BuiltinOperator_ARG_MAX, + BuiltinOperator_MINIMUM, + BuiltinOperator_LESS, + BuiltinOperator_NEG, + BuiltinOperator_PADV2, + BuiltinOperator_GREATER, + BuiltinOperator_GREATER_EQUAL, + BuiltinOperator_LESS_EQUAL, + BuiltinOperator_SELECT, + BuiltinOperator_SLICE, + BuiltinOperator_SIN, + BuiltinOperator_TRANSPOSE_CONV, + BuiltinOperator_SPARSE_TO_DENSE, + BuiltinOperator_TILE, + BuiltinOperator_EXPAND_DIMS, + BuiltinOperator_EQUAL, + BuiltinOperator_NOT_EQUAL, + BuiltinOperator_LOG, + BuiltinOperator_SUM, + BuiltinOperator_SQRT, + BuiltinOperator_RSQRT, + BuiltinOperator_SHAPE, + BuiltinOperator_POW, + BuiltinOperator_ARG_MIN, + BuiltinOperator_FAKE_QUANT, + BuiltinOperator_REDUCE_PROD, + BuiltinOperator_REDUCE_MAX, + BuiltinOperator_PACK, + BuiltinOperator_LOGICAL_OR, + BuiltinOperator_ONE_HOT, + BuiltinOperator_LOGICAL_AND, + BuiltinOperator_LOGICAL_NOT, + BuiltinOperator_UNPACK, + BuiltinOperator_REDUCE_MIN, + BuiltinOperator_FLOOR_DIV, + BuiltinOperator_REDUCE_ANY, + BuiltinOperator_SQUARE, + BuiltinOperator_ZEROS_LIKE, + BuiltinOperator_FILL, + BuiltinOperator_FLOOR_MOD, + BuiltinOperator_RANGE, + BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, + BuiltinOperator_LEAKY_RELU, + BuiltinOperator_SQUARED_DIFFERENCE, + BuiltinOperator_MIRROR_PAD, + BuiltinOperator_ABS, + BuiltinOperator_SPLIT_V, + BuiltinOperator_UNIQUE, + BuiltinOperator_CEIL, + BuiltinOperator_REVERSE_V2, + BuiltinOperator_ADD_N, + BuiltinOperator_GATHER_ND, + BuiltinOperator_COS, + BuiltinOperator_WHERE, + BuiltinOperator_RANK, + BuiltinOperator_ELU, + BuiltinOperator_REVERSE_SEQUENCE, + BuiltinOperator_MATRIX_DIAG, + BuiltinOperator_QUANTIZE, + BuiltinOperator_MATRIX_SET_DIAG, + BuiltinOperator_ROUND, + BuiltinOperator_HARD_SWISH, + BuiltinOperator_IF, + BuiltinOperator_WHILE, + BuiltinOperator_NON_MAX_SUPPRESSION_V4, + BuiltinOperator_NON_MAX_SUPPRESSION_V5, + BuiltinOperator_SCATTER_ND, + BuiltinOperator_SELECT_V2, + BuiltinOperator_DENSIFY, + BuiltinOperator_SEGMENT_SUM, + BuiltinOperator_BATCH_MATMUL}; + return values; +} + +inline const char *const *EnumNamesBuiltinOperator() +{ + static const char *const names[] = {"ADD", + "AVERAGE_POOL_2D", + "CONCATENATION", + "CONV_2D", + "DEPTHWISE_CONV_2D", + "DEPTH_TO_SPACE", + "DEQUANTIZE", + "EMBEDDING_LOOKUP", + "FLOOR", + "FULLY_CONNECTED", + "HASHTABLE_LOOKUP", + "L2_NORMALIZATION", + "L2_POOL_2D", + "LOCAL_RESPONSE_NORMALIZATION", + "LOGISTIC", + "LSH_PROJECTION", + "LSTM", + "MAX_POOL_2D", + "MUL", + "RELU", + "RELU_N1_TO_1", + "RELU6", + "RESHAPE", + "RESIZE_BILINEAR", + "RNN", + "SOFTMAX", + "SPACE_TO_DEPTH", + "SVDF", + "TANH", + "CONCAT_EMBEDDINGS", + "SKIP_GRAM", + "CALL", + "CUSTOM", + "EMBEDDING_LOOKUP_SPARSE", + "PAD", + "UNIDIRECTIONAL_SEQUENCE_RNN", + "GATHER", + "BATCH_TO_SPACE_ND", + "SPACE_TO_BATCH_ND", + "TRANSPOSE", + "MEAN", + "SUB", + "DIV", + "SQUEEZE", + "UNIDIRECTIONAL_SEQUENCE_LSTM", + "STRIDED_SLICE", + "BIDIRECTIONAL_SEQUENCE_RNN", + "EXP", + "TOPK_V2", + "SPLIT", + "LOG_SOFTMAX", + "DELEGATE", + "BIDIRECTIONAL_SEQUENCE_LSTM", + "CAST", + "PRELU", + "MAXIMUM", + "ARG_MAX", + "MINIMUM", + "LESS", + "NEG", + "PADV2", + "GREATER", + "GREATER_EQUAL", + "LESS_EQUAL", + "SELECT", + "SLICE", + "SIN", + "TRANSPOSE_CONV", + "SPARSE_TO_DENSE", + "TILE", + "EXPAND_DIMS", + "EQUAL", + "NOT_EQUAL", + "LOG", + "SUM", + "SQRT", + "RSQRT", + "SHAPE", + "POW", + "ARG_MIN", + "FAKE_QUANT", + "REDUCE_PROD", + "REDUCE_MAX", + "PACK", + "LOGICAL_OR", + "ONE_HOT", + "LOGICAL_AND", + "LOGICAL_NOT", + "UNPACK", + "REDUCE_MIN", + "FLOOR_DIV", + "REDUCE_ANY", + "SQUARE", + "ZEROS_LIKE", + "FILL", + "FLOOR_MOD", + "RANGE", + "RESIZE_NEAREST_NEIGHBOR", + "LEAKY_RELU", + "SQUARED_DIFFERENCE", + "MIRROR_PAD", + "ABS", + "SPLIT_V", + "UNIQUE", + "CEIL", + "REVERSE_V2", + "ADD_N", + "GATHER_ND", + "COS", + "WHERE", + "RANK", + "ELU", + "REVERSE_SEQUENCE", + "MATRIX_DIAG", + "QUANTIZE", + "MATRIX_SET_DIAG", + "ROUND", + "HARD_SWISH", + "IF", + "WHILE", + "NON_MAX_SUPPRESSION_V4", + "NON_MAX_SUPPRESSION_V5", + "SCATTER_ND", + "SELECT_V2", + "DENSIFY", + "SEGMENT_SUM", + "BATCH_MATMUL", + nullptr}; + return names; +} + +inline const char *EnumNameBuiltinOperator(BuiltinOperator e) +{ + const size_t index = static_cast(e); + return EnumNamesBuiltinOperator()[index]; +} + +enum BuiltinOptions +{ + BuiltinOptions_NONE = 0, + BuiltinOptions_Conv2DOptions = 1, + BuiltinOptions_DepthwiseConv2DOptions = 2, + BuiltinOptions_ConcatEmbeddingsOptions = 3, + BuiltinOptions_LSHProjectionOptions = 4, + BuiltinOptions_Pool2DOptions = 5, + BuiltinOptions_SVDFOptions = 6, + BuiltinOptions_RNNOptions = 7, + BuiltinOptions_FullyConnectedOptions = 8, + BuiltinOptions_SoftmaxOptions = 9, + BuiltinOptions_ConcatenationOptions = 10, + BuiltinOptions_AddOptions = 11, + BuiltinOptions_L2NormOptions = 12, + BuiltinOptions_LocalResponseNormalizationOptions = 13, + BuiltinOptions_LSTMOptions = 14, + BuiltinOptions_ResizeBilinearOptions = 15, + BuiltinOptions_CallOptions = 16, + BuiltinOptions_ReshapeOptions = 17, + BuiltinOptions_SkipGramOptions = 18, + BuiltinOptions_SpaceToDepthOptions = 19, + BuiltinOptions_EmbeddingLookupSparseOptions = 20, + BuiltinOptions_MulOptions = 21, + BuiltinOptions_PadOptions = 22, + BuiltinOptions_GatherOptions = 23, + BuiltinOptions_BatchToSpaceNDOptions = 24, + BuiltinOptions_SpaceToBatchNDOptions = 25, + BuiltinOptions_TransposeOptions = 26, + BuiltinOptions_ReducerOptions = 27, + BuiltinOptions_SubOptions = 28, + BuiltinOptions_DivOptions = 29, + BuiltinOptions_SqueezeOptions = 30, + BuiltinOptions_SequenceRNNOptions = 31, + BuiltinOptions_StridedSliceOptions = 32, + BuiltinOptions_ExpOptions = 33, + BuiltinOptions_TopKV2Options = 34, + BuiltinOptions_SplitOptions = 35, + BuiltinOptions_LogSoftmaxOptions = 36, + BuiltinOptions_CastOptions = 37, + BuiltinOptions_DequantizeOptions = 38, + BuiltinOptions_MaximumMinimumOptions = 39, + BuiltinOptions_ArgMaxOptions = 40, + BuiltinOptions_LessOptions = 41, + BuiltinOptions_NegOptions = 42, + BuiltinOptions_PadV2Options = 43, + BuiltinOptions_GreaterOptions = 44, + BuiltinOptions_GreaterEqualOptions = 45, + BuiltinOptions_LessEqualOptions = 46, + BuiltinOptions_SelectOptions = 47, + BuiltinOptions_SliceOptions = 48, + BuiltinOptions_TransposeConvOptions = 49, + BuiltinOptions_SparseToDenseOptions = 50, + BuiltinOptions_TileOptions = 51, + BuiltinOptions_ExpandDimsOptions = 52, + BuiltinOptions_EqualOptions = 53, + BuiltinOptions_NotEqualOptions = 54, + BuiltinOptions_ShapeOptions = 55, + BuiltinOptions_PowOptions = 56, + BuiltinOptions_ArgMinOptions = 57, + BuiltinOptions_FakeQuantOptions = 58, + BuiltinOptions_PackOptions = 59, + BuiltinOptions_LogicalOrOptions = 60, + BuiltinOptions_OneHotOptions = 61, + BuiltinOptions_LogicalAndOptions = 62, + BuiltinOptions_LogicalNotOptions = 63, + BuiltinOptions_UnpackOptions = 64, + BuiltinOptions_FloorDivOptions = 65, + BuiltinOptions_SquareOptions = 66, + BuiltinOptions_ZerosLikeOptions = 67, + BuiltinOptions_FillOptions = 68, + BuiltinOptions_BidirectionalSequenceLSTMOptions = 69, + BuiltinOptions_BidirectionalSequenceRNNOptions = 70, + BuiltinOptions_UnidirectionalSequenceLSTMOptions = 71, + BuiltinOptions_FloorModOptions = 72, + BuiltinOptions_RangeOptions = 73, + BuiltinOptions_ResizeNearestNeighborOptions = 74, + BuiltinOptions_LeakyReluOptions = 75, + BuiltinOptions_SquaredDifferenceOptions = 76, + BuiltinOptions_MirrorPadOptions = 77, + BuiltinOptions_AbsOptions = 78, + BuiltinOptions_SplitVOptions = 79, + BuiltinOptions_UniqueOptions = 80, + BuiltinOptions_ReverseV2Options = 81, + BuiltinOptions_AddNOptions = 82, + BuiltinOptions_GatherNdOptions = 83, + BuiltinOptions_CosOptions = 84, + BuiltinOptions_WhereOptions = 85, + BuiltinOptions_RankOptions = 86, + BuiltinOptions_ReverseSequenceOptions = 87, + BuiltinOptions_MatrixDiagOptions = 88, + BuiltinOptions_QuantizeOptions = 89, + BuiltinOptions_MatrixSetDiagOptions = 90, + BuiltinOptions_HardSwishOptions = 91, + BuiltinOptions_IfOptions = 92, + BuiltinOptions_WhileOptions = 93, + BuiltinOptions_DepthToSpaceOptions = 94, + BuiltinOptions_NonMaxSuppressionV4Options = 95, + BuiltinOptions_NonMaxSuppressionV5Options = 96, + BuiltinOptions_ScatterNdOptions = 97, + BuiltinOptions_SelectV2Options = 98, + BuiltinOptions_DensifyOptions = 99, + BuiltinOptions_SegmentSumOptions = 100, + BuiltinOptions_BatchMatMulOptions = 101, + BuiltinOptions_MIN = BuiltinOptions_NONE, + BuiltinOptions_MAX = BuiltinOptions_BatchMatMulOptions +}; + +inline const BuiltinOptions (&EnumValuesBuiltinOptions())[102] +{ + static const BuiltinOptions values[] = {BuiltinOptions_NONE, + BuiltinOptions_Conv2DOptions, + BuiltinOptions_DepthwiseConv2DOptions, + BuiltinOptions_ConcatEmbeddingsOptions, + BuiltinOptions_LSHProjectionOptions, + BuiltinOptions_Pool2DOptions, + BuiltinOptions_SVDFOptions, + BuiltinOptions_RNNOptions, + BuiltinOptions_FullyConnectedOptions, + BuiltinOptions_SoftmaxOptions, + BuiltinOptions_ConcatenationOptions, + BuiltinOptions_AddOptions, + BuiltinOptions_L2NormOptions, + BuiltinOptions_LocalResponseNormalizationOptions, + BuiltinOptions_LSTMOptions, + BuiltinOptions_ResizeBilinearOptions, + BuiltinOptions_CallOptions, + BuiltinOptions_ReshapeOptions, + BuiltinOptions_SkipGramOptions, + BuiltinOptions_SpaceToDepthOptions, + BuiltinOptions_EmbeddingLookupSparseOptions, + BuiltinOptions_MulOptions, + BuiltinOptions_PadOptions, + BuiltinOptions_GatherOptions, + BuiltinOptions_BatchToSpaceNDOptions, + BuiltinOptions_SpaceToBatchNDOptions, + BuiltinOptions_TransposeOptions, + BuiltinOptions_ReducerOptions, + BuiltinOptions_SubOptions, + BuiltinOptions_DivOptions, + BuiltinOptions_SqueezeOptions, + BuiltinOptions_SequenceRNNOptions, + BuiltinOptions_StridedSliceOptions, + BuiltinOptions_ExpOptions, + BuiltinOptions_TopKV2Options, + BuiltinOptions_SplitOptions, + BuiltinOptions_LogSoftmaxOptions, + BuiltinOptions_CastOptions, + BuiltinOptions_DequantizeOptions, + BuiltinOptions_MaximumMinimumOptions, + BuiltinOptions_ArgMaxOptions, + BuiltinOptions_LessOptions, + BuiltinOptions_NegOptions, + BuiltinOptions_PadV2Options, + BuiltinOptions_GreaterOptions, + BuiltinOptions_GreaterEqualOptions, + BuiltinOptions_LessEqualOptions, + BuiltinOptions_SelectOptions, + BuiltinOptions_SliceOptions, + BuiltinOptions_TransposeConvOptions, + BuiltinOptions_SparseToDenseOptions, + BuiltinOptions_TileOptions, + BuiltinOptions_ExpandDimsOptions, + BuiltinOptions_EqualOptions, + BuiltinOptions_NotEqualOptions, + BuiltinOptions_ShapeOptions, + BuiltinOptions_PowOptions, + BuiltinOptions_ArgMinOptions, + BuiltinOptions_FakeQuantOptions, + BuiltinOptions_PackOptions, + BuiltinOptions_LogicalOrOptions, + BuiltinOptions_OneHotOptions, + BuiltinOptions_LogicalAndOptions, + BuiltinOptions_LogicalNotOptions, + BuiltinOptions_UnpackOptions, + BuiltinOptions_FloorDivOptions, + BuiltinOptions_SquareOptions, + BuiltinOptions_ZerosLikeOptions, + BuiltinOptions_FillOptions, + BuiltinOptions_BidirectionalSequenceLSTMOptions, + BuiltinOptions_BidirectionalSequenceRNNOptions, + BuiltinOptions_UnidirectionalSequenceLSTMOptions, + BuiltinOptions_FloorModOptions, + BuiltinOptions_RangeOptions, + BuiltinOptions_ResizeNearestNeighborOptions, + BuiltinOptions_LeakyReluOptions, + BuiltinOptions_SquaredDifferenceOptions, + BuiltinOptions_MirrorPadOptions, + BuiltinOptions_AbsOptions, + BuiltinOptions_SplitVOptions, + BuiltinOptions_UniqueOptions, + BuiltinOptions_ReverseV2Options, + BuiltinOptions_AddNOptions, + BuiltinOptions_GatherNdOptions, + BuiltinOptions_CosOptions, + BuiltinOptions_WhereOptions, + BuiltinOptions_RankOptions, + BuiltinOptions_ReverseSequenceOptions, + BuiltinOptions_MatrixDiagOptions, + BuiltinOptions_QuantizeOptions, + BuiltinOptions_MatrixSetDiagOptions, + BuiltinOptions_HardSwishOptions, + BuiltinOptions_IfOptions, + BuiltinOptions_WhileOptions, + BuiltinOptions_DepthToSpaceOptions, + BuiltinOptions_NonMaxSuppressionV4Options, + BuiltinOptions_NonMaxSuppressionV5Options, + BuiltinOptions_ScatterNdOptions, + BuiltinOptions_SelectV2Options, + BuiltinOptions_DensifyOptions, + BuiltinOptions_SegmentSumOptions, + BuiltinOptions_BatchMatMulOptions}; + return values; +} + +inline const char *const *EnumNamesBuiltinOptions() +{ + static const char *const names[] = {"NONE", + "Conv2DOptions", + "DepthwiseConv2DOptions", + "ConcatEmbeddingsOptions", + "LSHProjectionOptions", + "Pool2DOptions", + "SVDFOptions", + "RNNOptions", + "FullyConnectedOptions", + "SoftmaxOptions", + "ConcatenationOptions", + "AddOptions", + "L2NormOptions", + "LocalResponseNormalizationOptions", + "LSTMOptions", + "ResizeBilinearOptions", + "CallOptions", + "ReshapeOptions", + "SkipGramOptions", + "SpaceToDepthOptions", + "EmbeddingLookupSparseOptions", + "MulOptions", + "PadOptions", + "GatherOptions", + "BatchToSpaceNDOptions", + "SpaceToBatchNDOptions", + "TransposeOptions", + "ReducerOptions", + "SubOptions", + "DivOptions", + "SqueezeOptions", + "SequenceRNNOptions", + "StridedSliceOptions", + "ExpOptions", + "TopKV2Options", + "SplitOptions", + "LogSoftmaxOptions", + "CastOptions", + "DequantizeOptions", + "MaximumMinimumOptions", + "ArgMaxOptions", + "LessOptions", + "NegOptions", + "PadV2Options", + "GreaterOptions", + "GreaterEqualOptions", + "LessEqualOptions", + "SelectOptions", + "SliceOptions", + "TransposeConvOptions", + "SparseToDenseOptions", + "TileOptions", + "ExpandDimsOptions", + "EqualOptions", + "NotEqualOptions", + "ShapeOptions", + "PowOptions", + "ArgMinOptions", + "FakeQuantOptions", + "PackOptions", + "LogicalOrOptions", + "OneHotOptions", + "LogicalAndOptions", + "LogicalNotOptions", + "UnpackOptions", + "FloorDivOptions", + "SquareOptions", + "ZerosLikeOptions", + "FillOptions", + "BidirectionalSequenceLSTMOptions", + "BidirectionalSequenceRNNOptions", + "UnidirectionalSequenceLSTMOptions", + "FloorModOptions", + "RangeOptions", + "ResizeNearestNeighborOptions", + "LeakyReluOptions", + "SquaredDifferenceOptions", + "MirrorPadOptions", + "AbsOptions", + "SplitVOptions", + "UniqueOptions", + "ReverseV2Options", + "AddNOptions", + "GatherNdOptions", + "CosOptions", + "WhereOptions", + "RankOptions", + "ReverseSequenceOptions", + "MatrixDiagOptions", + "QuantizeOptions", + "MatrixSetDiagOptions", + "HardSwishOptions", + "IfOptions", + "WhileOptions", + "DepthToSpaceOptions", + "NonMaxSuppressionV4Options", + "NonMaxSuppressionV5Options", + "ScatterNdOptions", + "SelectV2Options", + "DensifyOptions", + "SegmentSumOptions", + "BatchMatMulOptions", + nullptr}; + return names; +} + +inline const char *EnumNameBuiltinOptions(BuiltinOptions e) +{ + const size_t index = static_cast(e); + return EnumNamesBuiltinOptions()[index]; +} + +template struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NONE; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_Conv2DOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DepthwiseConv2DOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ConcatEmbeddingsOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LSHProjectionOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_Pool2DOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SVDFOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_RNNOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FullyConnectedOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SoftmaxOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ConcatenationOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_AddOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_L2NormOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LocalResponseNormalizationOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LSTMOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ResizeBilinearOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_CallOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ReshapeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SkipGramOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SpaceToDepthOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_EmbeddingLookupSparseOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MulOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_PadOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_GatherOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_BatchToSpaceNDOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SpaceToBatchNDOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_TransposeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ReducerOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SubOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DivOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SqueezeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SequenceRNNOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_StridedSliceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ExpOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_TopKV2Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SplitOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LogSoftmaxOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_CastOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DequantizeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MaximumMinimumOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ArgMaxOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LessOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NegOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_PadV2Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_GreaterOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_GreaterEqualOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LessEqualOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SelectOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SliceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_TransposeConvOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SparseToDenseOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_TileOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ExpandDimsOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_EqualOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NotEqualOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ShapeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_PowOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ArgMinOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FakeQuantOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_PackOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LogicalOrOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_OneHotOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LogicalAndOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LogicalNotOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_UnpackOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FloorDivOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SquareOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ZerosLikeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FillOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceLSTMOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_BidirectionalSequenceRNNOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_UnidirectionalSequenceLSTMOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_FloorModOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_RangeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ResizeNearestNeighborOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_LeakyReluOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SquaredDifferenceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MirrorPadOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_AbsOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SplitVOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_UniqueOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ReverseV2Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_AddNOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_GatherNdOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_CosOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_WhereOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_RankOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ReverseSequenceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MatrixDiagOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_QuantizeOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_MatrixSetDiagOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_HardSwishOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_IfOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_WhileOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DepthToSpaceOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV4Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_NonMaxSuppressionV5Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_ScatterNdOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SelectV2Options; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_DensifyOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_SegmentSumOptions; +}; + +template <> struct BuiltinOptionsTraits +{ + static const BuiltinOptions enum_value = BuiltinOptions_BatchMatMulOptions; +}; + +bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, BuiltinOptions type); +bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types); + +enum Padding +{ + Padding_SAME = 0, + Padding_VALID = 1, + Padding_MIN = Padding_SAME, + Padding_MAX = Padding_VALID +}; + +inline const Padding (&EnumValuesPadding())[2] +{ + static const Padding values[] = {Padding_SAME, Padding_VALID}; + return values; +} + +inline const char *const *EnumNamesPadding() +{ + static const char *const names[] = {"SAME", "VALID", nullptr}; + return names; +} + +inline const char *EnumNamePadding(Padding e) +{ + const size_t index = static_cast(e); + return EnumNamesPadding()[index]; +} + +enum ActivationFunctionType +{ + ActivationFunctionType_NONE = 0, + ActivationFunctionType_RELU = 1, + ActivationFunctionType_RELU_N1_TO_1 = 2, + ActivationFunctionType_RELU6 = 3, + ActivationFunctionType_TANH = 4, + ActivationFunctionType_SIGN_BIT = 5, + ActivationFunctionType_MIN = ActivationFunctionType_NONE, + ActivationFunctionType_MAX = ActivationFunctionType_SIGN_BIT +}; + +inline const ActivationFunctionType (&EnumValuesActivationFunctionType())[6] +{ + static const ActivationFunctionType values[] = { + ActivationFunctionType_NONE, ActivationFunctionType_RELU, + ActivationFunctionType_RELU_N1_TO_1, ActivationFunctionType_RELU6, + ActivationFunctionType_TANH, ActivationFunctionType_SIGN_BIT}; + return values; +} + +inline const char *const *EnumNamesActivationFunctionType() +{ + static const char *const names[] = {"NONE", "RELU", "RELU_N1_TO_1", "RELU6", + "TANH", "SIGN_BIT", nullptr}; + return names; +} + +inline const char *EnumNameActivationFunctionType(ActivationFunctionType e) +{ + const size_t index = static_cast(e); + return EnumNamesActivationFunctionType()[index]; +} + +enum LSHProjectionType +{ + LSHProjectionType_UNKNOWN = 0, + LSHProjectionType_SPARSE = 1, + LSHProjectionType_DENSE = 2, + LSHProjectionType_MIN = LSHProjectionType_UNKNOWN, + LSHProjectionType_MAX = LSHProjectionType_DENSE +}; + +inline const LSHProjectionType (&EnumValuesLSHProjectionType())[3] +{ + static const LSHProjectionType values[] = {LSHProjectionType_UNKNOWN, LSHProjectionType_SPARSE, + LSHProjectionType_DENSE}; + return values; +} + +inline const char *const *EnumNamesLSHProjectionType() +{ + static const char *const names[] = {"UNKNOWN", "SPARSE", "DENSE", nullptr}; + return names; +} + +inline const char *EnumNameLSHProjectionType(LSHProjectionType e) +{ + const size_t index = static_cast(e); + return EnumNamesLSHProjectionType()[index]; +} + +enum FullyConnectedOptionsWeightsFormat +{ + FullyConnectedOptionsWeightsFormat_DEFAULT = 0, + FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8 = 1, + FullyConnectedOptionsWeightsFormat_MIN = FullyConnectedOptionsWeightsFormat_DEFAULT, + FullyConnectedOptionsWeightsFormat_MAX = FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8 +}; + +inline const FullyConnectedOptionsWeightsFormat (&EnumValuesFullyConnectedOptionsWeightsFormat())[2] +{ + static const FullyConnectedOptionsWeightsFormat values[] = { + FullyConnectedOptionsWeightsFormat_DEFAULT, + FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8}; + return values; +} + +inline const char *const *EnumNamesFullyConnectedOptionsWeightsFormat() +{ + static const char *const names[] = {"DEFAULT", "SHUFFLED4x16INT8", nullptr}; + return names; +} + +inline const char *EnumNameFullyConnectedOptionsWeightsFormat(FullyConnectedOptionsWeightsFormat e) +{ + const size_t index = static_cast(e); + return EnumNamesFullyConnectedOptionsWeightsFormat()[index]; +} + +enum LSTMKernelType +{ + LSTMKernelType_FULL = 0, + LSTMKernelType_BASIC = 1, + LSTMKernelType_MIN = LSTMKernelType_FULL, + LSTMKernelType_MAX = LSTMKernelType_BASIC +}; + +inline const LSTMKernelType (&EnumValuesLSTMKernelType())[2] +{ + static const LSTMKernelType values[] = {LSTMKernelType_FULL, LSTMKernelType_BASIC}; + return values; +} + +inline const char *const *EnumNamesLSTMKernelType() +{ + static const char *const names[] = {"FULL", "BASIC", nullptr}; + return names; +} + +inline const char *EnumNameLSTMKernelType(LSTMKernelType e) +{ + const size_t index = static_cast(e); + return EnumNamesLSTMKernelType()[index]; +} + +enum CombinerType +{ + CombinerType_SUM = 0, + CombinerType_MEAN = 1, + CombinerType_SQRTN = 2, + CombinerType_MIN = CombinerType_SUM, + CombinerType_MAX = CombinerType_SQRTN +}; + +inline const CombinerType (&EnumValuesCombinerType())[3] +{ + static const CombinerType values[] = {CombinerType_SUM, CombinerType_MEAN, CombinerType_SQRTN}; + return values; +} + +inline const char *const *EnumNamesCombinerType() +{ + static const char *const names[] = {"SUM", "MEAN", "SQRTN", nullptr}; + return names; +} + +inline const char *EnumNameCombinerType(CombinerType e) +{ + const size_t index = static_cast(e); + return EnumNamesCombinerType()[index]; +} + +enum MirrorPadMode +{ + MirrorPadMode_REFLECT = 0, + MirrorPadMode_SYMMETRIC = 1, + MirrorPadMode_MIN = MirrorPadMode_REFLECT, + MirrorPadMode_MAX = MirrorPadMode_SYMMETRIC +}; + +inline const MirrorPadMode (&EnumValuesMirrorPadMode())[2] +{ + static const MirrorPadMode values[] = {MirrorPadMode_REFLECT, MirrorPadMode_SYMMETRIC}; + return values; +} + +inline const char *const *EnumNamesMirrorPadMode() +{ + static const char *const names[] = {"REFLECT", "SYMMETRIC", nullptr}; + return names; +} + +inline const char *EnumNameMirrorPadMode(MirrorPadMode e) +{ + const size_t index = static_cast(e); + return EnumNamesMirrorPadMode()[index]; +} + +enum CustomOptionsFormat +{ + CustomOptionsFormat_FLEXBUFFERS = 0, + CustomOptionsFormat_MIN = CustomOptionsFormat_FLEXBUFFERS, + CustomOptionsFormat_MAX = CustomOptionsFormat_FLEXBUFFERS +}; + +inline const CustomOptionsFormat (&EnumValuesCustomOptionsFormat())[1] +{ + static const CustomOptionsFormat values[] = {CustomOptionsFormat_FLEXBUFFERS}; + return values; +} + +inline const char *const *EnumNamesCustomOptionsFormat() +{ + static const char *const names[] = {"FLEXBUFFERS", nullptr}; + return names; +} + +inline const char *EnumNameCustomOptionsFormat(CustomOptionsFormat e) +{ + const size_t index = static_cast(e); + return EnumNamesCustomOptionsFormat()[index]; +} + +struct CustomQuantization FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_CUSTOM = 4 + }; + const flatbuffers::Vector *custom() const + { + return GetPointer *>(VT_CUSTOM); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_CUSTOM) && + verifier.VerifyVector(custom()) && verifier.EndTable(); + } +}; + +struct CustomQuantizationBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_custom(flatbuffers::Offset> custom) + { + fbb_.AddOffset(CustomQuantization::VT_CUSTOM, custom); + } + explicit CustomQuantizationBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + CustomQuantizationBuilder &operator=(const CustomQuantizationBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateCustomQuantization(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> custom = 0) +{ + CustomQuantizationBuilder builder_(_fbb); + builder_.add_custom(custom); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateCustomQuantizationDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *custom = nullptr) +{ + return onert_tflite::CreateCustomQuantization(_fbb, + custom ? _fbb.CreateVector(*custom) : 0); +} + +struct QuantizationParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_MIN = 4, + VT_MAX = 6, + VT_SCALE = 8, + VT_ZERO_POINT = 10, + VT_DETAILS_TYPE = 12, + VT_DETAILS = 14, + VT_QUANTIZED_DIMENSION = 16 + }; + const flatbuffers::Vector *min() const + { + return GetPointer *>(VT_MIN); + } + const flatbuffers::Vector *max() const + { + return GetPointer *>(VT_MAX); + } + const flatbuffers::Vector *scale() const + { + return GetPointer *>(VT_SCALE); + } + const flatbuffers::Vector *zero_point() const + { + return GetPointer *>(VT_ZERO_POINT); + } + QuantizationDetails details_type() const + { + return static_cast(GetField(VT_DETAILS_TYPE, 0)); + } + const void *details() const { return GetPointer(VT_DETAILS); } + template const T *details_as() const; + const CustomQuantization *details_as_CustomQuantization() const + { + return details_type() == QuantizationDetails_CustomQuantization + ? static_cast(details()) + : nullptr; + } + int32_t quantized_dimension() const { return GetField(VT_QUANTIZED_DIMENSION, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_MIN) && + verifier.VerifyVector(min()) && VerifyOffset(verifier, VT_MAX) && + verifier.VerifyVector(max()) && VerifyOffset(verifier, VT_SCALE) && + verifier.VerifyVector(scale()) && VerifyOffset(verifier, VT_ZERO_POINT) && + verifier.VerifyVector(zero_point()) && VerifyField(verifier, VT_DETAILS_TYPE) && + VerifyOffset(verifier, VT_DETAILS) && + VerifyQuantizationDetails(verifier, details(), details_type()) && + VerifyField(verifier, VT_QUANTIZED_DIMENSION) && verifier.EndTable(); + } +}; + +template <> +inline const CustomQuantization *QuantizationParameters::details_as() const +{ + return details_as_CustomQuantization(); +} + +struct QuantizationParametersBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_min(flatbuffers::Offset> min) + { + fbb_.AddOffset(QuantizationParameters::VT_MIN, min); + } + void add_max(flatbuffers::Offset> max) + { + fbb_.AddOffset(QuantizationParameters::VT_MAX, max); + } + void add_scale(flatbuffers::Offset> scale) + { + fbb_.AddOffset(QuantizationParameters::VT_SCALE, scale); + } + void add_zero_point(flatbuffers::Offset> zero_point) + { + fbb_.AddOffset(QuantizationParameters::VT_ZERO_POINT, zero_point); + } + void add_details_type(QuantizationDetails details_type) + { + fbb_.AddElement(QuantizationParameters::VT_DETAILS_TYPE, + static_cast(details_type), 0); + } + void add_details(flatbuffers::Offset details) + { + fbb_.AddOffset(QuantizationParameters::VT_DETAILS, details); + } + void add_quantized_dimension(int32_t quantized_dimension) + { + fbb_.AddElement(QuantizationParameters::VT_QUANTIZED_DIMENSION, quantized_dimension, + 0); + } + explicit QuantizationParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + QuantizationParametersBuilder &operator=(const QuantizationParametersBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateQuantizationParameters(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> min = 0, + flatbuffers::Offset> max = 0, + flatbuffers::Offset> scale = 0, + flatbuffers::Offset> zero_point = 0, + QuantizationDetails details_type = QuantizationDetails_NONE, + flatbuffers::Offset details = 0, int32_t quantized_dimension = 0) +{ + QuantizationParametersBuilder builder_(_fbb); + builder_.add_quantized_dimension(quantized_dimension); + builder_.add_details(details); + builder_.add_zero_point(zero_point); + builder_.add_scale(scale); + builder_.add_max(max); + builder_.add_min(min); + builder_.add_details_type(details_type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateQuantizationParametersDirect( + flatbuffers::FlatBufferBuilder &_fbb, const std::vector *min = nullptr, + const std::vector *max = nullptr, const std::vector *scale = nullptr, + const std::vector *zero_point = nullptr, + QuantizationDetails details_type = QuantizationDetails_NONE, + flatbuffers::Offset details = 0, int32_t quantized_dimension = 0) +{ + return onert_tflite::CreateQuantizationParameters( + _fbb, min ? _fbb.CreateVector(*min) : 0, max ? _fbb.CreateVector(*max) : 0, + scale ? _fbb.CreateVector(*scale) : 0, + zero_point ? _fbb.CreateVector(*zero_point) : 0, details_type, details, + quantized_dimension); +} + +struct Int32Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALUES = 4 + }; + const flatbuffers::Vector *values() const + { + return GetPointer *>(VT_VALUES); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && verifier.EndTable(); + } +}; + +struct Int32VectorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values(flatbuffers::Offset> values) + { + fbb_.AddOffset(Int32Vector::VT_VALUES, values); + } + explicit Int32VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Int32VectorBuilder &operator=(const Int32VectorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateInt32Vector(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> values = 0) +{ + Int32VectorBuilder builder_(_fbb); + builder_.add_values(values); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateInt32VectorDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *values = nullptr) +{ + return onert_tflite::CreateInt32Vector(_fbb, values ? _fbb.CreateVector(*values) : 0); +} + +struct Uint16Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALUES = 4 + }; + const flatbuffers::Vector *values() const + { + return GetPointer *>(VT_VALUES); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && verifier.EndTable(); + } +}; + +struct Uint16VectorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values(flatbuffers::Offset> values) + { + fbb_.AddOffset(Uint16Vector::VT_VALUES, values); + } + explicit Uint16VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Uint16VectorBuilder &operator=(const Uint16VectorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateUint16Vector(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> values = 0) +{ + Uint16VectorBuilder builder_(_fbb); + builder_.add_values(values); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateUint16VectorDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *values = nullptr) +{ + return onert_tflite::CreateUint16Vector(_fbb, values ? _fbb.CreateVector(*values) : 0); +} + +struct Uint8Vector FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALUES = 4 + }; + const flatbuffers::Vector *values() const + { + return GetPointer *>(VT_VALUES); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && verifier.EndTable(); + } +}; + +struct Uint8VectorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values(flatbuffers::Offset> values) + { + fbb_.AddOffset(Uint8Vector::VT_VALUES, values); + } + explicit Uint8VectorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Uint8VectorBuilder &operator=(const Uint8VectorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateUint8Vector(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> values = 0) +{ + Uint8VectorBuilder builder_(_fbb); + builder_.add_values(values); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateUint8VectorDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *values = nullptr) +{ + return onert_tflite::CreateUint8Vector(_fbb, values ? _fbb.CreateVector(*values) : 0); +} + +struct DimensionMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FORMAT = 4, + VT_DENSE_SIZE = 6, + VT_ARRAY_SEGMENTS_TYPE = 8, + VT_ARRAY_SEGMENTS = 10, + VT_ARRAY_INDICES_TYPE = 12, + VT_ARRAY_INDICES = 14 + }; + DimensionType format() const + { + return static_cast(GetField(VT_FORMAT, 0)); + } + int32_t dense_size() const { return GetField(VT_DENSE_SIZE, 0); } + SparseIndexVector array_segments_type() const + { + return static_cast(GetField(VT_ARRAY_SEGMENTS_TYPE, 0)); + } + const void *array_segments() const { return GetPointer(VT_ARRAY_SEGMENTS); } + template const T *array_segments_as() const; + const Int32Vector *array_segments_as_Int32Vector() const + { + return array_segments_type() == SparseIndexVector_Int32Vector + ? static_cast(array_segments()) + : nullptr; + } + const Uint16Vector *array_segments_as_Uint16Vector() const + { + return array_segments_type() == SparseIndexVector_Uint16Vector + ? static_cast(array_segments()) + : nullptr; + } + const Uint8Vector *array_segments_as_Uint8Vector() const + { + return array_segments_type() == SparseIndexVector_Uint8Vector + ? static_cast(array_segments()) + : nullptr; + } + SparseIndexVector array_indices_type() const + { + return static_cast(GetField(VT_ARRAY_INDICES_TYPE, 0)); + } + const void *array_indices() const { return GetPointer(VT_ARRAY_INDICES); } + template const T *array_indices_as() const; + const Int32Vector *array_indices_as_Int32Vector() const + { + return array_indices_type() == SparseIndexVector_Int32Vector + ? static_cast(array_indices()) + : nullptr; + } + const Uint16Vector *array_indices_as_Uint16Vector() const + { + return array_indices_type() == SparseIndexVector_Uint16Vector + ? static_cast(array_indices()) + : nullptr; + } + const Uint8Vector *array_indices_as_Uint8Vector() const + { + return array_indices_type() == SparseIndexVector_Uint8Vector + ? static_cast(array_indices()) + : nullptr; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_FORMAT) && + VerifyField(verifier, VT_DENSE_SIZE) && + VerifyField(verifier, VT_ARRAY_SEGMENTS_TYPE) && + VerifyOffset(verifier, VT_ARRAY_SEGMENTS) && + VerifySparseIndexVector(verifier, array_segments(), array_segments_type()) && + VerifyField(verifier, VT_ARRAY_INDICES_TYPE) && + VerifyOffset(verifier, VT_ARRAY_INDICES) && + VerifySparseIndexVector(verifier, array_indices(), array_indices_type()) && + verifier.EndTable(); + } +}; + +template <> inline const Int32Vector *DimensionMetadata::array_segments_as() const +{ + return array_segments_as_Int32Vector(); +} + +template <> inline const Uint16Vector *DimensionMetadata::array_segments_as() const +{ + return array_segments_as_Uint16Vector(); +} + +template <> inline const Uint8Vector *DimensionMetadata::array_segments_as() const +{ + return array_segments_as_Uint8Vector(); +} + +template <> inline const Int32Vector *DimensionMetadata::array_indices_as() const +{ + return array_indices_as_Int32Vector(); +} + +template <> inline const Uint16Vector *DimensionMetadata::array_indices_as() const +{ + return array_indices_as_Uint16Vector(); +} + +template <> inline const Uint8Vector *DimensionMetadata::array_indices_as() const +{ + return array_indices_as_Uint8Vector(); +} + +struct DimensionMetadataBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_format(DimensionType format) + { + fbb_.AddElement(DimensionMetadata::VT_FORMAT, static_cast(format), 0); + } + void add_dense_size(int32_t dense_size) + { + fbb_.AddElement(DimensionMetadata::VT_DENSE_SIZE, dense_size, 0); + } + void add_array_segments_type(SparseIndexVector array_segments_type) + { + fbb_.AddElement(DimensionMetadata::VT_ARRAY_SEGMENTS_TYPE, + static_cast(array_segments_type), 0); + } + void add_array_segments(flatbuffers::Offset array_segments) + { + fbb_.AddOffset(DimensionMetadata::VT_ARRAY_SEGMENTS, array_segments); + } + void add_array_indices_type(SparseIndexVector array_indices_type) + { + fbb_.AddElement(DimensionMetadata::VT_ARRAY_INDICES_TYPE, + static_cast(array_indices_type), 0); + } + void add_array_indices(flatbuffers::Offset array_indices) + { + fbb_.AddOffset(DimensionMetadata::VT_ARRAY_INDICES, array_indices); + } + explicit DimensionMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DimensionMetadataBuilder &operator=(const DimensionMetadataBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDimensionMetadata(flatbuffers::FlatBufferBuilder &_fbb, + DimensionType format = DimensionType_DENSE, int32_t dense_size = 0, + SparseIndexVector array_segments_type = SparseIndexVector_NONE, + flatbuffers::Offset array_segments = 0, + SparseIndexVector array_indices_type = SparseIndexVector_NONE, + flatbuffers::Offset array_indices = 0) +{ + DimensionMetadataBuilder builder_(_fbb); + builder_.add_array_indices(array_indices); + builder_.add_array_segments(array_segments); + builder_.add_dense_size(dense_size); + builder_.add_array_indices_type(array_indices_type); + builder_.add_array_segments_type(array_segments_type); + builder_.add_format(format); + return builder_.Finish(); +} + +struct SparsityParameters FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TRAVERSAL_ORDER = 4, + VT_BLOCK_MAP = 6, + VT_DIM_METADATA = 8 + }; + const flatbuffers::Vector *traversal_order() const + { + return GetPointer *>(VT_TRAVERSAL_ORDER); + } + const flatbuffers::Vector *block_map() const + { + return GetPointer *>(VT_BLOCK_MAP); + } + const flatbuffers::Vector> *dim_metadata() const + { + return GetPointer> *>( + VT_DIM_METADATA); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TRAVERSAL_ORDER) && + verifier.VerifyVector(traversal_order()) && VerifyOffset(verifier, VT_BLOCK_MAP) && + verifier.VerifyVector(block_map()) && VerifyOffset(verifier, VT_DIM_METADATA) && + verifier.VerifyVector(dim_metadata()) && verifier.VerifyVectorOfTables(dim_metadata()) && + verifier.EndTable(); + } +}; + +struct SparsityParametersBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_traversal_order(flatbuffers::Offset> traversal_order) + { + fbb_.AddOffset(SparsityParameters::VT_TRAVERSAL_ORDER, traversal_order); + } + void add_block_map(flatbuffers::Offset> block_map) + { + fbb_.AddOffset(SparsityParameters::VT_BLOCK_MAP, block_map); + } + void add_dim_metadata( + flatbuffers::Offset>> dim_metadata) + { + fbb_.AddOffset(SparsityParameters::VT_DIM_METADATA, dim_metadata); + } + explicit SparsityParametersBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SparsityParametersBuilder &operator=(const SparsityParametersBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSparsityParameters( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> traversal_order = 0, + flatbuffers::Offset> block_map = 0, + flatbuffers::Offset>> dim_metadata = + 0) +{ + SparsityParametersBuilder builder_(_fbb); + builder_.add_dim_metadata(dim_metadata); + builder_.add_block_map(block_map); + builder_.add_traversal_order(traversal_order); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateSparsityParametersDirect( + flatbuffers::FlatBufferBuilder &_fbb, const std::vector *traversal_order = nullptr, + const std::vector *block_map = nullptr, + const std::vector> *dim_metadata = nullptr) +{ + return onert_tflite::CreateSparsityParameters( + _fbb, traversal_order ? _fbb.CreateVector(*traversal_order) : 0, + block_map ? _fbb.CreateVector(*block_map) : 0, + dim_metadata ? _fbb.CreateVector>(*dim_metadata) : 0); +} + +struct Tensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_SHAPE = 4, + VT_TYPE = 6, + VT_BUFFER = 8, + VT_NAME = 10, + VT_QUANTIZATION = 12, + VT_IS_VARIABLE = 14, + VT_SPARSITY = 16, + VT_SHAPE_SIGNATURE = 18 + }; + const flatbuffers::Vector *shape() const + { + return GetPointer *>(VT_SHAPE); + } + TensorType type() const { return static_cast(GetField(VT_TYPE, 0)); } + uint32_t buffer() const { return GetField(VT_BUFFER, 0); } + const flatbuffers::String *name() const + { + return GetPointer(VT_NAME); + } + const QuantizationParameters *quantization() const + { + return GetPointer(VT_QUANTIZATION); + } + bool is_variable() const { return GetField(VT_IS_VARIABLE, 0) != 0; } + const SparsityParameters *sparsity() const + { + return GetPointer(VT_SPARSITY); + } + const flatbuffers::Vector *shape_signature() const + { + return GetPointer *>(VT_SHAPE_SIGNATURE); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_SHAPE) && + verifier.VerifyVector(shape()) && VerifyField(verifier, VT_TYPE) && + VerifyField(verifier, VT_BUFFER) && VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && VerifyOffset(verifier, VT_QUANTIZATION) && + verifier.VerifyTable(quantization()) && VerifyField(verifier, VT_IS_VARIABLE) && + VerifyOffset(verifier, VT_SPARSITY) && verifier.VerifyTable(sparsity()) && + VerifyOffset(verifier, VT_SHAPE_SIGNATURE) && verifier.VerifyVector(shape_signature()) && + verifier.EndTable(); + } +}; + +struct TensorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_shape(flatbuffers::Offset> shape) + { + fbb_.AddOffset(Tensor::VT_SHAPE, shape); + } + void add_type(TensorType type) + { + fbb_.AddElement(Tensor::VT_TYPE, static_cast(type), 0); + } + void add_buffer(uint32_t buffer) { fbb_.AddElement(Tensor::VT_BUFFER, buffer, 0); } + void add_name(flatbuffers::Offset name) + { + fbb_.AddOffset(Tensor::VT_NAME, name); + } + void add_quantization(flatbuffers::Offset quantization) + { + fbb_.AddOffset(Tensor::VT_QUANTIZATION, quantization); + } + void add_is_variable(bool is_variable) + { + fbb_.AddElement(Tensor::VT_IS_VARIABLE, static_cast(is_variable), 0); + } + void add_sparsity(flatbuffers::Offset sparsity) + { + fbb_.AddOffset(Tensor::VT_SPARSITY, sparsity); + } + void add_shape_signature(flatbuffers::Offset> shape_signature) + { + fbb_.AddOffset(Tensor::VT_SHAPE_SIGNATURE, shape_signature); + } + explicit TensorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TensorBuilder &operator=(const TensorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateTensor(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> shape = 0, + TensorType type = TensorType_FLOAT32, uint32_t buffer = 0, + flatbuffers::Offset name = 0, + flatbuffers::Offset quantization = 0, bool is_variable = false, + flatbuffers::Offset sparsity = 0, + flatbuffers::Offset> shape_signature = 0) +{ + TensorBuilder builder_(_fbb); + builder_.add_shape_signature(shape_signature); + builder_.add_sparsity(sparsity); + builder_.add_quantization(quantization); + builder_.add_name(name); + builder_.add_buffer(buffer); + builder_.add_shape(shape); + builder_.add_is_variable(is_variable); + builder_.add_type(type); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateTensorDirect( + flatbuffers::FlatBufferBuilder &_fbb, const std::vector *shape = nullptr, + TensorType type = TensorType_FLOAT32, uint32_t buffer = 0, const char *name = nullptr, + flatbuffers::Offset quantization = 0, bool is_variable = false, + flatbuffers::Offset sparsity = 0, + const std::vector *shape_signature = nullptr) +{ + return onert_tflite::CreateTensor( + _fbb, shape ? _fbb.CreateVector(*shape) : 0, type, buffer, + name ? _fbb.CreateString(name) : 0, quantization, is_variable, sparsity, + shape_signature ? _fbb.CreateVector(*shape_signature) : 0); +} + +struct Conv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8, + VT_FUSED_ACTIVATION_FUNCTION = 10, + VT_DILATION_W_FACTOR = 12, + VT_DILATION_H_FACTOR = 14 + }; + Padding padding() const { return static_cast(GetField(VT_PADDING, 0)); } + int32_t stride_w() const { return GetField(VT_STRIDE_W, 0); } + int32_t stride_h() const { return GetField(VT_STRIDE_H, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + int32_t dilation_w_factor() const { return GetField(VT_DILATION_W_FACTOR, 1); } + int32_t dilation_h_factor() const { return GetField(VT_DILATION_H_FACTOR, 1); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_PADDING) && + VerifyField(verifier, VT_STRIDE_W) && + VerifyField(verifier, VT_STRIDE_H) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_DILATION_W_FACTOR) && + VerifyField(verifier, VT_DILATION_H_FACTOR) && verifier.EndTable(); + } +}; + +struct Conv2DOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(Padding padding) + { + fbb_.AddElement(Conv2DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) + { + fbb_.AddElement(Conv2DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) + { + fbb_.AddElement(Conv2DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(Conv2DOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_dilation_w_factor(int32_t dilation_w_factor) + { + fbb_.AddElement(Conv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1); + } + void add_dilation_h_factor(int32_t dilation_h_factor) + { + fbb_.AddElement(Conv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1); + } + explicit Conv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Conv2DOptionsBuilder &operator=(const Conv2DOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateConv2DOptions(flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME, + int32_t stride_w = 0, int32_t stride_h = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + int32_t dilation_w_factor = 1, int32_t dilation_h_factor = 1) +{ + Conv2DOptionsBuilder builder_(_fbb); + builder_.add_dilation_h_factor(dilation_h_factor); + builder_.add_dilation_w_factor(dilation_w_factor); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +struct Pool2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8, + VT_FILTER_WIDTH = 10, + VT_FILTER_HEIGHT = 12, + VT_FUSED_ACTIVATION_FUNCTION = 14 + }; + Padding padding() const { return static_cast(GetField(VT_PADDING, 0)); } + int32_t stride_w() const { return GetField(VT_STRIDE_W, 0); } + int32_t stride_h() const { return GetField(VT_STRIDE_H, 0); } + int32_t filter_width() const { return GetField(VT_FILTER_WIDTH, 0); } + int32_t filter_height() const { return GetField(VT_FILTER_HEIGHT, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_PADDING) && + VerifyField(verifier, VT_STRIDE_W) && + VerifyField(verifier, VT_STRIDE_H) && + VerifyField(verifier, VT_FILTER_WIDTH) && + VerifyField(verifier, VT_FILTER_HEIGHT) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct Pool2DOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(Padding padding) + { + fbb_.AddElement(Pool2DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) + { + fbb_.AddElement(Pool2DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) + { + fbb_.AddElement(Pool2DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_filter_width(int32_t filter_width) + { + fbb_.AddElement(Pool2DOptions::VT_FILTER_WIDTH, filter_width, 0); + } + void add_filter_height(int32_t filter_height) + { + fbb_.AddElement(Pool2DOptions::VT_FILTER_HEIGHT, filter_height, 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(Pool2DOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit Pool2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + Pool2DOptionsBuilder &operator=(const Pool2DOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreatePool2DOptions(flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME, + int32_t stride_w = 0, int32_t stride_h = 0, int32_t filter_width = 0, + int32_t filter_height = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + Pool2DOptionsBuilder builder_(_fbb); + builder_.add_filter_height(filter_height); + builder_.add_filter_width(filter_width); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +struct DepthwiseConv2DOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8, + VT_DEPTH_MULTIPLIER = 10, + VT_FUSED_ACTIVATION_FUNCTION = 12, + VT_DILATION_W_FACTOR = 14, + VT_DILATION_H_FACTOR = 16 + }; + Padding padding() const { return static_cast(GetField(VT_PADDING, 0)); } + int32_t stride_w() const { return GetField(VT_STRIDE_W, 0); } + int32_t stride_h() const { return GetField(VT_STRIDE_H, 0); } + int32_t depth_multiplier() const { return GetField(VT_DEPTH_MULTIPLIER, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + int32_t dilation_w_factor() const { return GetField(VT_DILATION_W_FACTOR, 1); } + int32_t dilation_h_factor() const { return GetField(VT_DILATION_H_FACTOR, 1); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_PADDING) && + VerifyField(verifier, VT_STRIDE_W) && + VerifyField(verifier, VT_STRIDE_H) && + VerifyField(verifier, VT_DEPTH_MULTIPLIER) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_DILATION_W_FACTOR) && + VerifyField(verifier, VT_DILATION_H_FACTOR) && verifier.EndTable(); + } +}; + +struct DepthwiseConv2DOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(Padding padding) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_STRIDE_H, stride_h, 0); + } + void add_depth_multiplier(int32_t depth_multiplier) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_DEPTH_MULTIPLIER, depth_multiplier, 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_dilation_w_factor(int32_t dilation_w_factor) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_DILATION_W_FACTOR, dilation_w_factor, 1); + } + void add_dilation_h_factor(int32_t dilation_h_factor) + { + fbb_.AddElement(DepthwiseConv2DOptions::VT_DILATION_H_FACTOR, dilation_h_factor, 1); + } + explicit DepthwiseConv2DOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DepthwiseConv2DOptionsBuilder &operator=(const DepthwiseConv2DOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateDepthwiseConv2DOptions( + flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME, int32_t stride_w = 0, + int32_t stride_h = 0, int32_t depth_multiplier = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + int32_t dilation_w_factor = 1, int32_t dilation_h_factor = 1) +{ + DepthwiseConv2DOptionsBuilder builder_(_fbb); + builder_.add_dilation_h_factor(dilation_h_factor); + builder_.add_dilation_w_factor(dilation_w_factor); + builder_.add_depth_multiplier(depth_multiplier); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_padding(padding); + return builder_.Finish(); +} + +struct ConcatEmbeddingsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NUM_CHANNELS = 4, + VT_NUM_COLUMNS_PER_CHANNEL = 6, + VT_EMBEDDING_DIM_PER_CHANNEL = 8 + }; + int32_t num_channels() const { return GetField(VT_NUM_CHANNELS, 0); } + const flatbuffers::Vector *num_columns_per_channel() const + { + return GetPointer *>(VT_NUM_COLUMNS_PER_CHANNEL); + } + const flatbuffers::Vector *embedding_dim_per_channel() const + { + return GetPointer *>(VT_EMBEDDING_DIM_PER_CHANNEL); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NUM_CHANNELS) && + VerifyOffset(verifier, VT_NUM_COLUMNS_PER_CHANNEL) && + verifier.VerifyVector(num_columns_per_channel()) && + VerifyOffset(verifier, VT_EMBEDDING_DIM_PER_CHANNEL) && + verifier.VerifyVector(embedding_dim_per_channel()) && verifier.EndTable(); + } +}; + +struct ConcatEmbeddingsOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_channels(int32_t num_channels) + { + fbb_.AddElement(ConcatEmbeddingsOptions::VT_NUM_CHANNELS, num_channels, 0); + } + void add_num_columns_per_channel( + flatbuffers::Offset> num_columns_per_channel) + { + fbb_.AddOffset(ConcatEmbeddingsOptions::VT_NUM_COLUMNS_PER_CHANNEL, num_columns_per_channel); + } + void add_embedding_dim_per_channel( + flatbuffers::Offset> embedding_dim_per_channel) + { + fbb_.AddOffset(ConcatEmbeddingsOptions::VT_EMBEDDING_DIM_PER_CHANNEL, + embedding_dim_per_channel); + } + explicit ConcatEmbeddingsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ConcatEmbeddingsOptionsBuilder &operator=(const ConcatEmbeddingsOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateConcatEmbeddingsOptions( + flatbuffers::FlatBufferBuilder &_fbb, int32_t num_channels = 0, + flatbuffers::Offset> num_columns_per_channel = 0, + flatbuffers::Offset> embedding_dim_per_channel = 0) +{ + ConcatEmbeddingsOptionsBuilder builder_(_fbb); + builder_.add_embedding_dim_per_channel(embedding_dim_per_channel); + builder_.add_num_columns_per_channel(num_columns_per_channel); + builder_.add_num_channels(num_channels); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateConcatEmbeddingsOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb, int32_t num_channels = 0, + const std::vector *num_columns_per_channel = nullptr, + const std::vector *embedding_dim_per_channel = nullptr) +{ + return onert_tflite::CreateConcatEmbeddingsOptions( + _fbb, num_channels, + num_columns_per_channel ? _fbb.CreateVector(*num_columns_per_channel) : 0, + embedding_dim_per_channel ? _fbb.CreateVector(*embedding_dim_per_channel) : 0); +} + +struct LSHProjectionOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TYPE = 4 + }; + LSHProjectionType type() const + { + return static_cast(GetField(VT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_TYPE) && + verifier.EndTable(); + } +}; + +struct LSHProjectionOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_type(LSHProjectionType type) + { + fbb_.AddElement(LSHProjectionOptions::VT_TYPE, static_cast(type), 0); + } + explicit LSHProjectionOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LSHProjectionOptionsBuilder &operator=(const LSHProjectionOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLSHProjectionOptions(flatbuffers::FlatBufferBuilder &_fbb, + LSHProjectionType type = LSHProjectionType_UNKNOWN) +{ + LSHProjectionOptionsBuilder builder_(_fbb); + builder_.add_type(type); + return builder_.Finish(); +} + +struct SVDFOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_RANK = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 8 + }; + int32_t rank() const { return GetField(VT_RANK, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_RANK) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct SVDFOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_rank(int32_t rank) { fbb_.AddElement(SVDFOptions::VT_RANK, rank, 0); } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(SVDFOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(SVDFOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit SVDFOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SVDFOptionsBuilder &operator=(const SVDFOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSVDFOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t rank = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + bool asymmetric_quantize_inputs = false) +{ + SVDFOptionsBuilder builder_(_fbb); + builder_.add_rank(rank); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct RNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 6 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct RNNOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(RNNOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(RNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit RNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + RNNOptionsBuilder &operator=(const RNNOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateRNNOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + bool asymmetric_quantize_inputs = false) +{ + RNNOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct SequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TIME_MAJOR = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 8 + }; + bool time_major() const { return GetField(VT_TIME_MAJOR, 0) != 0; } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_TIME_MAJOR) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct SequenceRNNOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_time_major(bool time_major) + { + fbb_.AddElement(SequenceRNNOptions::VT_TIME_MAJOR, static_cast(time_major), + 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(SequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(SequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit SequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SequenceRNNOptionsBuilder &operator=(const SequenceRNNOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSequenceRNNOptions( + flatbuffers::FlatBufferBuilder &_fbb, bool time_major = false, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + bool asymmetric_quantize_inputs = false) +{ + SequenceRNNOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_time_major(time_major); + return builder_.Finish(); +} + +struct BidirectionalSequenceRNNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TIME_MAJOR = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6, + VT_MERGE_OUTPUTS = 8, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 10 + }; + bool time_major() const { return GetField(VT_TIME_MAJOR, 0) != 0; } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool merge_outputs() const { return GetField(VT_MERGE_OUTPUTS, 0) != 0; } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_TIME_MAJOR) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_MERGE_OUTPUTS) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct BidirectionalSequenceRNNOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_time_major(bool time_major) + { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_TIME_MAJOR, + static_cast(time_major), 0); + } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_merge_outputs(bool merge_outputs) + { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_MERGE_OUTPUTS, + static_cast(merge_outputs), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(BidirectionalSequenceRNNOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit BidirectionalSequenceRNNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BidirectionalSequenceRNNOptionsBuilder &operator=(const BidirectionalSequenceRNNOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBidirectionalSequenceRNNOptions( + flatbuffers::FlatBufferBuilder &_fbb, bool time_major = false, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + bool merge_outputs = false, bool asymmetric_quantize_inputs = false) +{ + BidirectionalSequenceRNNOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_merge_outputs(merge_outputs); + builder_.add_fused_activation_function(fused_activation_function); + builder_.add_time_major(time_major); + return builder_.Finish(); +} + +struct FullyConnectedOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_WEIGHTS_FORMAT = 6, + VT_KEEP_NUM_DIMS = 8, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 10 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + FullyConnectedOptionsWeightsFormat weights_format() const + { + return static_cast(GetField(VT_WEIGHTS_FORMAT, 0)); + } + bool keep_num_dims() const { return GetField(VT_KEEP_NUM_DIMS, 0) != 0; } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_WEIGHTS_FORMAT) && + VerifyField(verifier, VT_KEEP_NUM_DIMS) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct FullyConnectedOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(FullyConnectedOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_weights_format(FullyConnectedOptionsWeightsFormat weights_format) + { + fbb_.AddElement(FullyConnectedOptions::VT_WEIGHTS_FORMAT, + static_cast(weights_format), 0); + } + void add_keep_num_dims(bool keep_num_dims) + { + fbb_.AddElement(FullyConnectedOptions::VT_KEEP_NUM_DIMS, + static_cast(keep_num_dims), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(FullyConnectedOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit FullyConnectedOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FullyConnectedOptionsBuilder &operator=(const FullyConnectedOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFullyConnectedOptions( + flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + FullyConnectedOptionsWeightsFormat weights_format = FullyConnectedOptionsWeightsFormat_DEFAULT, + bool keep_num_dims = false, bool asymmetric_quantize_inputs = false) +{ + FullyConnectedOptionsBuilder builder_(_fbb); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_keep_num_dims(keep_num_dims); + builder_.add_weights_format(weights_format); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct SoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BETA = 4 + }; + float beta() const { return GetField(VT_BETA, 0.0f); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BETA) && + verifier.EndTable(); + } +}; + +struct SoftmaxOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_beta(float beta) { fbb_.AddElement(SoftmaxOptions::VT_BETA, beta, 0.0f); } + explicit SoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SoftmaxOptionsBuilder &operator=(const SoftmaxOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb, float beta = 0.0f) +{ + SoftmaxOptionsBuilder builder_(_fbb); + builder_.add_beta(beta); + return builder_.Finish(); +} + +struct ConcatenationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_AXIS = 4, + VT_FUSED_ACTIVATION_FUNCTION = 6 + }; + int32_t axis() const { return GetField(VT_AXIS, 0); } + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_AXIS) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct ConcatenationOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(int32_t axis) { fbb_.AddElement(ConcatenationOptions::VT_AXIS, axis, 0); } + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(ConcatenationOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit ConcatenationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ConcatenationOptionsBuilder &operator=(const ConcatenationOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateConcatenationOptions( + flatbuffers::FlatBufferBuilder &_fbb, int32_t axis = 0, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + ConcatenationOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct AddOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct AddOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(AddOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit AddOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + AddOptionsBuilder &operator=(const AddOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateAddOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + AddOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct MulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct MulOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(MulOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit MulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MulOptionsBuilder &operator=(const MulOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMulOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + MulOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct L2NormOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct L2NormOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(L2NormOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit L2NormOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + L2NormOptionsBuilder &operator=(const L2NormOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateL2NormOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + L2NormOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct LocalResponseNormalizationOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_RADIUS = 4, + VT_BIAS = 6, + VT_ALPHA = 8, + VT_BETA = 10 + }; + int32_t radius() const { return GetField(VT_RADIUS, 0); } + float bias() const { return GetField(VT_BIAS, 0.0f); } + float alpha() const { return GetField(VT_ALPHA, 0.0f); } + float beta() const { return GetField(VT_BETA, 0.0f); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_RADIUS) && + VerifyField(verifier, VT_BIAS) && VerifyField(verifier, VT_ALPHA) && + VerifyField(verifier, VT_BETA) && verifier.EndTable(); + } +}; + +struct LocalResponseNormalizationOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_radius(int32_t radius) + { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_RADIUS, radius, 0); + } + void add_bias(float bias) + { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_BIAS, bias, 0.0f); + } + void add_alpha(float alpha) + { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_ALPHA, alpha, 0.0f); + } + void add_beta(float beta) + { + fbb_.AddElement(LocalResponseNormalizationOptions::VT_BETA, beta, 0.0f); + } + explicit LocalResponseNormalizationOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LocalResponseNormalizationOptionsBuilder & + operator=(const LocalResponseNormalizationOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLocalResponseNormalizationOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t radius = 0, + float bias = 0.0f, float alpha = 0.0f, float beta = 0.0f) +{ + LocalResponseNormalizationOptionsBuilder builder_(_fbb); + builder_.add_beta(beta); + builder_.add_alpha(alpha); + builder_.add_bias(bias); + builder_.add_radius(radius); + return builder_.Finish(); +} + +struct LSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_CELL_CLIP = 6, + VT_PROJ_CLIP = 8, + VT_KERNEL_TYPE = 10, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 12 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + float cell_clip() const { return GetField(VT_CELL_CLIP, 0.0f); } + float proj_clip() const { return GetField(VT_PROJ_CLIP, 0.0f); } + LSTMKernelType kernel_type() const + { + return static_cast(GetField(VT_KERNEL_TYPE, 0)); + } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_CELL_CLIP) && + VerifyField(verifier, VT_PROJ_CLIP) && + VerifyField(verifier, VT_KERNEL_TYPE) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct LSTMOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(LSTMOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_cell_clip(float cell_clip) + { + fbb_.AddElement(LSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f); + } + void add_proj_clip(float proj_clip) + { + fbb_.AddElement(LSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f); + } + void add_kernel_type(LSTMKernelType kernel_type) + { + fbb_.AddElement(LSTMOptions::VT_KERNEL_TYPE, static_cast(kernel_type), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(LSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit LSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LSTMOptionsBuilder &operator=(const LSTMOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLSTMOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + float cell_clip = 0.0f, float proj_clip = 0.0f, + LSTMKernelType kernel_type = LSTMKernelType_FULL, + bool asymmetric_quantize_inputs = false) +{ + LSTMOptionsBuilder builder_(_fbb); + builder_.add_proj_clip(proj_clip); + builder_.add_cell_clip(cell_clip); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_kernel_type(kernel_type); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct UnidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_CELL_CLIP = 6, + VT_PROJ_CLIP = 8, + VT_TIME_MAJOR = 10, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 12 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + float cell_clip() const { return GetField(VT_CELL_CLIP, 0.0f); } + float proj_clip() const { return GetField(VT_PROJ_CLIP, 0.0f); } + bool time_major() const { return GetField(VT_TIME_MAJOR, 0) != 0; } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_CELL_CLIP) && + VerifyField(verifier, VT_PROJ_CLIP) && + VerifyField(verifier, VT_TIME_MAJOR) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct UnidirectionalSequenceLSTMOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_cell_clip(float cell_clip) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f); + } + void add_proj_clip(float proj_clip) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f); + } + void add_time_major(bool time_major) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_TIME_MAJOR, + static_cast(time_major), 0); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(UnidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit UnidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + UnidirectionalSequenceLSTMOptionsBuilder & + operator=(const UnidirectionalSequenceLSTMOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateUnidirectionalSequenceLSTMOptions( + flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + float cell_clip = 0.0f, float proj_clip = 0.0f, bool time_major = false, + bool asymmetric_quantize_inputs = false) +{ + UnidirectionalSequenceLSTMOptionsBuilder builder_(_fbb); + builder_.add_proj_clip(proj_clip); + builder_.add_cell_clip(cell_clip); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_time_major(time_major); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct BidirectionalSequenceLSTMOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4, + VT_CELL_CLIP = 6, + VT_PROJ_CLIP = 8, + VT_MERGE_OUTPUTS = 10, + VT_TIME_MAJOR = 12, + VT_ASYMMETRIC_QUANTIZE_INPUTS = 14 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + float cell_clip() const { return GetField(VT_CELL_CLIP, 0.0f); } + float proj_clip() const { return GetField(VT_PROJ_CLIP, 0.0f); } + bool merge_outputs() const { return GetField(VT_MERGE_OUTPUTS, 0) != 0; } + bool time_major() const { return GetField(VT_TIME_MAJOR, 1) != 0; } + bool asymmetric_quantize_inputs() const + { + return GetField(VT_ASYMMETRIC_QUANTIZE_INPUTS, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && + VerifyField(verifier, VT_CELL_CLIP) && + VerifyField(verifier, VT_PROJ_CLIP) && + VerifyField(verifier, VT_MERGE_OUTPUTS) && + VerifyField(verifier, VT_TIME_MAJOR) && + VerifyField(verifier, VT_ASYMMETRIC_QUANTIZE_INPUTS) && verifier.EndTable(); + } +}; + +struct BidirectionalSequenceLSTMOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + void add_cell_clip(float cell_clip) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_CELL_CLIP, cell_clip, 0.0f); + } + void add_proj_clip(float proj_clip) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_PROJ_CLIP, proj_clip, 0.0f); + } + void add_merge_outputs(bool merge_outputs) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_MERGE_OUTPUTS, + static_cast(merge_outputs), 0); + } + void add_time_major(bool time_major) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_TIME_MAJOR, + static_cast(time_major), 1); + } + void add_asymmetric_quantize_inputs(bool asymmetric_quantize_inputs) + { + fbb_.AddElement(BidirectionalSequenceLSTMOptions::VT_ASYMMETRIC_QUANTIZE_INPUTS, + static_cast(asymmetric_quantize_inputs), 0); + } + explicit BidirectionalSequenceLSTMOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BidirectionalSequenceLSTMOptionsBuilder & + operator=(const BidirectionalSequenceLSTMOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateBidirectionalSequenceLSTMOptions( + flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE, + float cell_clip = 0.0f, float proj_clip = 0.0f, bool merge_outputs = false, + bool time_major = true, bool asymmetric_quantize_inputs = false) +{ + BidirectionalSequenceLSTMOptionsBuilder builder_(_fbb); + builder_.add_proj_clip(proj_clip); + builder_.add_cell_clip(cell_clip); + builder_.add_asymmetric_quantize_inputs(asymmetric_quantize_inputs); + builder_.add_time_major(time_major); + builder_.add_merge_outputs(merge_outputs); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct ResizeBilinearOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_ALIGN_CORNERS = 8, + VT_HALF_PIXEL_CENTERS = 10 + }; + bool align_corners() const { return GetField(VT_ALIGN_CORNERS, 0) != 0; } + bool half_pixel_centers() const { return GetField(VT_HALF_PIXEL_CENTERS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_ALIGN_CORNERS) && + VerifyField(verifier, VT_HALF_PIXEL_CENTERS) && verifier.EndTable(); + } +}; + +struct ResizeBilinearOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_align_corners(bool align_corners) + { + fbb_.AddElement(ResizeBilinearOptions::VT_ALIGN_CORNERS, + static_cast(align_corners), 0); + } + void add_half_pixel_centers(bool half_pixel_centers) + { + fbb_.AddElement(ResizeBilinearOptions::VT_HALF_PIXEL_CENTERS, + static_cast(half_pixel_centers), 0); + } + explicit ResizeBilinearOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ResizeBilinearOptionsBuilder &operator=(const ResizeBilinearOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateResizeBilinearOptions(flatbuffers::FlatBufferBuilder &_fbb, bool align_corners = false, + bool half_pixel_centers = false) +{ + ResizeBilinearOptionsBuilder builder_(_fbb); + builder_.add_half_pixel_centers(half_pixel_centers); + builder_.add_align_corners(align_corners); + return builder_.Finish(); +} + +struct ResizeNearestNeighborOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_ALIGN_CORNERS = 4 + }; + bool align_corners() const { return GetField(VT_ALIGN_CORNERS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_ALIGN_CORNERS) && + verifier.EndTable(); + } +}; + +struct ResizeNearestNeighborOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_align_corners(bool align_corners) + { + fbb_.AddElement(ResizeNearestNeighborOptions::VT_ALIGN_CORNERS, + static_cast(align_corners), 0); + } + explicit ResizeNearestNeighborOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ResizeNearestNeighborOptionsBuilder &operator=(const ResizeNearestNeighborOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateResizeNearestNeighborOptions(flatbuffers::FlatBufferBuilder &_fbb, bool align_corners = false) +{ + ResizeNearestNeighborOptionsBuilder builder_(_fbb); + builder_.add_align_corners(align_corners); + return builder_.Finish(); +} + +struct CallOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_SUBGRAPH = 4 + }; + uint32_t subgraph() const { return GetField(VT_SUBGRAPH, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_SUBGRAPH) && + verifier.EndTable(); + } +}; + +struct CallOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_subgraph(uint32_t subgraph) + { + fbb_.AddElement(CallOptions::VT_SUBGRAPH, subgraph, 0); + } + explicit CallOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + CallOptionsBuilder &operator=(const CallOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCallOptions(flatbuffers::FlatBufferBuilder &_fbb, + uint32_t subgraph = 0) +{ + CallOptionsBuilder builder_(_fbb); + builder_.add_subgraph(subgraph); + return builder_.Finish(); +} + +struct PadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct PadOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit PadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + PadOptionsBuilder &operator=(const PadOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePadOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + PadOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct PadV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct PadV2OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit PadV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + PadV2OptionsBuilder &operator=(const PadV2OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePadV2Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + PadV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ReshapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NEW_SHAPE = 4 + }; + const flatbuffers::Vector *new_shape() const + { + return GetPointer *>(VT_NEW_SHAPE); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NEW_SHAPE) && + verifier.VerifyVector(new_shape()) && verifier.EndTable(); + } +}; + +struct ReshapeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_new_shape(flatbuffers::Offset> new_shape) + { + fbb_.AddOffset(ReshapeOptions::VT_NEW_SHAPE, new_shape); + } + explicit ReshapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ReshapeOptionsBuilder &operator=(const ReshapeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateReshapeOptions(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> new_shape = 0) +{ + ReshapeOptionsBuilder builder_(_fbb); + builder_.add_new_shape(new_shape); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateReshapeOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *new_shape = nullptr) +{ + return onert_tflite::CreateReshapeOptions(_fbb, + new_shape ? _fbb.CreateVector(*new_shape) : 0); +} + +struct SpaceToBatchNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SpaceToBatchNDOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SpaceToBatchNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SpaceToBatchNDOptionsBuilder &operator=(const SpaceToBatchNDOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSpaceToBatchNDOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SpaceToBatchNDOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct BatchToSpaceNDOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct BatchToSpaceNDOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit BatchToSpaceNDOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BatchToSpaceNDOptionsBuilder &operator=(const BatchToSpaceNDOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateBatchToSpaceNDOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + BatchToSpaceNDOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SkipGramOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NGRAM_SIZE = 4, + VT_MAX_SKIP_SIZE = 6, + VT_INCLUDE_ALL_NGRAMS = 8 + }; + int32_t ngram_size() const { return GetField(VT_NGRAM_SIZE, 0); } + int32_t max_skip_size() const { return GetField(VT_MAX_SKIP_SIZE, 0); } + bool include_all_ngrams() const { return GetField(VT_INCLUDE_ALL_NGRAMS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NGRAM_SIZE) && + VerifyField(verifier, VT_MAX_SKIP_SIZE) && + VerifyField(verifier, VT_INCLUDE_ALL_NGRAMS) && verifier.EndTable(); + } +}; + +struct SkipGramOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_ngram_size(int32_t ngram_size) + { + fbb_.AddElement(SkipGramOptions::VT_NGRAM_SIZE, ngram_size, 0); + } + void add_max_skip_size(int32_t max_skip_size) + { + fbb_.AddElement(SkipGramOptions::VT_MAX_SKIP_SIZE, max_skip_size, 0); + } + void add_include_all_ngrams(bool include_all_ngrams) + { + fbb_.AddElement(SkipGramOptions::VT_INCLUDE_ALL_NGRAMS, + static_cast(include_all_ngrams), 0); + } + explicit SkipGramOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SkipGramOptionsBuilder &operator=(const SkipGramOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSkipGramOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t ngram_size = 0, + int32_t max_skip_size = 0, bool include_all_ngrams = false) +{ + SkipGramOptionsBuilder builder_(_fbb); + builder_.add_max_skip_size(max_skip_size); + builder_.add_ngram_size(ngram_size); + builder_.add_include_all_ngrams(include_all_ngrams); + return builder_.Finish(); +} + +struct SpaceToDepthOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BLOCK_SIZE = 4 + }; + int32_t block_size() const { return GetField(VT_BLOCK_SIZE, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BLOCK_SIZE) && + verifier.EndTable(); + } +}; + +struct SpaceToDepthOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_block_size(int32_t block_size) + { + fbb_.AddElement(SpaceToDepthOptions::VT_BLOCK_SIZE, block_size, 0); + } + explicit SpaceToDepthOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SpaceToDepthOptionsBuilder &operator=(const SpaceToDepthOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSpaceToDepthOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t block_size = 0) +{ + SpaceToDepthOptionsBuilder builder_(_fbb); + builder_.add_block_size(block_size); + return builder_.Finish(); +} + +struct DepthToSpaceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BLOCK_SIZE = 4 + }; + int32_t block_size() const { return GetField(VT_BLOCK_SIZE, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BLOCK_SIZE) && + verifier.EndTable(); + } +}; + +struct DepthToSpaceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_block_size(int32_t block_size) + { + fbb_.AddElement(DepthToSpaceOptions::VT_BLOCK_SIZE, block_size, 0); + } + explicit DepthToSpaceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DepthToSpaceOptionsBuilder &operator=(const DepthToSpaceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDepthToSpaceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t block_size = 0) +{ + DepthToSpaceOptionsBuilder builder_(_fbb); + builder_.add_block_size(block_size); + return builder_.Finish(); +} + +struct SubOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct SubOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(SubOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit SubOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SubOptionsBuilder &operator=(const SubOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSubOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + SubOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct DivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_FUSED_ACTIVATION_FUNCTION = 4 + }; + ActivationFunctionType fused_activation_function() const + { + return static_cast(GetField(VT_FUSED_ACTIVATION_FUNCTION, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && + VerifyField(verifier, VT_FUSED_ACTIVATION_FUNCTION) && verifier.EndTable(); + } +}; + +struct DivOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_fused_activation_function(ActivationFunctionType fused_activation_function) + { + fbb_.AddElement(DivOptions::VT_FUSED_ACTIVATION_FUNCTION, + static_cast(fused_activation_function), 0); + } + explicit DivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DivOptionsBuilder &operator=(const DivOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDivOptions(flatbuffers::FlatBufferBuilder &_fbb, + ActivationFunctionType fused_activation_function = ActivationFunctionType_NONE) +{ + DivOptionsBuilder builder_(_fbb); + builder_.add_fused_activation_function(fused_activation_function); + return builder_.Finish(); +} + +struct TopKV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct TopKV2OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit TopKV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TopKV2OptionsBuilder &operator=(const TopKV2OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTopKV2Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + TopKV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct EmbeddingLookupSparseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_COMBINER = 4 + }; + CombinerType combiner() const + { + return static_cast(GetField(VT_COMBINER, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_COMBINER) && + verifier.EndTable(); + } +}; + +struct EmbeddingLookupSparseOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_combiner(CombinerType combiner) + { + fbb_.AddElement(EmbeddingLookupSparseOptions::VT_COMBINER, + static_cast(combiner), 0); + } + explicit EmbeddingLookupSparseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + EmbeddingLookupSparseOptionsBuilder &operator=(const EmbeddingLookupSparseOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateEmbeddingLookupSparseOptions(flatbuffers::FlatBufferBuilder &_fbb, + CombinerType combiner = CombinerType_SUM) +{ + EmbeddingLookupSparseOptionsBuilder builder_(_fbb); + builder_.add_combiner(combiner); + return builder_.Finish(); +} + +struct GatherOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_AXIS = 4 + }; + int32_t axis() const { return GetField(VT_AXIS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_AXIS) && + verifier.EndTable(); + } +}; + +struct GatherOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(int32_t axis) { fbb_.AddElement(GatherOptions::VT_AXIS, axis, 0); } + explicit GatherOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + GatherOptionsBuilder &operator=(const GatherOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateGatherOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t axis = 0) +{ + GatherOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + return builder_.Finish(); +} + +struct TransposeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct TransposeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit TransposeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TransposeOptionsBuilder &operator=(const TransposeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateTransposeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + TransposeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ExpOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ExpOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ExpOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ExpOptionsBuilder &operator=(const ExpOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateExpOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + ExpOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct CosOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct CosOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit CosOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + CosOptionsBuilder &operator=(const CosOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateCosOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + CosOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ReducerOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_KEEP_DIMS = 4 + }; + bool keep_dims() const { return GetField(VT_KEEP_DIMS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_KEEP_DIMS) && + verifier.EndTable(); + } +}; + +struct ReducerOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_keep_dims(bool keep_dims) + { + fbb_.AddElement(ReducerOptions::VT_KEEP_DIMS, static_cast(keep_dims), 0); + } + explicit ReducerOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ReducerOptionsBuilder &operator=(const ReducerOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateReducerOptions(flatbuffers::FlatBufferBuilder &_fbb, bool keep_dims = false) +{ + ReducerOptionsBuilder builder_(_fbb); + builder_.add_keep_dims(keep_dims); + return builder_.Finish(); +} + +struct SqueezeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_SQUEEZE_DIMS = 4 + }; + const flatbuffers::Vector *squeeze_dims() const + { + return GetPointer *>(VT_SQUEEZE_DIMS); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_SQUEEZE_DIMS) && + verifier.VerifyVector(squeeze_dims()) && verifier.EndTable(); + } +}; + +struct SqueezeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_squeeze_dims(flatbuffers::Offset> squeeze_dims) + { + fbb_.AddOffset(SqueezeOptions::VT_SQUEEZE_DIMS, squeeze_dims); + } + explicit SqueezeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SqueezeOptionsBuilder &operator=(const SqueezeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSqueezeOptions(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> squeeze_dims = 0) +{ + SqueezeOptionsBuilder builder_(_fbb); + builder_.add_squeeze_dims(squeeze_dims); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateSqueezeOptionsDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *squeeze_dims = nullptr) +{ + return onert_tflite::CreateSqueezeOptions( + _fbb, squeeze_dims ? _fbb.CreateVector(*squeeze_dims) : 0); +} + +struct SplitOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NUM_SPLITS = 4 + }; + int32_t num_splits() const { return GetField(VT_NUM_SPLITS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NUM_SPLITS) && + verifier.EndTable(); + } +}; + +struct SplitOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_splits(int32_t num_splits) + { + fbb_.AddElement(SplitOptions::VT_NUM_SPLITS, num_splits, 0); + } + explicit SplitOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SplitOptionsBuilder &operator=(const SplitOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSplitOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t num_splits = 0) +{ + SplitOptionsBuilder builder_(_fbb); + builder_.add_num_splits(num_splits); + return builder_.Finish(); +} + +struct SplitVOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NUM_SPLITS = 4 + }; + int32_t num_splits() const { return GetField(VT_NUM_SPLITS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NUM_SPLITS) && + verifier.EndTable(); + } +}; + +struct SplitVOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num_splits(int32_t num_splits) + { + fbb_.AddElement(SplitVOptions::VT_NUM_SPLITS, num_splits, 0); + } + explicit SplitVOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SplitVOptionsBuilder &operator=(const SplitVOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSplitVOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t num_splits = 0) +{ + SplitVOptionsBuilder builder_(_fbb); + builder_.add_num_splits(num_splits); + return builder_.Finish(); +} + +struct StridedSliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BEGIN_MASK = 4, + VT_END_MASK = 6, + VT_ELLIPSIS_MASK = 8, + VT_NEW_AXIS_MASK = 10, + VT_SHRINK_AXIS_MASK = 12 + }; + int32_t begin_mask() const { return GetField(VT_BEGIN_MASK, 0); } + int32_t end_mask() const { return GetField(VT_END_MASK, 0); } + int32_t ellipsis_mask() const { return GetField(VT_ELLIPSIS_MASK, 0); } + int32_t new_axis_mask() const { return GetField(VT_NEW_AXIS_MASK, 0); } + int32_t shrink_axis_mask() const { return GetField(VT_SHRINK_AXIS_MASK, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BEGIN_MASK) && + VerifyField(verifier, VT_END_MASK) && + VerifyField(verifier, VT_ELLIPSIS_MASK) && + VerifyField(verifier, VT_NEW_AXIS_MASK) && + VerifyField(verifier, VT_SHRINK_AXIS_MASK) && verifier.EndTable(); + } +}; + +struct StridedSliceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_begin_mask(int32_t begin_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_BEGIN_MASK, begin_mask, 0); + } + void add_end_mask(int32_t end_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_END_MASK, end_mask, 0); + } + void add_ellipsis_mask(int32_t ellipsis_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_ELLIPSIS_MASK, ellipsis_mask, 0); + } + void add_new_axis_mask(int32_t new_axis_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_NEW_AXIS_MASK, new_axis_mask, 0); + } + void add_shrink_axis_mask(int32_t shrink_axis_mask) + { + fbb_.AddElement(StridedSliceOptions::VT_SHRINK_AXIS_MASK, shrink_axis_mask, 0); + } + explicit StridedSliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + StridedSliceOptionsBuilder &operator=(const StridedSliceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateStridedSliceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t begin_mask = 0, + int32_t end_mask = 0, int32_t ellipsis_mask = 0, + int32_t new_axis_mask = 0, int32_t shrink_axis_mask = 0) +{ + StridedSliceOptionsBuilder builder_(_fbb); + builder_.add_shrink_axis_mask(shrink_axis_mask); + builder_.add_new_axis_mask(new_axis_mask); + builder_.add_ellipsis_mask(ellipsis_mask); + builder_.add_end_mask(end_mask); + builder_.add_begin_mask(begin_mask); + return builder_.Finish(); +} + +struct LogSoftmaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LogSoftmaxOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogSoftmaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LogSoftmaxOptionsBuilder &operator=(const LogSoftmaxOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLogSoftmaxOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LogSoftmaxOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct CastOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_IN_DATA_TYPE = 4, + VT_OUT_DATA_TYPE = 6 + }; + TensorType in_data_type() const + { + return static_cast(GetField(VT_IN_DATA_TYPE, 0)); + } + TensorType out_data_type() const + { + return static_cast(GetField(VT_OUT_DATA_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_IN_DATA_TYPE) && + VerifyField(verifier, VT_OUT_DATA_TYPE) && verifier.EndTable(); + } +}; + +struct CastOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_in_data_type(TensorType in_data_type) + { + fbb_.AddElement(CastOptions::VT_IN_DATA_TYPE, static_cast(in_data_type), 0); + } + void add_out_data_type(TensorType out_data_type) + { + fbb_.AddElement(CastOptions::VT_OUT_DATA_TYPE, static_cast(out_data_type), 0); + } + explicit CastOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + CastOptionsBuilder &operator=(const CastOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateCastOptions(flatbuffers::FlatBufferBuilder &_fbb, + TensorType in_data_type = TensorType_FLOAT32, + TensorType out_data_type = TensorType_FLOAT32) +{ + CastOptionsBuilder builder_(_fbb); + builder_.add_out_data_type(out_data_type); + builder_.add_in_data_type(in_data_type); + return builder_.Finish(); +} + +struct DequantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct DequantizeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit DequantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DequantizeOptionsBuilder &operator=(const DequantizeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDequantizeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + DequantizeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct MaximumMinimumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct MaximumMinimumOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit MaximumMinimumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MaximumMinimumOptionsBuilder &operator=(const MaximumMinimumOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMaximumMinimumOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + MaximumMinimumOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct TileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct TileOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit TileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TileOptionsBuilder &operator=(const TileOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateTileOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + TileOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ArgMaxOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_OUTPUT_TYPE = 4 + }; + TensorType output_type() const + { + return static_cast(GetField(VT_OUTPUT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_OUTPUT_TYPE) && + verifier.EndTable(); + } +}; + +struct ArgMaxOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_output_type(TensorType output_type) + { + fbb_.AddElement(ArgMaxOptions::VT_OUTPUT_TYPE, static_cast(output_type), 0); + } + explicit ArgMaxOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ArgMaxOptionsBuilder &operator=(const ArgMaxOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateArgMaxOptions(flatbuffers::FlatBufferBuilder &_fbb, + TensorType output_type = TensorType_FLOAT32) +{ + ArgMaxOptionsBuilder builder_(_fbb); + builder_.add_output_type(output_type); + return builder_.Finish(); +} + +struct ArgMinOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_OUTPUT_TYPE = 4 + }; + TensorType output_type() const + { + return static_cast(GetField(VT_OUTPUT_TYPE, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_OUTPUT_TYPE) && + verifier.EndTable(); + } +}; + +struct ArgMinOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_output_type(TensorType output_type) + { + fbb_.AddElement(ArgMinOptions::VT_OUTPUT_TYPE, static_cast(output_type), 0); + } + explicit ArgMinOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ArgMinOptionsBuilder &operator=(const ArgMinOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateArgMinOptions(flatbuffers::FlatBufferBuilder &_fbb, + TensorType output_type = TensorType_FLOAT32) +{ + ArgMinOptionsBuilder builder_(_fbb); + builder_.add_output_type(output_type); + return builder_.Finish(); +} + +struct GreaterOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct GreaterOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit GreaterOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + GreaterOptionsBuilder &operator=(const GreaterOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateGreaterOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + GreaterOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct GreaterEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct GreaterEqualOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit GreaterEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + GreaterEqualOptionsBuilder &operator=(const GreaterEqualOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateGreaterEqualOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + GreaterEqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LessOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LessOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LessOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LessOptionsBuilder &operator=(const LessOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateLessOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LessOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LessEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LessEqualOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LessEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LessEqualOptionsBuilder &operator=(const LessEqualOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLessEqualOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LessEqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct NegOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct NegOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NegOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + NegOptionsBuilder &operator=(const NegOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateNegOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + NegOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SelectOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SelectOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SelectOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SelectOptionsBuilder &operator=(const SelectOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSelectOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SelectOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SliceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SliceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SliceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SliceOptionsBuilder &operator=(const SliceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSliceOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SliceOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct TransposeConvOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_PADDING = 4, + VT_STRIDE_W = 6, + VT_STRIDE_H = 8 + }; + Padding padding() const { return static_cast(GetField(VT_PADDING, 0)); } + int32_t stride_w() const { return GetField(VT_STRIDE_W, 0); } + int32_t stride_h() const { return GetField(VT_STRIDE_H, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_PADDING) && + VerifyField(verifier, VT_STRIDE_W) && + VerifyField(verifier, VT_STRIDE_H) && verifier.EndTable(); + } +}; + +struct TransposeConvOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_padding(Padding padding) + { + fbb_.AddElement(TransposeConvOptions::VT_PADDING, static_cast(padding), 0); + } + void add_stride_w(int32_t stride_w) + { + fbb_.AddElement(TransposeConvOptions::VT_STRIDE_W, stride_w, 0); + } + void add_stride_h(int32_t stride_h) + { + fbb_.AddElement(TransposeConvOptions::VT_STRIDE_H, stride_h, 0); + } + explicit TransposeConvOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + TransposeConvOptionsBuilder &operator=(const TransposeConvOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateTransposeConvOptions(flatbuffers::FlatBufferBuilder &_fbb, Padding padding = Padding_SAME, + int32_t stride_w = 0, int32_t stride_h = 0) +{ + TransposeConvOptionsBuilder builder_(_fbb); + builder_.add_stride_h(stride_h); + builder_.add_stride_w(stride_w); + builder_.add_padding(padding); + return builder_.Finish(); +} + +struct ExpandDimsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ExpandDimsOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ExpandDimsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ExpandDimsOptionsBuilder &operator=(const ExpandDimsOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateExpandDimsOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + ExpandDimsOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SparseToDenseOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALIDATE_INDICES = 4 + }; + bool validate_indices() const { return GetField(VT_VALIDATE_INDICES, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_VALIDATE_INDICES) && + verifier.EndTable(); + } +}; + +struct SparseToDenseOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_validate_indices(bool validate_indices) + { + fbb_.AddElement(SparseToDenseOptions::VT_VALIDATE_INDICES, + static_cast(validate_indices), 0); + } + explicit SparseToDenseOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SparseToDenseOptionsBuilder &operator=(const SparseToDenseOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSparseToDenseOptions(flatbuffers::FlatBufferBuilder &_fbb, bool validate_indices = false) +{ + SparseToDenseOptionsBuilder builder_(_fbb); + builder_.add_validate_indices(validate_indices); + return builder_.Finish(); +} + +struct EqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct EqualOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit EqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + EqualOptionsBuilder &operator=(const EqualOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateEqualOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + EqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct NotEqualOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct NotEqualOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NotEqualOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + NotEqualOptionsBuilder &operator=(const NotEqualOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateNotEqualOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + NotEqualOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ShapeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_OUT_TYPE = 4 + }; + TensorType out_type() const { return static_cast(GetField(VT_OUT_TYPE, 0)); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_OUT_TYPE) && + verifier.EndTable(); + } +}; + +struct ShapeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_out_type(TensorType out_type) + { + fbb_.AddElement(ShapeOptions::VT_OUT_TYPE, static_cast(out_type), 0); + } + explicit ShapeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ShapeOptionsBuilder &operator=(const ShapeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateShapeOptions(flatbuffers::FlatBufferBuilder &_fbb, TensorType out_type = TensorType_FLOAT32) +{ + ShapeOptionsBuilder builder_(_fbb); + builder_.add_out_type(out_type); + return builder_.Finish(); +} + +struct RankOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct RankOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit RankOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + RankOptionsBuilder &operator=(const RankOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRankOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + RankOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct PowOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct PowOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit PowOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + PowOptionsBuilder &operator=(const PowOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreatePowOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + PowOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct FakeQuantOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_MIN = 4, + VT_MAX = 6, + VT_NUM_BITS = 8, + VT_NARROW_RANGE = 10 + }; + float min() const { return GetField(VT_MIN, 0.0f); } + float max() const { return GetField(VT_MAX, 0.0f); } + int32_t num_bits() const { return GetField(VT_NUM_BITS, 0); } + bool narrow_range() const { return GetField(VT_NARROW_RANGE, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_MIN) && + VerifyField(verifier, VT_MAX) && VerifyField(verifier, VT_NUM_BITS) && + VerifyField(verifier, VT_NARROW_RANGE) && verifier.EndTable(); + } +}; + +struct FakeQuantOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_min(float min) { fbb_.AddElement(FakeQuantOptions::VT_MIN, min, 0.0f); } + void add_max(float max) { fbb_.AddElement(FakeQuantOptions::VT_MAX, max, 0.0f); } + void add_num_bits(int32_t num_bits) + { + fbb_.AddElement(FakeQuantOptions::VT_NUM_BITS, num_bits, 0); + } + void add_narrow_range(bool narrow_range) + { + fbb_.AddElement(FakeQuantOptions::VT_NARROW_RANGE, static_cast(narrow_range), + 0); + } + explicit FakeQuantOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FakeQuantOptionsBuilder &operator=(const FakeQuantOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateFakeQuantOptions(flatbuffers::FlatBufferBuilder &_fbb, float min = 0.0f, float max = 0.0f, + int32_t num_bits = 0, bool narrow_range = false) +{ + FakeQuantOptionsBuilder builder_(_fbb); + builder_.add_num_bits(num_bits); + builder_.add_max(max); + builder_.add_min(min); + builder_.add_narrow_range(narrow_range); + return builder_.Finish(); +} + +struct PackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VALUES_COUNT = 4, + VT_AXIS = 6 + }; + int32_t values_count() const { return GetField(VT_VALUES_COUNT, 0); } + int32_t axis() const { return GetField(VT_AXIS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_VALUES_COUNT) && + VerifyField(verifier, VT_AXIS) && verifier.EndTable(); + } +}; + +struct PackOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_values_count(int32_t values_count) + { + fbb_.AddElement(PackOptions::VT_VALUES_COUNT, values_count, 0); + } + void add_axis(int32_t axis) { fbb_.AddElement(PackOptions::VT_AXIS, axis, 0); } + explicit PackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + PackOptionsBuilder &operator=(const PackOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreatePackOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t values_count = 0, int32_t axis = 0) +{ + PackOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + builder_.add_values_count(values_count); + return builder_.Finish(); +} + +struct LogicalOrOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LogicalOrOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogicalOrOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LogicalOrOptionsBuilder &operator=(const LogicalOrOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLogicalOrOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LogicalOrOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct OneHotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_AXIS = 4 + }; + int32_t axis() const { return GetField(VT_AXIS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_AXIS) && + verifier.EndTable(); + } +}; + +struct OneHotOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_axis(int32_t axis) { fbb_.AddElement(OneHotOptions::VT_AXIS, axis, 0); } + explicit OneHotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + OneHotOptionsBuilder &operator=(const OneHotOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateOneHotOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t axis = 0) +{ + OneHotOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + return builder_.Finish(); +} + +struct AbsOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct AbsOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit AbsOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + AbsOptionsBuilder &operator=(const AbsOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAbsOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + AbsOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct HardSwishOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct HardSwishOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit HardSwishOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + HardSwishOptionsBuilder &operator=(const HardSwishOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateHardSwishOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + HardSwishOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LogicalAndOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LogicalAndOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogicalAndOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LogicalAndOptionsBuilder &operator=(const LogicalAndOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLogicalAndOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LogicalAndOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LogicalNotOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct LogicalNotOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit LogicalNotOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LogicalNotOptionsBuilder &operator=(const LogicalNotOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLogicalNotOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + LogicalNotOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct UnpackOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NUM = 4, + VT_AXIS = 6 + }; + int32_t num() const { return GetField(VT_NUM, 0); } + int32_t axis() const { return GetField(VT_AXIS, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_NUM) && + VerifyField(verifier, VT_AXIS) && verifier.EndTable(); + } +}; + +struct UnpackOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_num(int32_t num) { fbb_.AddElement(UnpackOptions::VT_NUM, num, 0); } + void add_axis(int32_t axis) { fbb_.AddElement(UnpackOptions::VT_AXIS, axis, 0); } + explicit UnpackOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + UnpackOptionsBuilder &operator=(const UnpackOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateUnpackOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t num = 0, int32_t axis = 0) +{ + UnpackOptionsBuilder builder_(_fbb); + builder_.add_axis(axis); + builder_.add_num(num); + return builder_.Finish(); +} + +struct FloorDivOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct FloorDivOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit FloorDivOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FloorDivOptionsBuilder &operator=(const FloorDivOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateFloorDivOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + FloorDivOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SquareOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SquareOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SquareOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SquareOptionsBuilder &operator=(const SquareOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSquareOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SquareOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ZerosLikeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ZerosLikeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ZerosLikeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ZerosLikeOptionsBuilder &operator=(const ZerosLikeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateZerosLikeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + ZerosLikeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct FillOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct FillOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit FillOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FillOptionsBuilder &operator=(const FillOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateFillOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + FillOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct FloorModOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct FloorModOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit FloorModOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + FloorModOptionsBuilder &operator=(const FloorModOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateFloorModOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + FloorModOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct RangeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct RangeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit RangeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + RangeOptionsBuilder &operator=(const RangeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateRangeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + RangeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct LeakyReluOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_ALPHA = 4 + }; + float alpha() const { return GetField(VT_ALPHA, 0.0f); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_ALPHA) && + verifier.EndTable(); + } +}; + +struct LeakyReluOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_alpha(float alpha) { fbb_.AddElement(LeakyReluOptions::VT_ALPHA, alpha, 0.0f); } + explicit LeakyReluOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + LeakyReluOptionsBuilder &operator=(const LeakyReluOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateLeakyReluOptions(flatbuffers::FlatBufferBuilder &_fbb, float alpha = 0.0f) +{ + LeakyReluOptionsBuilder builder_(_fbb); + builder_.add_alpha(alpha); + return builder_.Finish(); +} + +struct SquaredDifferenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SquaredDifferenceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SquaredDifferenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SquaredDifferenceOptionsBuilder &operator=(const SquaredDifferenceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSquaredDifferenceOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SquaredDifferenceOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct MirrorPadOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_MODE = 4 + }; + MirrorPadMode mode() const { return static_cast(GetField(VT_MODE, 0)); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_MODE) && + verifier.EndTable(); + } +}; + +struct MirrorPadOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_mode(MirrorPadMode mode) + { + fbb_.AddElement(MirrorPadOptions::VT_MODE, static_cast(mode), 0); + } + explicit MirrorPadOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MirrorPadOptionsBuilder &operator=(const MirrorPadOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMirrorPadOptions(flatbuffers::FlatBufferBuilder &_fbb, + MirrorPadMode mode = MirrorPadMode_REFLECT) +{ + MirrorPadOptionsBuilder builder_(_fbb); + builder_.add_mode(mode); + return builder_.Finish(); +} + +struct UniqueOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_IDX_OUT_TYPE = 4 + }; + TensorType idx_out_type() const + { + return static_cast(GetField(VT_IDX_OUT_TYPE, 2)); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_IDX_OUT_TYPE) && + verifier.EndTable(); + } +}; + +struct UniqueOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_idx_out_type(TensorType idx_out_type) + { + fbb_.AddElement(UniqueOptions::VT_IDX_OUT_TYPE, static_cast(idx_out_type), 2); + } + explicit UniqueOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + UniqueOptionsBuilder &operator=(const UniqueOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateUniqueOptions(flatbuffers::FlatBufferBuilder &_fbb, + TensorType idx_out_type = TensorType_INT32) +{ + UniqueOptionsBuilder builder_(_fbb); + builder_.add_idx_out_type(idx_out_type); + return builder_.Finish(); +} + +struct ReverseV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ReverseV2OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ReverseV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ReverseV2OptionsBuilder &operator=(const ReverseV2OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateReverseV2Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + ReverseV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct AddNOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct AddNOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit AddNOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + AddNOptionsBuilder &operator=(const AddNOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateAddNOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + AddNOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct GatherNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct GatherNdOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit GatherNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + GatherNdOptionsBuilder &operator=(const GatherNdOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateGatherNdOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + GatherNdOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct WhereOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct WhereOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit WhereOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + WhereOptionsBuilder &operator=(const WhereOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateWhereOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + WhereOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ReverseSequenceOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_SEQ_DIM = 4, + VT_BATCH_DIM = 6 + }; + int32_t seq_dim() const { return GetField(VT_SEQ_DIM, 0); } + int32_t batch_dim() const { return GetField(VT_BATCH_DIM, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_SEQ_DIM) && + VerifyField(verifier, VT_BATCH_DIM) && verifier.EndTable(); + } +}; + +struct ReverseSequenceOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_seq_dim(int32_t seq_dim) + { + fbb_.AddElement(ReverseSequenceOptions::VT_SEQ_DIM, seq_dim, 0); + } + void add_batch_dim(int32_t batch_dim) + { + fbb_.AddElement(ReverseSequenceOptions::VT_BATCH_DIM, batch_dim, 0); + } + explicit ReverseSequenceOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ReverseSequenceOptionsBuilder &operator=(const ReverseSequenceOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateReverseSequenceOptions(flatbuffers::FlatBufferBuilder &_fbb, int32_t seq_dim = 0, + int32_t batch_dim = 0) +{ + ReverseSequenceOptionsBuilder builder_(_fbb); + builder_.add_batch_dim(batch_dim); + builder_.add_seq_dim(seq_dim); + return builder_.Finish(); +} + +struct MatrixDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct MatrixDiagOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit MatrixDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MatrixDiagOptionsBuilder &operator=(const MatrixDiagOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMatrixDiagOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + MatrixDiagOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct QuantizeOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct QuantizeOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit QuantizeOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + QuantizeOptionsBuilder &operator=(const QuantizeOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateQuantizeOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + QuantizeOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct MatrixSetDiagOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct MatrixSetDiagOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit MatrixSetDiagOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MatrixSetDiagOptionsBuilder &operator=(const MatrixSetDiagOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMatrixSetDiagOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + MatrixSetDiagOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct IfOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_THEN_SUBGRAPH_INDEX = 4, + VT_ELSE_SUBGRAPH_INDEX = 6 + }; + int32_t then_subgraph_index() const { return GetField(VT_THEN_SUBGRAPH_INDEX, 0); } + int32_t else_subgraph_index() const { return GetField(VT_ELSE_SUBGRAPH_INDEX, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_THEN_SUBGRAPH_INDEX) && + VerifyField(verifier, VT_ELSE_SUBGRAPH_INDEX) && verifier.EndTable(); + } +}; + +struct IfOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_then_subgraph_index(int32_t then_subgraph_index) + { + fbb_.AddElement(IfOptions::VT_THEN_SUBGRAPH_INDEX, then_subgraph_index, 0); + } + void add_else_subgraph_index(int32_t else_subgraph_index) + { + fbb_.AddElement(IfOptions::VT_ELSE_SUBGRAPH_INDEX, else_subgraph_index, 0); + } + explicit IfOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + IfOptionsBuilder &operator=(const IfOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateIfOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t then_subgraph_index = 0, + int32_t else_subgraph_index = 0) +{ + IfOptionsBuilder builder_(_fbb); + builder_.add_else_subgraph_index(else_subgraph_index); + builder_.add_then_subgraph_index(then_subgraph_index); + return builder_.Finish(); +} + +struct WhileOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_COND_SUBGRAPH_INDEX = 4, + VT_BODY_SUBGRAPH_INDEX = 6 + }; + int32_t cond_subgraph_index() const { return GetField(VT_COND_SUBGRAPH_INDEX, 0); } + int32_t body_subgraph_index() const { return GetField(VT_BODY_SUBGRAPH_INDEX, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_COND_SUBGRAPH_INDEX) && + VerifyField(verifier, VT_BODY_SUBGRAPH_INDEX) && verifier.EndTable(); + } +}; + +struct WhileOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_cond_subgraph_index(int32_t cond_subgraph_index) + { + fbb_.AddElement(WhileOptions::VT_COND_SUBGRAPH_INDEX, cond_subgraph_index, 0); + } + void add_body_subgraph_index(int32_t body_subgraph_index) + { + fbb_.AddElement(WhileOptions::VT_BODY_SUBGRAPH_INDEX, body_subgraph_index, 0); + } + explicit WhileOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + WhileOptionsBuilder &operator=(const WhileOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateWhileOptions(flatbuffers::FlatBufferBuilder &_fbb, + int32_t cond_subgraph_index = 0, + int32_t body_subgraph_index = 0) +{ + WhileOptionsBuilder builder_(_fbb); + builder_.add_body_subgraph_index(body_subgraph_index); + builder_.add_cond_subgraph_index(cond_subgraph_index); + return builder_.Finish(); +} + +struct NonMaxSuppressionV4Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct NonMaxSuppressionV4OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NonMaxSuppressionV4OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + NonMaxSuppressionV4OptionsBuilder &operator=(const NonMaxSuppressionV4OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateNonMaxSuppressionV4Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + NonMaxSuppressionV4OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct NonMaxSuppressionV5Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct NonMaxSuppressionV5OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit NonMaxSuppressionV5OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + NonMaxSuppressionV5OptionsBuilder &operator=(const NonMaxSuppressionV5OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateNonMaxSuppressionV5Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + NonMaxSuppressionV5OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct ScatterNdOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct ScatterNdOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit ScatterNdOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ScatterNdOptionsBuilder &operator=(const ScatterNdOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateScatterNdOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + ScatterNdOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SelectV2Options FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SelectV2OptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SelectV2OptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SelectV2OptionsBuilder &operator=(const SelectV2OptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSelectV2Options(flatbuffers::FlatBufferBuilder &_fbb) +{ + SelectV2OptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct DensifyOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct DensifyOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit DensifyOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + DensifyOptionsBuilder &operator=(const DensifyOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateDensifyOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + DensifyOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct SegmentSumOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && verifier.EndTable(); + } +}; + +struct SegmentSumOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + explicit SegmentSumOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SegmentSumOptionsBuilder &operator=(const SegmentSumOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateSegmentSumOptions(flatbuffers::FlatBufferBuilder &_fbb) +{ + SegmentSumOptionsBuilder builder_(_fbb); + return builder_.Finish(); +} + +struct BatchMatMulOptions FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_ADJOINT_LHS = 4, + VT_ADJOINT_RHS = 6 + }; + bool adjoint_lhs() const { return GetField(VT_ADJOINT_LHS, 0) != 0; } + bool adjoint_rhs() const { return GetField(VT_ADJOINT_RHS, 0) != 0; } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_ADJOINT_LHS) && + VerifyField(verifier, VT_ADJOINT_RHS) && verifier.EndTable(); + } +}; + +struct BatchMatMulOptionsBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_adjoint_lhs(bool adjoint_lhs) + { + fbb_.AddElement(BatchMatMulOptions::VT_ADJOINT_LHS, static_cast(adjoint_lhs), + 0); + } + void add_adjoint_rhs(bool adjoint_rhs) + { + fbb_.AddElement(BatchMatMulOptions::VT_ADJOINT_RHS, static_cast(adjoint_rhs), + 0); + } + explicit BatchMatMulOptionsBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BatchMatMulOptionsBuilder &operator=(const BatchMatMulOptionsBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateBatchMatMulOptions(flatbuffers::FlatBufferBuilder &_fbb, bool adjoint_lhs = false, + bool adjoint_rhs = false) +{ + BatchMatMulOptionsBuilder builder_(_fbb); + builder_.add_adjoint_rhs(adjoint_rhs); + builder_.add_adjoint_lhs(adjoint_lhs); + return builder_.Finish(); +} + +struct OperatorCode FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_BUILTIN_CODE = 4, + VT_CUSTOM_CODE = 6, + VT_VERSION = 8 + }; + BuiltinOperator builtin_code() const + { + return static_cast(GetField(VT_BUILTIN_CODE, 0)); + } + const flatbuffers::String *custom_code() const + { + return GetPointer(VT_CUSTOM_CODE); + } + int32_t version() const { return GetField(VT_VERSION, 1); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_BUILTIN_CODE) && + VerifyOffset(verifier, VT_CUSTOM_CODE) && verifier.VerifyString(custom_code()) && + VerifyField(verifier, VT_VERSION) && verifier.EndTable(); + } +}; + +struct OperatorCodeBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_builtin_code(BuiltinOperator builtin_code) + { + fbb_.AddElement(OperatorCode::VT_BUILTIN_CODE, static_cast(builtin_code), 0); + } + void add_custom_code(flatbuffers::Offset custom_code) + { + fbb_.AddOffset(OperatorCode::VT_CUSTOM_CODE, custom_code); + } + void add_version(int32_t version) + { + fbb_.AddElement(OperatorCode::VT_VERSION, version, 1); + } + explicit OperatorCodeBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + OperatorCodeBuilder &operator=(const OperatorCodeBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateOperatorCode(flatbuffers::FlatBufferBuilder &_fbb, + BuiltinOperator builtin_code = BuiltinOperator_ADD, + flatbuffers::Offset custom_code = 0, int32_t version = 1) +{ + OperatorCodeBuilder builder_(_fbb); + builder_.add_version(version); + builder_.add_custom_code(custom_code); + builder_.add_builtin_code(builtin_code); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateOperatorCodeDirect(flatbuffers::FlatBufferBuilder &_fbb, + BuiltinOperator builtin_code = BuiltinOperator_ADD, + const char *custom_code = nullptr, int32_t version = 1) +{ + return onert_tflite::CreateOperatorCode( + _fbb, builtin_code, custom_code ? _fbb.CreateString(custom_code) : 0, version); +} + +struct Operator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_OPCODE_INDEX = 4, + VT_INPUTS = 6, + VT_OUTPUTS = 8, + VT_BUILTIN_OPTIONS_TYPE = 10, + VT_BUILTIN_OPTIONS = 12, + VT_CUSTOM_OPTIONS = 14, + VT_CUSTOM_OPTIONS_FORMAT = 16, + VT_MUTATING_VARIABLE_INPUTS = 18, + VT_INTERMEDIATES = 20 + }; + uint32_t opcode_index() const { return GetField(VT_OPCODE_INDEX, 0); } + const flatbuffers::Vector *inputs() const + { + return GetPointer *>(VT_INPUTS); + } + const flatbuffers::Vector *outputs() const + { + return GetPointer *>(VT_OUTPUTS); + } + BuiltinOptions builtin_options_type() const + { + return static_cast(GetField(VT_BUILTIN_OPTIONS_TYPE, 0)); + } + const void *builtin_options() const { return GetPointer(VT_BUILTIN_OPTIONS); } + template const T *builtin_options_as() const; + const Conv2DOptions *builtin_options_as_Conv2DOptions() const + { + return builtin_options_type() == BuiltinOptions_Conv2DOptions + ? static_cast(builtin_options()) + : nullptr; + } + const DepthwiseConv2DOptions *builtin_options_as_DepthwiseConv2DOptions() const + { + return builtin_options_type() == BuiltinOptions_DepthwiseConv2DOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ConcatEmbeddingsOptions *builtin_options_as_ConcatEmbeddingsOptions() const + { + return builtin_options_type() == BuiltinOptions_ConcatEmbeddingsOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LSHProjectionOptions *builtin_options_as_LSHProjectionOptions() const + { + return builtin_options_type() == BuiltinOptions_LSHProjectionOptions + ? static_cast(builtin_options()) + : nullptr; + } + const Pool2DOptions *builtin_options_as_Pool2DOptions() const + { + return builtin_options_type() == BuiltinOptions_Pool2DOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SVDFOptions *builtin_options_as_SVDFOptions() const + { + return builtin_options_type() == BuiltinOptions_SVDFOptions + ? static_cast(builtin_options()) + : nullptr; + } + const RNNOptions *builtin_options_as_RNNOptions() const + { + return builtin_options_type() == BuiltinOptions_RNNOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FullyConnectedOptions *builtin_options_as_FullyConnectedOptions() const + { + return builtin_options_type() == BuiltinOptions_FullyConnectedOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SoftmaxOptions *builtin_options_as_SoftmaxOptions() const + { + return builtin_options_type() == BuiltinOptions_SoftmaxOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ConcatenationOptions *builtin_options_as_ConcatenationOptions() const + { + return builtin_options_type() == BuiltinOptions_ConcatenationOptions + ? static_cast(builtin_options()) + : nullptr; + } + const AddOptions *builtin_options_as_AddOptions() const + { + return builtin_options_type() == BuiltinOptions_AddOptions + ? static_cast(builtin_options()) + : nullptr; + } + const L2NormOptions *builtin_options_as_L2NormOptions() const + { + return builtin_options_type() == BuiltinOptions_L2NormOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LocalResponseNormalizationOptions * + builtin_options_as_LocalResponseNormalizationOptions() const + { + return builtin_options_type() == BuiltinOptions_LocalResponseNormalizationOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LSTMOptions *builtin_options_as_LSTMOptions() const + { + return builtin_options_type() == BuiltinOptions_LSTMOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ResizeBilinearOptions *builtin_options_as_ResizeBilinearOptions() const + { + return builtin_options_type() == BuiltinOptions_ResizeBilinearOptions + ? static_cast(builtin_options()) + : nullptr; + } + const CallOptions *builtin_options_as_CallOptions() const + { + return builtin_options_type() == BuiltinOptions_CallOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ReshapeOptions *builtin_options_as_ReshapeOptions() const + { + return builtin_options_type() == BuiltinOptions_ReshapeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SkipGramOptions *builtin_options_as_SkipGramOptions() const + { + return builtin_options_type() == BuiltinOptions_SkipGramOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SpaceToDepthOptions *builtin_options_as_SpaceToDepthOptions() const + { + return builtin_options_type() == BuiltinOptions_SpaceToDepthOptions + ? static_cast(builtin_options()) + : nullptr; + } + const EmbeddingLookupSparseOptions *builtin_options_as_EmbeddingLookupSparseOptions() const + { + return builtin_options_type() == BuiltinOptions_EmbeddingLookupSparseOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MulOptions *builtin_options_as_MulOptions() const + { + return builtin_options_type() == BuiltinOptions_MulOptions + ? static_cast(builtin_options()) + : nullptr; + } + const PadOptions *builtin_options_as_PadOptions() const + { + return builtin_options_type() == BuiltinOptions_PadOptions + ? static_cast(builtin_options()) + : nullptr; + } + const GatherOptions *builtin_options_as_GatherOptions() const + { + return builtin_options_type() == BuiltinOptions_GatherOptions + ? static_cast(builtin_options()) + : nullptr; + } + const BatchToSpaceNDOptions *builtin_options_as_BatchToSpaceNDOptions() const + { + return builtin_options_type() == BuiltinOptions_BatchToSpaceNDOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SpaceToBatchNDOptions *builtin_options_as_SpaceToBatchNDOptions() const + { + return builtin_options_type() == BuiltinOptions_SpaceToBatchNDOptions + ? static_cast(builtin_options()) + : nullptr; + } + const TransposeOptions *builtin_options_as_TransposeOptions() const + { + return builtin_options_type() == BuiltinOptions_TransposeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ReducerOptions *builtin_options_as_ReducerOptions() const + { + return builtin_options_type() == BuiltinOptions_ReducerOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SubOptions *builtin_options_as_SubOptions() const + { + return builtin_options_type() == BuiltinOptions_SubOptions + ? static_cast(builtin_options()) + : nullptr; + } + const DivOptions *builtin_options_as_DivOptions() const + { + return builtin_options_type() == BuiltinOptions_DivOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SqueezeOptions *builtin_options_as_SqueezeOptions() const + { + return builtin_options_type() == BuiltinOptions_SqueezeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SequenceRNNOptions *builtin_options_as_SequenceRNNOptions() const + { + return builtin_options_type() == BuiltinOptions_SequenceRNNOptions + ? static_cast(builtin_options()) + : nullptr; + } + const StridedSliceOptions *builtin_options_as_StridedSliceOptions() const + { + return builtin_options_type() == BuiltinOptions_StridedSliceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ExpOptions *builtin_options_as_ExpOptions() const + { + return builtin_options_type() == BuiltinOptions_ExpOptions + ? static_cast(builtin_options()) + : nullptr; + } + const TopKV2Options *builtin_options_as_TopKV2Options() const + { + return builtin_options_type() == BuiltinOptions_TopKV2Options + ? static_cast(builtin_options()) + : nullptr; + } + const SplitOptions *builtin_options_as_SplitOptions() const + { + return builtin_options_type() == BuiltinOptions_SplitOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LogSoftmaxOptions *builtin_options_as_LogSoftmaxOptions() const + { + return builtin_options_type() == BuiltinOptions_LogSoftmaxOptions + ? static_cast(builtin_options()) + : nullptr; + } + const CastOptions *builtin_options_as_CastOptions() const + { + return builtin_options_type() == BuiltinOptions_CastOptions + ? static_cast(builtin_options()) + : nullptr; + } + const DequantizeOptions *builtin_options_as_DequantizeOptions() const + { + return builtin_options_type() == BuiltinOptions_DequantizeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MaximumMinimumOptions *builtin_options_as_MaximumMinimumOptions() const + { + return builtin_options_type() == BuiltinOptions_MaximumMinimumOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ArgMaxOptions *builtin_options_as_ArgMaxOptions() const + { + return builtin_options_type() == BuiltinOptions_ArgMaxOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LessOptions *builtin_options_as_LessOptions() const + { + return builtin_options_type() == BuiltinOptions_LessOptions + ? static_cast(builtin_options()) + : nullptr; + } + const NegOptions *builtin_options_as_NegOptions() const + { + return builtin_options_type() == BuiltinOptions_NegOptions + ? static_cast(builtin_options()) + : nullptr; + } + const PadV2Options *builtin_options_as_PadV2Options() const + { + return builtin_options_type() == BuiltinOptions_PadV2Options + ? static_cast(builtin_options()) + : nullptr; + } + const GreaterOptions *builtin_options_as_GreaterOptions() const + { + return builtin_options_type() == BuiltinOptions_GreaterOptions + ? static_cast(builtin_options()) + : nullptr; + } + const GreaterEqualOptions *builtin_options_as_GreaterEqualOptions() const + { + return builtin_options_type() == BuiltinOptions_GreaterEqualOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LessEqualOptions *builtin_options_as_LessEqualOptions() const + { + return builtin_options_type() == BuiltinOptions_LessEqualOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SelectOptions *builtin_options_as_SelectOptions() const + { + return builtin_options_type() == BuiltinOptions_SelectOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SliceOptions *builtin_options_as_SliceOptions() const + { + return builtin_options_type() == BuiltinOptions_SliceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const TransposeConvOptions *builtin_options_as_TransposeConvOptions() const + { + return builtin_options_type() == BuiltinOptions_TransposeConvOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SparseToDenseOptions *builtin_options_as_SparseToDenseOptions() const + { + return builtin_options_type() == BuiltinOptions_SparseToDenseOptions + ? static_cast(builtin_options()) + : nullptr; + } + const TileOptions *builtin_options_as_TileOptions() const + { + return builtin_options_type() == BuiltinOptions_TileOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ExpandDimsOptions *builtin_options_as_ExpandDimsOptions() const + { + return builtin_options_type() == BuiltinOptions_ExpandDimsOptions + ? static_cast(builtin_options()) + : nullptr; + } + const EqualOptions *builtin_options_as_EqualOptions() const + { + return builtin_options_type() == BuiltinOptions_EqualOptions + ? static_cast(builtin_options()) + : nullptr; + } + const NotEqualOptions *builtin_options_as_NotEqualOptions() const + { + return builtin_options_type() == BuiltinOptions_NotEqualOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ShapeOptions *builtin_options_as_ShapeOptions() const + { + return builtin_options_type() == BuiltinOptions_ShapeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const PowOptions *builtin_options_as_PowOptions() const + { + return builtin_options_type() == BuiltinOptions_PowOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ArgMinOptions *builtin_options_as_ArgMinOptions() const + { + return builtin_options_type() == BuiltinOptions_ArgMinOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FakeQuantOptions *builtin_options_as_FakeQuantOptions() const + { + return builtin_options_type() == BuiltinOptions_FakeQuantOptions + ? static_cast(builtin_options()) + : nullptr; + } + const PackOptions *builtin_options_as_PackOptions() const + { + return builtin_options_type() == BuiltinOptions_PackOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LogicalOrOptions *builtin_options_as_LogicalOrOptions() const + { + return builtin_options_type() == BuiltinOptions_LogicalOrOptions + ? static_cast(builtin_options()) + : nullptr; + } + const OneHotOptions *builtin_options_as_OneHotOptions() const + { + return builtin_options_type() == BuiltinOptions_OneHotOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LogicalAndOptions *builtin_options_as_LogicalAndOptions() const + { + return builtin_options_type() == BuiltinOptions_LogicalAndOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LogicalNotOptions *builtin_options_as_LogicalNotOptions() const + { + return builtin_options_type() == BuiltinOptions_LogicalNotOptions + ? static_cast(builtin_options()) + : nullptr; + } + const UnpackOptions *builtin_options_as_UnpackOptions() const + { + return builtin_options_type() == BuiltinOptions_UnpackOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FloorDivOptions *builtin_options_as_FloorDivOptions() const + { + return builtin_options_type() == BuiltinOptions_FloorDivOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SquareOptions *builtin_options_as_SquareOptions() const + { + return builtin_options_type() == BuiltinOptions_SquareOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ZerosLikeOptions *builtin_options_as_ZerosLikeOptions() const + { + return builtin_options_type() == BuiltinOptions_ZerosLikeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FillOptions *builtin_options_as_FillOptions() const + { + return builtin_options_type() == BuiltinOptions_FillOptions + ? static_cast(builtin_options()) + : nullptr; + } + const BidirectionalSequenceLSTMOptions * + builtin_options_as_BidirectionalSequenceLSTMOptions() const + { + return builtin_options_type() == BuiltinOptions_BidirectionalSequenceLSTMOptions + ? static_cast(builtin_options()) + : nullptr; + } + const BidirectionalSequenceRNNOptions *builtin_options_as_BidirectionalSequenceRNNOptions() const + { + return builtin_options_type() == BuiltinOptions_BidirectionalSequenceRNNOptions + ? static_cast(builtin_options()) + : nullptr; + } + const UnidirectionalSequenceLSTMOptions * + builtin_options_as_UnidirectionalSequenceLSTMOptions() const + { + return builtin_options_type() == BuiltinOptions_UnidirectionalSequenceLSTMOptions + ? static_cast(builtin_options()) + : nullptr; + } + const FloorModOptions *builtin_options_as_FloorModOptions() const + { + return builtin_options_type() == BuiltinOptions_FloorModOptions + ? static_cast(builtin_options()) + : nullptr; + } + const RangeOptions *builtin_options_as_RangeOptions() const + { + return builtin_options_type() == BuiltinOptions_RangeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ResizeNearestNeighborOptions *builtin_options_as_ResizeNearestNeighborOptions() const + { + return builtin_options_type() == BuiltinOptions_ResizeNearestNeighborOptions + ? static_cast(builtin_options()) + : nullptr; + } + const LeakyReluOptions *builtin_options_as_LeakyReluOptions() const + { + return builtin_options_type() == BuiltinOptions_LeakyReluOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SquaredDifferenceOptions *builtin_options_as_SquaredDifferenceOptions() const + { + return builtin_options_type() == BuiltinOptions_SquaredDifferenceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MirrorPadOptions *builtin_options_as_MirrorPadOptions() const + { + return builtin_options_type() == BuiltinOptions_MirrorPadOptions + ? static_cast(builtin_options()) + : nullptr; + } + const AbsOptions *builtin_options_as_AbsOptions() const + { + return builtin_options_type() == BuiltinOptions_AbsOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SplitVOptions *builtin_options_as_SplitVOptions() const + { + return builtin_options_type() == BuiltinOptions_SplitVOptions + ? static_cast(builtin_options()) + : nullptr; + } + const UniqueOptions *builtin_options_as_UniqueOptions() const + { + return builtin_options_type() == BuiltinOptions_UniqueOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ReverseV2Options *builtin_options_as_ReverseV2Options() const + { + return builtin_options_type() == BuiltinOptions_ReverseV2Options + ? static_cast(builtin_options()) + : nullptr; + } + const AddNOptions *builtin_options_as_AddNOptions() const + { + return builtin_options_type() == BuiltinOptions_AddNOptions + ? static_cast(builtin_options()) + : nullptr; + } + const GatherNdOptions *builtin_options_as_GatherNdOptions() const + { + return builtin_options_type() == BuiltinOptions_GatherNdOptions + ? static_cast(builtin_options()) + : nullptr; + } + const CosOptions *builtin_options_as_CosOptions() const + { + return builtin_options_type() == BuiltinOptions_CosOptions + ? static_cast(builtin_options()) + : nullptr; + } + const WhereOptions *builtin_options_as_WhereOptions() const + { + return builtin_options_type() == BuiltinOptions_WhereOptions + ? static_cast(builtin_options()) + : nullptr; + } + const RankOptions *builtin_options_as_RankOptions() const + { + return builtin_options_type() == BuiltinOptions_RankOptions + ? static_cast(builtin_options()) + : nullptr; + } + const ReverseSequenceOptions *builtin_options_as_ReverseSequenceOptions() const + { + return builtin_options_type() == BuiltinOptions_ReverseSequenceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MatrixDiagOptions *builtin_options_as_MatrixDiagOptions() const + { + return builtin_options_type() == BuiltinOptions_MatrixDiagOptions + ? static_cast(builtin_options()) + : nullptr; + } + const QuantizeOptions *builtin_options_as_QuantizeOptions() const + { + return builtin_options_type() == BuiltinOptions_QuantizeOptions + ? static_cast(builtin_options()) + : nullptr; + } + const MatrixSetDiagOptions *builtin_options_as_MatrixSetDiagOptions() const + { + return builtin_options_type() == BuiltinOptions_MatrixSetDiagOptions + ? static_cast(builtin_options()) + : nullptr; + } + const HardSwishOptions *builtin_options_as_HardSwishOptions() const + { + return builtin_options_type() == BuiltinOptions_HardSwishOptions + ? static_cast(builtin_options()) + : nullptr; + } + const IfOptions *builtin_options_as_IfOptions() const + { + return builtin_options_type() == BuiltinOptions_IfOptions + ? static_cast(builtin_options()) + : nullptr; + } + const WhileOptions *builtin_options_as_WhileOptions() const + { + return builtin_options_type() == BuiltinOptions_WhileOptions + ? static_cast(builtin_options()) + : nullptr; + } + const DepthToSpaceOptions *builtin_options_as_DepthToSpaceOptions() const + { + return builtin_options_type() == BuiltinOptions_DepthToSpaceOptions + ? static_cast(builtin_options()) + : nullptr; + } + const NonMaxSuppressionV4Options *builtin_options_as_NonMaxSuppressionV4Options() const + { + return builtin_options_type() == BuiltinOptions_NonMaxSuppressionV4Options + ? static_cast(builtin_options()) + : nullptr; + } + const NonMaxSuppressionV5Options *builtin_options_as_NonMaxSuppressionV5Options() const + { + return builtin_options_type() == BuiltinOptions_NonMaxSuppressionV5Options + ? static_cast(builtin_options()) + : nullptr; + } + const ScatterNdOptions *builtin_options_as_ScatterNdOptions() const + { + return builtin_options_type() == BuiltinOptions_ScatterNdOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SelectV2Options *builtin_options_as_SelectV2Options() const + { + return builtin_options_type() == BuiltinOptions_SelectV2Options + ? static_cast(builtin_options()) + : nullptr; + } + const DensifyOptions *builtin_options_as_DensifyOptions() const + { + return builtin_options_type() == BuiltinOptions_DensifyOptions + ? static_cast(builtin_options()) + : nullptr; + } + const SegmentSumOptions *builtin_options_as_SegmentSumOptions() const + { + return builtin_options_type() == BuiltinOptions_SegmentSumOptions + ? static_cast(builtin_options()) + : nullptr; + } + const BatchMatMulOptions *builtin_options_as_BatchMatMulOptions() const + { + return builtin_options_type() == BuiltinOptions_BatchMatMulOptions + ? static_cast(builtin_options()) + : nullptr; + } + const flatbuffers::Vector *custom_options() const + { + return GetPointer *>(VT_CUSTOM_OPTIONS); + } + CustomOptionsFormat custom_options_format() const + { + return static_cast(GetField(VT_CUSTOM_OPTIONS_FORMAT, 0)); + } + const flatbuffers::Vector *mutating_variable_inputs() const + { + return GetPointer *>(VT_MUTATING_VARIABLE_INPUTS); + } + const flatbuffers::Vector *intermediates() const + { + return GetPointer *>(VT_INTERMEDIATES); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_OPCODE_INDEX) && + VerifyOffset(verifier, VT_INPUTS) && verifier.VerifyVector(inputs()) && + VerifyOffset(verifier, VT_OUTPUTS) && verifier.VerifyVector(outputs()) && + VerifyField(verifier, VT_BUILTIN_OPTIONS_TYPE) && + VerifyOffset(verifier, VT_BUILTIN_OPTIONS) && + VerifyBuiltinOptions(verifier, builtin_options(), builtin_options_type()) && + VerifyOffset(verifier, VT_CUSTOM_OPTIONS) && verifier.VerifyVector(custom_options()) && + VerifyField(verifier, VT_CUSTOM_OPTIONS_FORMAT) && + VerifyOffset(verifier, VT_MUTATING_VARIABLE_INPUTS) && + verifier.VerifyVector(mutating_variable_inputs()) && + VerifyOffset(verifier, VT_INTERMEDIATES) && verifier.VerifyVector(intermediates()) && + verifier.EndTable(); + } +}; + +template <> inline const Conv2DOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_Conv2DOptions(); +} + +template <> +inline const DepthwiseConv2DOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DepthwiseConv2DOptions(); +} + +template <> +inline const ConcatEmbeddingsOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ConcatEmbeddingsOptions(); +} + +template <> +inline const LSHProjectionOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LSHProjectionOptions(); +} + +template <> inline const Pool2DOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_Pool2DOptions(); +} + +template <> inline const SVDFOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SVDFOptions(); +} + +template <> inline const RNNOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_RNNOptions(); +} + +template <> +inline const FullyConnectedOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FullyConnectedOptions(); +} + +template <> inline const SoftmaxOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SoftmaxOptions(); +} + +template <> +inline const ConcatenationOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ConcatenationOptions(); +} + +template <> inline const AddOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_AddOptions(); +} + +template <> inline const L2NormOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_L2NormOptions(); +} + +template <> +inline const LocalResponseNormalizationOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_LocalResponseNormalizationOptions(); +} + +template <> inline const LSTMOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LSTMOptions(); +} + +template <> +inline const ResizeBilinearOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ResizeBilinearOptions(); +} + +template <> inline const CallOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_CallOptions(); +} + +template <> inline const ReshapeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ReshapeOptions(); +} + +template <> inline const SkipGramOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SkipGramOptions(); +} + +template <> +inline const SpaceToDepthOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SpaceToDepthOptions(); +} + +template <> +inline const EmbeddingLookupSparseOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_EmbeddingLookupSparseOptions(); +} + +template <> inline const MulOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MulOptions(); +} + +template <> inline const PadOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_PadOptions(); +} + +template <> inline const GatherOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_GatherOptions(); +} + +template <> +inline const BatchToSpaceNDOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_BatchToSpaceNDOptions(); +} + +template <> +inline const SpaceToBatchNDOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SpaceToBatchNDOptions(); +} + +template <> inline const TransposeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_TransposeOptions(); +} + +template <> inline const ReducerOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ReducerOptions(); +} + +template <> inline const SubOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SubOptions(); +} + +template <> inline const DivOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DivOptions(); +} + +template <> inline const SqueezeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SqueezeOptions(); +} + +template <> +inline const SequenceRNNOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SequenceRNNOptions(); +} + +template <> +inline const StridedSliceOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_StridedSliceOptions(); +} + +template <> inline const ExpOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ExpOptions(); +} + +template <> inline const TopKV2Options *Operator::builtin_options_as() const +{ + return builtin_options_as_TopKV2Options(); +} + +template <> inline const SplitOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SplitOptions(); +} + +template <> inline const LogSoftmaxOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LogSoftmaxOptions(); +} + +template <> inline const CastOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_CastOptions(); +} + +template <> inline const DequantizeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DequantizeOptions(); +} + +template <> +inline const MaximumMinimumOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MaximumMinimumOptions(); +} + +template <> inline const ArgMaxOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ArgMaxOptions(); +} + +template <> inline const LessOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LessOptions(); +} + +template <> inline const NegOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_NegOptions(); +} + +template <> inline const PadV2Options *Operator::builtin_options_as() const +{ + return builtin_options_as_PadV2Options(); +} + +template <> inline const GreaterOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_GreaterOptions(); +} + +template <> +inline const GreaterEqualOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_GreaterEqualOptions(); +} + +template <> inline const LessEqualOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LessEqualOptions(); +} + +template <> inline const SelectOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SelectOptions(); +} + +template <> inline const SliceOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SliceOptions(); +} + +template <> +inline const TransposeConvOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_TransposeConvOptions(); +} + +template <> +inline const SparseToDenseOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SparseToDenseOptions(); +} + +template <> inline const TileOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_TileOptions(); +} + +template <> inline const ExpandDimsOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ExpandDimsOptions(); +} + +template <> inline const EqualOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_EqualOptions(); +} + +template <> inline const NotEqualOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_NotEqualOptions(); +} + +template <> inline const ShapeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ShapeOptions(); +} + +template <> inline const PowOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_PowOptions(); +} + +template <> inline const ArgMinOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ArgMinOptions(); +} + +template <> inline const FakeQuantOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FakeQuantOptions(); +} + +template <> inline const PackOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_PackOptions(); +} + +template <> inline const LogicalOrOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LogicalOrOptions(); +} + +template <> inline const OneHotOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_OneHotOptions(); +} + +template <> inline const LogicalAndOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LogicalAndOptions(); +} + +template <> inline const LogicalNotOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LogicalNotOptions(); +} + +template <> inline const UnpackOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_UnpackOptions(); +} + +template <> inline const FloorDivOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FloorDivOptions(); +} + +template <> inline const SquareOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SquareOptions(); +} + +template <> inline const ZerosLikeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ZerosLikeOptions(); +} + +template <> inline const FillOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FillOptions(); +} + +template <> +inline const BidirectionalSequenceLSTMOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_BidirectionalSequenceLSTMOptions(); +} + +template <> +inline const BidirectionalSequenceRNNOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_BidirectionalSequenceRNNOptions(); +} + +template <> +inline const UnidirectionalSequenceLSTMOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_UnidirectionalSequenceLSTMOptions(); +} + +template <> inline const FloorModOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_FloorModOptions(); +} + +template <> inline const RangeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_RangeOptions(); +} + +template <> +inline const ResizeNearestNeighborOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_ResizeNearestNeighborOptions(); +} + +template <> inline const LeakyReluOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_LeakyReluOptions(); +} + +template <> +inline const SquaredDifferenceOptions * +Operator::builtin_options_as() const +{ + return builtin_options_as_SquaredDifferenceOptions(); +} + +template <> inline const MirrorPadOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MirrorPadOptions(); +} + +template <> inline const AbsOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_AbsOptions(); +} + +template <> inline const SplitVOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SplitVOptions(); +} + +template <> inline const UniqueOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_UniqueOptions(); +} + +template <> inline const ReverseV2Options *Operator::builtin_options_as() const +{ + return builtin_options_as_ReverseV2Options(); +} + +template <> inline const AddNOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_AddNOptions(); +} + +template <> inline const GatherNdOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_GatherNdOptions(); +} + +template <> inline const CosOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_CosOptions(); +} + +template <> inline const WhereOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_WhereOptions(); +} + +template <> inline const RankOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_RankOptions(); +} + +template <> +inline const ReverseSequenceOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ReverseSequenceOptions(); +} + +template <> inline const MatrixDiagOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MatrixDiagOptions(); +} + +template <> inline const QuantizeOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_QuantizeOptions(); +} + +template <> +inline const MatrixSetDiagOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_MatrixSetDiagOptions(); +} + +template <> inline const HardSwishOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_HardSwishOptions(); +} + +template <> inline const IfOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_IfOptions(); +} + +template <> inline const WhileOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_WhileOptions(); +} + +template <> +inline const DepthToSpaceOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DepthToSpaceOptions(); +} + +template <> +inline const NonMaxSuppressionV4Options * +Operator::builtin_options_as() const +{ + return builtin_options_as_NonMaxSuppressionV4Options(); +} + +template <> +inline const NonMaxSuppressionV5Options * +Operator::builtin_options_as() const +{ + return builtin_options_as_NonMaxSuppressionV5Options(); +} + +template <> inline const ScatterNdOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_ScatterNdOptions(); +} + +template <> inline const SelectV2Options *Operator::builtin_options_as() const +{ + return builtin_options_as_SelectV2Options(); +} + +template <> inline const DensifyOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_DensifyOptions(); +} + +template <> inline const SegmentSumOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_SegmentSumOptions(); +} + +template <> +inline const BatchMatMulOptions *Operator::builtin_options_as() const +{ + return builtin_options_as_BatchMatMulOptions(); +} + +struct OperatorBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_opcode_index(uint32_t opcode_index) + { + fbb_.AddElement(Operator::VT_OPCODE_INDEX, opcode_index, 0); + } + void add_inputs(flatbuffers::Offset> inputs) + { + fbb_.AddOffset(Operator::VT_INPUTS, inputs); + } + void add_outputs(flatbuffers::Offset> outputs) + { + fbb_.AddOffset(Operator::VT_OUTPUTS, outputs); + } + void add_builtin_options_type(BuiltinOptions builtin_options_type) + { + fbb_.AddElement(Operator::VT_BUILTIN_OPTIONS_TYPE, + static_cast(builtin_options_type), 0); + } + void add_builtin_options(flatbuffers::Offset builtin_options) + { + fbb_.AddOffset(Operator::VT_BUILTIN_OPTIONS, builtin_options); + } + void add_custom_options(flatbuffers::Offset> custom_options) + { + fbb_.AddOffset(Operator::VT_CUSTOM_OPTIONS, custom_options); + } + void add_custom_options_format(CustomOptionsFormat custom_options_format) + { + fbb_.AddElement(Operator::VT_CUSTOM_OPTIONS_FORMAT, + static_cast(custom_options_format), 0); + } + void add_mutating_variable_inputs( + flatbuffers::Offset> mutating_variable_inputs) + { + fbb_.AddOffset(Operator::VT_MUTATING_VARIABLE_INPUTS, mutating_variable_inputs); + } + void add_intermediates(flatbuffers::Offset> intermediates) + { + fbb_.AddOffset(Operator::VT_INTERMEDIATES, intermediates); + } + explicit OperatorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + OperatorBuilder &operator=(const OperatorBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateOperator(flatbuffers::FlatBufferBuilder &_fbb, uint32_t opcode_index = 0, + flatbuffers::Offset> inputs = 0, + flatbuffers::Offset> outputs = 0, + BuiltinOptions builtin_options_type = BuiltinOptions_NONE, + flatbuffers::Offset builtin_options = 0, + flatbuffers::Offset> custom_options = 0, + CustomOptionsFormat custom_options_format = CustomOptionsFormat_FLEXBUFFERS, + flatbuffers::Offset> mutating_variable_inputs = 0, + flatbuffers::Offset> intermediates = 0) +{ + OperatorBuilder builder_(_fbb); + builder_.add_intermediates(intermediates); + builder_.add_mutating_variable_inputs(mutating_variable_inputs); + builder_.add_custom_options(custom_options); + builder_.add_builtin_options(builtin_options); + builder_.add_outputs(outputs); + builder_.add_inputs(inputs); + builder_.add_opcode_index(opcode_index); + builder_.add_custom_options_format(custom_options_format); + builder_.add_builtin_options_type(builtin_options_type); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateOperatorDirect(flatbuffers::FlatBufferBuilder &_fbb, uint32_t opcode_index = 0, + const std::vector *inputs = nullptr, + const std::vector *outputs = nullptr, + BuiltinOptions builtin_options_type = BuiltinOptions_NONE, + flatbuffers::Offset builtin_options = 0, + const std::vector *custom_options = nullptr, + CustomOptionsFormat custom_options_format = CustomOptionsFormat_FLEXBUFFERS, + const std::vector *mutating_variable_inputs = nullptr, + const std::vector *intermediates = nullptr) +{ + return onert_tflite::CreateOperator( + _fbb, opcode_index, inputs ? _fbb.CreateVector(*inputs) : 0, + outputs ? _fbb.CreateVector(*outputs) : 0, builtin_options_type, builtin_options, + custom_options ? _fbb.CreateVector(*custom_options) : 0, custom_options_format, + mutating_variable_inputs ? _fbb.CreateVector(*mutating_variable_inputs) : 0, + intermediates ? _fbb.CreateVector(*intermediates) : 0); +} + +struct SubGraph FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_TENSORS = 4, + VT_INPUTS = 6, + VT_OUTPUTS = 8, + VT_OPERATORS = 10, + VT_NAME = 12 + }; + const flatbuffers::Vector> *tensors() const + { + return GetPointer> *>(VT_TENSORS); + } + const flatbuffers::Vector *inputs() const + { + return GetPointer *>(VT_INPUTS); + } + const flatbuffers::Vector *outputs() const + { + return GetPointer *>(VT_OUTPUTS); + } + const flatbuffers::Vector> *operators() const + { + return GetPointer> *>(VT_OPERATORS); + } + const flatbuffers::String *name() const + { + return GetPointer(VT_NAME); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_TENSORS) && + verifier.VerifyVector(tensors()) && verifier.VerifyVectorOfTables(tensors()) && + VerifyOffset(verifier, VT_INPUTS) && verifier.VerifyVector(inputs()) && + VerifyOffset(verifier, VT_OUTPUTS) && verifier.VerifyVector(outputs()) && + VerifyOffset(verifier, VT_OPERATORS) && verifier.VerifyVector(operators()) && + verifier.VerifyVectorOfTables(operators()) && VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && verifier.EndTable(); + } +}; + +struct SubGraphBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_tensors(flatbuffers::Offset>> tensors) + { + fbb_.AddOffset(SubGraph::VT_TENSORS, tensors); + } + void add_inputs(flatbuffers::Offset> inputs) + { + fbb_.AddOffset(SubGraph::VT_INPUTS, inputs); + } + void add_outputs(flatbuffers::Offset> outputs) + { + fbb_.AddOffset(SubGraph::VT_OUTPUTS, outputs); + } + void + add_operators(flatbuffers::Offset>> operators) + { + fbb_.AddOffset(SubGraph::VT_OPERATORS, operators); + } + void add_name(flatbuffers::Offset name) + { + fbb_.AddOffset(SubGraph::VT_NAME, name); + } + explicit SubGraphBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + SubGraphBuilder &operator=(const SubGraphBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateSubGraph( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset>> tensors = 0, + flatbuffers::Offset> inputs = 0, + flatbuffers::Offset> outputs = 0, + flatbuffers::Offset>> operators = 0, + flatbuffers::Offset name = 0) +{ + SubGraphBuilder builder_(_fbb); + builder_.add_name(name); + builder_.add_operators(operators); + builder_.add_outputs(outputs); + builder_.add_inputs(inputs); + builder_.add_tensors(tensors); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateSubGraphDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector> *tensors = nullptr, + const std::vector *inputs = nullptr, + const std::vector *outputs = nullptr, + const std::vector> *operators = nullptr, + const char *name = nullptr) +{ + return onert_tflite::CreateSubGraph( + _fbb, tensors ? _fbb.CreateVector>(*tensors) : 0, + inputs ? _fbb.CreateVector(*inputs) : 0, + outputs ? _fbb.CreateVector(*outputs) : 0, + operators ? _fbb.CreateVector>(*operators) : 0, + name ? _fbb.CreateString(name) : 0); +} + +struct Buffer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_DATA = 4 + }; + const flatbuffers::Vector *data() const + { + return GetPointer *>(VT_DATA); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_DATA) && + verifier.VerifyVector(data()) && verifier.EndTable(); + } +}; + +struct BufferBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_data(flatbuffers::Offset> data) + { + fbb_.AddOffset(Buffer::VT_DATA, data); + } + explicit BufferBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + BufferBuilder &operator=(const BufferBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateBuffer(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset> data = 0) +{ + BufferBuilder builder_(_fbb); + builder_.add_data(data); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateBufferDirect(flatbuffers::FlatBufferBuilder &_fbb, + const std::vector *data = nullptr) +{ + return onert_tflite::CreateBuffer(_fbb, data ? _fbb.CreateVector(*data) : 0); +} + +struct Metadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_NAME = 4, + VT_BUFFER = 6 + }; + const flatbuffers::String *name() const + { + return GetPointer(VT_NAME); + } + uint32_t buffer() const { return GetField(VT_BUFFER, 0); } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyOffset(verifier, VT_NAME) && + verifier.VerifyString(name()) && VerifyField(verifier, VT_BUFFER) && + verifier.EndTable(); + } +}; + +struct MetadataBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset name) + { + fbb_.AddOffset(Metadata::VT_NAME, name); + } + void add_buffer(uint32_t buffer) { fbb_.AddElement(Metadata::VT_BUFFER, buffer, 0); } + explicit MetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + MetadataBuilder &operator=(const MetadataBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset +CreateMetadata(flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset name = 0, uint32_t buffer = 0) +{ + MetadataBuilder builder_(_fbb); + builder_.add_buffer(buffer); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset CreateMetadataDirect(flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + uint32_t buffer = 0) +{ + return onert_tflite::CreateMetadata(_fbb, name ? _fbb.CreateString(name) : 0, buffer); +} + +struct Model FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table +{ + enum + { + VT_VERSION = 4, + VT_OPERATOR_CODES = 6, + VT_SUBGRAPHS = 8, + VT_DESCRIPTION = 10, + VT_BUFFERS = 12, + VT_METADATA_BUFFER = 14, + VT_METADATA = 16 + }; + uint32_t version() const { return GetField(VT_VERSION, 0); } + const flatbuffers::Vector> *operator_codes() const + { + return GetPointer> *>( + VT_OPERATOR_CODES); + } + const flatbuffers::Vector> *subgraphs() const + { + return GetPointer> *>(VT_SUBGRAPHS); + } + const flatbuffers::String *description() const + { + return GetPointer(VT_DESCRIPTION); + } + const flatbuffers::Vector> *buffers() const + { + return GetPointer> *>(VT_BUFFERS); + } + const flatbuffers::Vector *metadata_buffer() const + { + return GetPointer *>(VT_METADATA_BUFFER); + } + const flatbuffers::Vector> *metadata() const + { + return GetPointer> *>(VT_METADATA); + } + bool Verify(flatbuffers::Verifier &verifier) const + { + return VerifyTableStart(verifier) && VerifyField(verifier, VT_VERSION) && + VerifyOffset(verifier, VT_OPERATOR_CODES) && verifier.VerifyVector(operator_codes()) && + verifier.VerifyVectorOfTables(operator_codes()) && + VerifyOffset(verifier, VT_SUBGRAPHS) && verifier.VerifyVector(subgraphs()) && + verifier.VerifyVectorOfTables(subgraphs()) && VerifyOffset(verifier, VT_DESCRIPTION) && + verifier.VerifyString(description()) && VerifyOffset(verifier, VT_BUFFERS) && + verifier.VerifyVector(buffers()) && verifier.VerifyVectorOfTables(buffers()) && + VerifyOffset(verifier, VT_METADATA_BUFFER) && verifier.VerifyVector(metadata_buffer()) && + VerifyOffset(verifier, VT_METADATA) && verifier.VerifyVector(metadata()) && + verifier.VerifyVectorOfTables(metadata()) && verifier.EndTable(); + } +}; + +struct ModelBuilder +{ + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_version(uint32_t version) { fbb_.AddElement(Model::VT_VERSION, version, 0); } + void add_operator_codes( + flatbuffers::Offset>> operator_codes) + { + fbb_.AddOffset(Model::VT_OPERATOR_CODES, operator_codes); + } + void + add_subgraphs(flatbuffers::Offset>> subgraphs) + { + fbb_.AddOffset(Model::VT_SUBGRAPHS, subgraphs); + } + void add_description(flatbuffers::Offset description) + { + fbb_.AddOffset(Model::VT_DESCRIPTION, description); + } + void add_buffers(flatbuffers::Offset>> buffers) + { + fbb_.AddOffset(Model::VT_BUFFERS, buffers); + } + void add_metadata_buffer(flatbuffers::Offset> metadata_buffer) + { + fbb_.AddOffset(Model::VT_METADATA_BUFFER, metadata_buffer); + } + void + add_metadata(flatbuffers::Offset>> metadata) + { + fbb_.AddOffset(Model::VT_METADATA, metadata); + } + explicit ModelBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) + { + start_ = fbb_.StartTable(); + } + ModelBuilder &operator=(const ModelBuilder &); + flatbuffers::Offset Finish() + { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset(end); + return o; + } +}; + +inline flatbuffers::Offset CreateModel( + flatbuffers::FlatBufferBuilder &_fbb, uint32_t version = 0, + flatbuffers::Offset>> operator_codes = 0, + flatbuffers::Offset>> subgraphs = 0, + flatbuffers::Offset description = 0, + flatbuffers::Offset>> buffers = 0, + flatbuffers::Offset> metadata_buffer = 0, + flatbuffers::Offset>> metadata = 0) +{ + ModelBuilder builder_(_fbb); + builder_.add_metadata(metadata); + builder_.add_metadata_buffer(metadata_buffer); + builder_.add_buffers(buffers); + builder_.add_description(description); + builder_.add_subgraphs(subgraphs); + builder_.add_operator_codes(operator_codes); + builder_.add_version(version); + return builder_.Finish(); +} + +inline flatbuffers::Offset +CreateModelDirect(flatbuffers::FlatBufferBuilder &_fbb, uint32_t version = 0, + const std::vector> *operator_codes = nullptr, + const std::vector> *subgraphs = nullptr, + const char *description = nullptr, + const std::vector> *buffers = nullptr, + const std::vector *metadata_buffer = nullptr, + const std::vector> *metadata = nullptr) +{ + return onert_tflite::CreateModel( + _fbb, version, + operator_codes ? _fbb.CreateVector>(*operator_codes) : 0, + subgraphs ? _fbb.CreateVector>(*subgraphs) : 0, + description ? _fbb.CreateString(description) : 0, + buffers ? _fbb.CreateVector>(*buffers) : 0, + metadata_buffer ? _fbb.CreateVector(*metadata_buffer) : 0, + metadata ? _fbb.CreateVector>(*metadata) : 0); +} + +inline bool VerifyQuantizationDetails(flatbuffers::Verifier &verifier, const void *obj, + QuantizationDetails type) +{ + switch (type) + { + case QuantizationDetails_NONE: + { + return true; + } + case QuantizationDetails_CustomQuantization: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: + return false; + } +} + +inline bool +VerifyQuantizationDetailsVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types) +{ + if (!values || !types) + return !values && !types; + if (values->size() != types->size()) + return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) + { + if (!VerifyQuantizationDetails(verifier, values->Get(i), + types->GetEnum(i))) + { + return false; + } + } + return true; +} + +inline bool VerifySparseIndexVector(flatbuffers::Verifier &verifier, const void *obj, + SparseIndexVector type) +{ + switch (type) + { + case SparseIndexVector_NONE: + { + return true; + } + case SparseIndexVector_Int32Vector: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case SparseIndexVector_Uint16Vector: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case SparseIndexVector_Uint8Vector: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: + return false; + } +} + +inline bool +VerifySparseIndexVectorVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types) +{ + if (!values || !types) + return !values && !types; + if (values->size() != types->size()) + return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) + { + if (!VerifySparseIndexVector(verifier, values->Get(i), types->GetEnum(i))) + { + return false; + } + } + return true; +} + +inline bool VerifyBuiltinOptions(flatbuffers::Verifier &verifier, const void *obj, + BuiltinOptions type) +{ + switch (type) + { + case BuiltinOptions_NONE: + { + return true; + } + case BuiltinOptions_Conv2DOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DepthwiseConv2DOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ConcatEmbeddingsOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LSHProjectionOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_Pool2DOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SVDFOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RNNOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FullyConnectedOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SoftmaxOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ConcatenationOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AddOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_L2NormOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LocalResponseNormalizationOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LSTMOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ResizeBilinearOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CallOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReshapeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SkipGramOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SpaceToDepthOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_EmbeddingLookupSparseOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MulOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PadOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GatherOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BatchToSpaceNDOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SpaceToBatchNDOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TransposeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReducerOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SubOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DivOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SqueezeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SequenceRNNOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_StridedSliceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ExpOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TopKV2Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SplitOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogSoftmaxOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CastOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DequantizeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MaximumMinimumOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ArgMaxOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LessOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NegOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PadV2Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GreaterOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GreaterEqualOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LessEqualOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SelectOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SliceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TransposeConvOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SparseToDenseOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_TileOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ExpandDimsOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_EqualOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NotEqualOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ShapeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PowOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ArgMinOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FakeQuantOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_PackOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogicalOrOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_OneHotOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogicalAndOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LogicalNotOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnpackOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FloorDivOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SquareOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ZerosLikeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FillOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BidirectionalSequenceLSTMOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BidirectionalSequenceRNNOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UnidirectionalSequenceLSTMOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_FloorModOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RangeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ResizeNearestNeighborOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_LeakyReluOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SquaredDifferenceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MirrorPadOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AbsOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SplitVOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_UniqueOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReverseV2Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_AddNOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_GatherNdOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_CosOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_WhereOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_RankOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ReverseSequenceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MatrixDiagOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_QuantizeOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_MatrixSetDiagOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_HardSwishOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_IfOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_WhileOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DepthToSpaceOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NonMaxSuppressionV4Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_NonMaxSuppressionV5Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_ScatterNdOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SelectV2Options: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_DensifyOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_SegmentSumOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + case BuiltinOptions_BatchMatMulOptions: + { + auto ptr = reinterpret_cast(obj); + return verifier.VerifyTable(ptr); + } + default: + return false; + } +} + +inline bool VerifyBuiltinOptionsVector(flatbuffers::Verifier &verifier, + const flatbuffers::Vector> *values, + const flatbuffers::Vector *types) +{ + if (!values || !types) + return !values && !types; + if (values->size() != types->size()) + return false; + for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) + { + if (!VerifyBuiltinOptions(verifier, values->Get(i), types->GetEnum(i))) + { + return false; + } + } + return true; +} + +inline const onert_tflite::Model *GetModel(const void *buf) +{ + return flatbuffers::GetRoot(buf); +} + +inline const onert_tflite::Model *GetSizePrefixedModel(const void *buf) +{ + return flatbuffers::GetSizePrefixedRoot(buf); +} + +inline const char *ModelIdentifier() { return "TFL3"; } + +inline bool ModelBufferHasIdentifier(const void *buf) +{ + return flatbuffers::BufferHasIdentifier(buf, ModelIdentifier()); +} + +inline bool VerifyModelBuffer(flatbuffers::Verifier &verifier) +{ + return verifier.VerifyBuffer(ModelIdentifier()); +} + +inline bool VerifySizePrefixedModelBuffer(flatbuffers::Verifier &verifier) +{ + return verifier.VerifySizePrefixedBuffer(ModelIdentifier()); +} + +inline const char *ModelExtension() { return "tflite"; } + +inline void FinishModelBuffer(flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) +{ + fbb.Finish(root, ModelIdentifier()); +} + +inline void FinishSizePrefixedModelBuffer(flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset root) +{ + fbb.FinishSizePrefixed(root, ModelIdentifier()); +} + +} // namespace onert_tflite + +#endif // FLATBUFFERS_GENERATED_TFLITESCHEMA_ONERT_TFLITE_H_ diff --git a/runtime/onert/frontend/tflite/tflite_schema-1.13.1.fbs b/runtime/onert/frontend/tflite/tflite_schema-1.13.1.fbs new file mode 100644 index 000000000..ae6b5230f --- /dev/null +++ b/runtime/onert/frontend/tflite/tflite_schema-1.13.1.fbs @@ -0,0 +1,795 @@ +// Copyright 2017 The TensorFlow Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Revision History +// Version 0: Initial version. +// Version 1: Add subgraphs to schema. +// Version 2: Rename operators to conform to NN API. +// Version 3: Move buffer data from Model.Subgraph.Tensors to Model.Buffers. + +// Change namespace to onert_tflite +namespace onert_tflite; + +// This corresponds to the version. +file_identifier "TFL3"; +// File extension of any written files. +file_extension "tflite"; + +// IMPORTANT: All new members of tables, enums and unions must be added at the +// end to ensure backwards compatibility. + +// The type of data stored in a tensor. +enum TensorType : byte { + FLOAT32 = 0, + FLOAT16 = 1, + INT32 = 2, + UINT8 = 3, + INT64 = 4, + STRING = 5, + BOOL = 6, + INT16 = 7, + COMPLEX64 = 8, + INT8 = 9, +} + +// Custom quantization parameters for experimenting with new quantization +// techniques. +table CustomQuantization { + custom:[ubyte] (force_align: 16); +} + +// Represents a specific quantization technique's parameters. +union QuantizationDetails { + CustomQuantization, +} + +// Parameters for converting a quantized tensor back to float. +table QuantizationParameters { + // These four parameters are the asymmetric linear quantization parameters. + // Given a quantized value q, the corresponding float value f should be: + // f = scale * (q - zero_point) + // For other quantization types, the QuantizationDetails below is used. + min:[float]; // For importing back into tensorflow. + max:[float]; // For importing back into tensorflow. + scale:[float]; // For dequantizing the tensor's values. + zero_point:[long]; + + // If this is not none, the quantization parameters above are ignored and the + // value of the QuantizationDetails union below should be used. + details:QuantizationDetails; +} + +table Tensor { + // The tensor shape. The meaning of each entry is operator-specific but + // builtin ops use: [batch size, height, width, number of channels] (That's + // Tensorflow's NHWC). + shape:[int]; + type:TensorType; + // An index that refers to the buffers table at the root of the model. Or, + // if there is no data buffer associated (i.e. intermediate results), then + // this is 0 (which refers to an always existent empty buffer). + // + // The data_buffer itself is an opaque container, with the assumption that the + // target device is little-endian. In addition, all builtin operators assume + // the memory is ordered such that if `shape` is [4, 3, 2], then index + // [i, j, k] maps to data_buffer[i*3*2 + j*2 + k]. + buffer:uint; + name:string; // For debugging and importing back into tensorflow. + quantization:QuantizationParameters; // Optional. + + is_variable:bool = false; +} + +// A list of builtin operators. Builtin operators are slightly faster than custom +// ones, but not by much. Moreover, while custom operators accept an opaque +// object containing configuration parameters, builtins have a predetermined +// set of acceptable options. +enum BuiltinOperator : byte { + ADD = 0, + AVERAGE_POOL_2D = 1, + CONCATENATION = 2, + CONV_2D = 3, + DEPTHWISE_CONV_2D = 4, + // DEPTH_TO_SPACE = 5, + DEQUANTIZE = 6, + EMBEDDING_LOOKUP = 7, + FLOOR = 8, + FULLY_CONNECTED = 9, + HASHTABLE_LOOKUP = 10, + L2_NORMALIZATION = 11, + L2_POOL_2D = 12, + LOCAL_RESPONSE_NORMALIZATION = 13, + LOGISTIC = 14, + LSH_PROJECTION = 15, + LSTM = 16, + MAX_POOL_2D = 17, + MUL = 18, + RELU = 19, + // NOTE(aselle): RELU_N1_TO_1 used to be called RELU1, but it was renamed + // since different model developers use RELU1 in different ways. Never + // create another op called RELU1. + RELU_N1_TO_1 = 20, + RELU6 = 21, + RESHAPE = 22, + RESIZE_BILINEAR = 23, + RNN = 24, + SOFTMAX = 25, + SPACE_TO_DEPTH = 26, + SVDF = 27, + TANH = 28, + // TODO(aselle): Consider rename to CONCATENATE_EMBEDDINGS + CONCAT_EMBEDDINGS = 29, + SKIP_GRAM = 30, + CALL = 31, + CUSTOM = 32, + EMBEDDING_LOOKUP_SPARSE = 33, + PAD = 34, + UNIDIRECTIONAL_SEQUENCE_RNN = 35, + GATHER = 36, + BATCH_TO_SPACE_ND = 37, + SPACE_TO_BATCH_ND = 38, + TRANSPOSE = 39, + MEAN = 40, + SUB = 41, + DIV = 42, + SQUEEZE = 43, + UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + STRIDED_SLICE = 45, + BIDIRECTIONAL_SEQUENCE_RNN = 46, + EXP = 47, + TOPK_V2 = 48, + SPLIT = 49, + LOG_SOFTMAX = 50, + // DELEGATE is a special op type for the operations which are delegated to + // other backends. + // WARNING: Experimental interface, subject to change + DELEGATE = 51, + BIDIRECTIONAL_SEQUENCE_LSTM = 52, + CAST = 53, + PRELU = 54, + MAXIMUM = 55, + ARG_MAX = 56, + MINIMUM = 57, + LESS = 58, + NEG = 59, + PADV2 = 60, + GREATER = 61, + GREATER_EQUAL = 62, + LESS_EQUAL = 63, + SELECT = 64, + SLICE = 65, + SIN = 66, + TRANSPOSE_CONV = 67, + SPARSE_TO_DENSE = 68, + TILE = 69, + EXPAND_DIMS = 70, + EQUAL = 71, + NOT_EQUAL = 72, + LOG = 73, + SUM = 74, + SQRT = 75, + RSQRT = 76, + SHAPE = 77, + POW = 78, + ARG_MIN = 79, + FAKE_QUANT = 80, + REDUCE_PROD = 81, + REDUCE_MAX = 82, + PACK = 83, + LOGICAL_OR = 84, + ONE_HOT = 85, + LOGICAL_AND = 86, + LOGICAL_NOT = 87, + UNPACK = 88, + REDUCE_MIN = 89, + FLOOR_DIV = 90, + REDUCE_ANY = 91, + SQUARE = 92, + ZEROS_LIKE = 93, + FILL = 94, + FLOOR_MOD = 95, + RANGE = 96, + RESIZE_NEAREST_NEIGHBOR = 97, + LEAKY_RELU = 98, + SQUARED_DIFFERENCE = 99, + MIRROR_PAD = 100, + ABS = 101, + SPLIT_V = 102, +} + +// Options for the builtin operators. +union BuiltinOptions { + Conv2DOptions, + DepthwiseConv2DOptions, + ConcatEmbeddingsOptions, + LSHProjectionOptions, + Pool2DOptions, + SVDFOptions, + RNNOptions, + FullyConnectedOptions, + SoftmaxOptions, + ConcatenationOptions, + AddOptions, + L2NormOptions, + LocalResponseNormalizationOptions, + LSTMOptions, + ResizeBilinearOptions, + CallOptions, + ReshapeOptions, + SkipGramOptions, + SpaceToDepthOptions, + EmbeddingLookupSparseOptions, + MulOptions, + PadOptions, + GatherOptions, + BatchToSpaceNDOptions, + SpaceToBatchNDOptions, + TransposeOptions, + ReducerOptions, + SubOptions, + DivOptions, + SqueezeOptions, + SequenceRNNOptions, + StridedSliceOptions, + ExpOptions, + TopKV2Options, + SplitOptions, + LogSoftmaxOptions, + CastOptions, + DequantizeOptions, + MaximumMinimumOptions, + ArgMaxOptions, + LessOptions, + NegOptions, + PadV2Options, + GreaterOptions, + GreaterEqualOptions, + LessEqualOptions, + SelectOptions, + SliceOptions, + TransposeConvOptions, + SparseToDenseOptions, + TileOptions, + ExpandDimsOptions, + EqualOptions, + NotEqualOptions, + ShapeOptions, + PowOptions, + ArgMinOptions, + FakeQuantOptions, + PackOptions, + LogicalOrOptions, + OneHotOptions, + LogicalAndOptions, + LogicalNotOptions, + UnpackOptions, + FloorDivOptions, + SquareOptions, + ZerosLikeOptions, + FillOptions, + BidirectionalSequenceLSTMOptions, + BidirectionalSequenceRNNOptions, + UnidirectionalSequenceLSTMOptions, + FloorModOptions, + RangeOptions, + ResizeNearestNeighborOptions, + LeakyReluOptions, + SquaredDifferenceOptions, + MirrorPadOptions, + AbsOptions, + SplitVOptions, +} + +enum Padding : byte { SAME, VALID } + +enum ActivationFunctionType : byte { + NONE = 0, + RELU = 1, + RELU_N1_TO_1 = 2, + RELU6 = 3, + TANH = 4, + SIGN_BIT = 5, +} + +table Conv2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + fused_activation_function:ActivationFunctionType; + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table Pool2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + filter_width:int; + filter_height:int; + fused_activation_function:ActivationFunctionType; +} + +table DepthwiseConv2DOptions { + // Parameters for DepthwiseConv version 1 or above. + padding:Padding; + stride_w:int; + stride_h:int; + depth_multiplier:int; + fused_activation_function:ActivationFunctionType; + // Parameters for DepthwiseConv version 2 or above. + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table ConcatEmbeddingsOptions { + num_channels:int; + num_columns_per_channel:[int]; + embedding_dim_per_channel:[int]; // This could be inferred from parameters. +} + +enum LSHProjectionType: byte { + UNKNOWN = 0, + SPARSE = 1, + DENSE = 2, +} + +table LSHProjectionOptions { + type: LSHProjectionType; +} + +table SVDFOptions { + rank:int; + fused_activation_function:ActivationFunctionType; +} + +// An implementation of TensorFlow RNNCell. +table RNNOptions { + fused_activation_function:ActivationFunctionType; +} + +// An implementation of TensorFlow dynamic_rnn with RNNCell. +table SequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; +} + +// An implementation of TensorFlow bidrectional_dynamic_rnn with RNNCell. +table BidirectionalSequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; + merge_outputs: bool; +} + +enum FullyConnectedOptionsWeightsFormat: byte { + DEFAULT = 0, + SHUFFLED4x16INT8 = 1, +} + +// An implementation of TensorFlow fully_connected (a.k.a Dense) layer. +table FullyConnectedOptions { + // Parameters for FullyConnected version 1 or above. + fused_activation_function:ActivationFunctionType; + + // Parameters for FullyConnected version 2 or above. + weights_format:FullyConnectedOptionsWeightsFormat = DEFAULT; +} + +table SoftmaxOptions { + beta: float; +} + +// An implementation of TensorFlow concat. +table ConcatenationOptions { + axis:int; + fused_activation_function:ActivationFunctionType; +} + +table AddOptions { + fused_activation_function:ActivationFunctionType; +} + +table MulOptions { + fused_activation_function:ActivationFunctionType; +} + +table L2NormOptions { + fused_activation_function:ActivationFunctionType; +} + +table LocalResponseNormalizationOptions { + radius:int; + bias:float; + alpha:float; + beta:float; +} + +enum LSTMKernelType : byte { + // Full LSTM kernel which supports peephole and projection. + FULL = 0, + // Basic LSTM kernels. Equivalent to TensorFlow BasicLSTMCell. + BASIC = 1, +} + +// An implementation of TensorFlow LSTMCell and CoupledInputForgetGateLSTMCell +table LSTMOptions { + // Parameters for LSTM version 1 or above. + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // Parameters for LSTM version 2 or above. + // Basic kernel is only supported in version 2 or above. + kernel_type: LSTMKernelType = FULL; +} + +// An implementation of TensorFlow dynamic_rnn with LSTMCell. +table UnidirectionalSequenceLSTMOptions { + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true then first dimension is sequence, otherwise batch. + time_major:bool; +} + +table BidirectionalSequenceLSTMOptions { + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true, store the outputs of both directions into the first output. + merge_outputs: bool; +} + +table ResizeBilinearOptions { + new_height: int (deprecated); + new_width: int (deprecated); + align_corners: bool; +} + +table ResizeNearestNeighborOptions { + align_corners: bool; +} + +// A call operation options +table CallOptions { + // The subgraph index that needs to be called. + subgraph:uint; +} + +table PadOptions { +} + +table PadV2Options { +} + +table ReshapeOptions { + new_shape:[int]; +} + +table SpaceToBatchNDOptions { +} + +table BatchToSpaceNDOptions { +} + +table SkipGramOptions { + ngram_size: int; + max_skip_size: int; + include_all_ngrams: bool; +} + +table SpaceToDepthOptions { + block_size: int; +} + +table SubOptions { + fused_activation_function:ActivationFunctionType; +} + +table DivOptions { + fused_activation_function:ActivationFunctionType; +} + +table TopKV2Options { +} + +enum CombinerType : byte { + SUM = 0, + MEAN = 1, + SQRTN = 2, +} + +table EmbeddingLookupSparseOptions { + combiner:CombinerType; +} + +table GatherOptions { + axis: int; +} + +table TransposeOptions { +} + +table ExpOptions { +} + +table ReducerOptions { + keep_dims: bool; +} + +table SqueezeOptions { + squeeze_dims:[int]; +} + +table SplitOptions { + num_splits: int; +} + +table SplitVOptions { + num_splits: int; +} + +table StridedSliceOptions { + begin_mask: int; + end_mask: int; + ellipsis_mask: int; + new_axis_mask: int; + shrink_axis_mask: int; +} + +table LogSoftmaxOptions { +} + +table CastOptions { + in_data_type: TensorType; + out_data_type: TensorType; +} + +table DequantizeOptions { +} + +table MaximumMinimumOptions { +} + +table TileOptions { +} + +table ArgMaxOptions { + output_type : TensorType; +} + +table ArgMinOptions { + output_type : TensorType; +} + +table GreaterOptions { +} + +table GreaterEqualOptions { +} + +table LessOptions { +} + +table LessEqualOptions { +} + +table NegOptions { +} + +table SelectOptions { +} + +table SliceOptions { +} + +table TransposeConvOptions { + padding:Padding; + stride_w:int; + stride_h:int; +} + +table ExpandDimsOptions { +} + +table SparseToDenseOptions { + validate_indices:bool; +} + +table EqualOptions { +} + +table NotEqualOptions { +} + +table ShapeOptions { + // Optional output type of the operation (int32 or int64). Defaults to int32. + out_type : TensorType; +} + +table PowOptions { +} + +table FakeQuantOptions { + // Parameters supported by version 1: + min:float; + max:float; + num_bits:int; + + // Parameters supported by version 2: + narrow_range:bool; +} + +table PackOptions { + values_count:int; + axis:int; +} + +table LogicalOrOptions { +} + +table OneHotOptions { + axis:int; +} + +table AbsOptions { +} + + +table LogicalAndOptions { +} + +table LogicalNotOptions { +} + +table UnpackOptions { + num:int; + axis:int; +} + +table FloorDivOptions { +} + +table SquareOptions { +} + +table ZerosLikeOptions { +} + +table FillOptions { +} + +table FloorModOptions { +} + +table RangeOptions { +} + +table LeakyReluOptions { + alpha:float; +} + +table SquaredDifferenceOptions { +} + +enum MirrorPadMode : byte { + // Doesn't include borders. + REFLECT = 0, + // Includes borders. + SYMMETRIC = 1, +} + +table MirrorPadOptions { + mode:MirrorPadMode; +} + +// An OperatorCode can be an enum value (BuiltinOperator) if the operator is a +// builtin, or a string if the operator is custom. +table OperatorCode { + builtin_code:BuiltinOperator; + custom_code:string; + + // The version of the operator. The version need to be bumped whenever new + // parameters are introduced into an op. + version:int = 1; +} + +enum CustomOptionsFormat : byte { + FLEXBUFFERS = 0, +} + +// An operator takes tensors as inputs and outputs. The type of operation being +// performed is determined by an index into the list of valid OperatorCodes, +// while the specifics of each operations is configured using builtin_options +// or custom_options. +table Operator { + // Index into the operator_codes array. Using an integer here avoids + // complicate map lookups. + opcode_index:uint; + + // Optional input and output tensors are indicated by -1. + inputs:[int]; + outputs:[int]; + + builtin_options:BuiltinOptions; + custom_options:[ubyte]; + custom_options_format:CustomOptionsFormat; + + // A list of booleans indicating the input tensors which are being mutated by + // this operator.(e.g. used by RNN and LSTM). + // For example, if the "inputs" array refers to 5 tensors and the second and + // fifth are mutable variables, then this list will contain + // [false, true, false, false, true]. + // + // If the list is empty, no variable is mutated in this operator. + // The list either has the same length as `inputs`, or is empty. + mutating_variable_inputs:[bool]; +} + +// The root type, defining a subgraph, which typically represents an entire +// model. +table SubGraph { + // A list of all tensors used in this subgraph. + tensors:[Tensor]; + + // Indices of the tensors that are inputs into this subgraph. Note this is + // the list of non-static tensors that feed into the subgraph for inference. + inputs:[int]; + + // Indices of the tensors that are outputs out of this subgraph. Note this is + // the list of output tensors that are considered the product of the + // subgraph's inference. + outputs:[int]; + + // All operators, in execution order. + operators:[Operator]; + + // Name of this subgraph (used for debugging). + name:string; +} + +// Table of raw data buffers (used for constant tensors). Referenced by tensors +// by index. The generous alignment accommodates mmap-friendly data structures. +table Buffer { + data:[ubyte] (force_align: 16); +} + +table Model { + // Version of the schema. + version:uint; + + // A list of all operator codes used in this model. This is + // kept in order because operators carry an index into this + // vector. + operator_codes:[OperatorCode]; + + // All the subgraphs of the model. The 0th is assumed to be the main + // model. + subgraphs:[SubGraph]; + + // A description of the model. + description:string; + + // Buffers of the model. + // Note the 0th entry of this array must be an empty buffer (sentinel). + // This is a convention so that tensors without a buffer can provide 0 as + // their buffer. + buffers:[Buffer]; + + // Metadata about the model. Indirects into the existings buffers list. + metadata_buffer:[int]; +} + +root_type Model; diff --git a/runtime/onert/frontend/tflite/tflite_schema.fbs b/runtime/onert/frontend/tflite/tflite_schema.fbs new file mode 100644 index 000000000..9bffb4f3c --- /dev/null +++ b/runtime/onert/frontend/tflite/tflite_schema.fbs @@ -0,0 +1,1095 @@ +// Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved +// Copyright 2017 The TensorFlow Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Revision History +// Version 0: Initial version. +// Version 1: Add subgraphs to schema. +// Version 2: Rename operators to conform to NN API. +// Version 3: Move buffer data from Model.Subgraph.Tensors to Model.Buffers. + +// Change namespace to onert_tflite +namespace onert_tflite; + +// This corresponds to the version. +file_identifier "TFL3"; +// File extension of any written files. +file_extension "tflite"; + +// IMPORTANT: All new members of tables, enums and unions must be added at the +// end to ensure backwards compatibility. + +// The type of data stored in a tensor. +enum TensorType : byte { + FLOAT32 = 0, + FLOAT16 = 1, + INT32 = 2, + UINT8 = 3, + INT64 = 4, + STRING = 5, + BOOL = 6, + INT16 = 7, + COMPLEX64 = 8, + INT8 = 9, + FLOAT64 = 10, +} + +// Custom quantization parameters for experimenting with new quantization +// techniques. +table CustomQuantization { + custom:[ubyte] (force_align: 16); +} + +// Represents a specific quantization technique's parameters. +union QuantizationDetails { + CustomQuantization, +} + +// Parameters for converting a quantized tensor back to float. +table QuantizationParameters { + // These four parameters are the asymmetric linear quantization parameters. + // Given a quantized value q, the corresponding float value f should be: + // f = scale * (q - zero_point) + // For other quantization types, the QuantizationDetails below is used. + min:[float]; // For importing back into tensorflow. + max:[float]; // For importing back into tensorflow. + scale:[float]; // For dequantizing the tensor's values. + zero_point:[long]; + + // If this is not none, the other quantization parameters (i.e. min, max, + // scale, zero_point fields above) are ignored and the value of the + // QuantizationDetails union should be used. + details:QuantizationDetails; + + // Specifies the dimension of the Tensor's shape that the scales and + // zero_points correspond to. For example, a tensor t, with dims=[4, 3, 2, 1] + // with quantization params: + // scale=[1.0, 2.0, 3.0], zero_point=[1, 2, 3], quantization_dimension=1 + // will be quantized across the second dimension of t. + // t[:, 0, :, :] will have scale[0]=1.0, zero_point[0]=1 + // t[:, 1, :, :] will have scale[1]=2.0, zero_point[0]=2 + // t[:, 2, :, :] will have scale[2]=3.0, zero_point[0]=3 + quantized_dimension:int; +} + +// Sparse tensors. +// We use a modification of the TACO format. +// Reference: http://tensor-compiler.org/kjolstad-oopsla17-tensor-compiler.pdf +// +// To encode a conceptual n-dimensional dense tensor with dims (d0, ..., dn-1), +// potentially with a k-dimensional block (0 <= k <= n) with dims +// (dn, ..., dn+k-1), the format needs to specify: +// 1. In what order to traverse these dimensions. For example, to store a 2-D +// matrix in row major order, the traversal order would be (d0, d1), +// whereas to store it in column major order, the traversal order would be +// (d1, d0). If the 2-D matrix has a 2-D inner block, the traversal order +// could be (d0, d1, d2, d3). +// 2. How each block dimension in (dn, ..., dn+k-1) maps to the original +// tensor dimension in (d0, ..., dn-1). +// 3. In the traversal order defined above, the format (dense vs. sparse) and +// index metadata for each dimension. For a dense dimension, this is just +// the size of that dimension. For a sparse dimension, it's the same as +// the compressed index defined in the Compressed Sparse Row (CSR) format. +// (http://scipy-lectures.org/advanced/scipy_sparse/csr_matrix.html) + +// The storage type for a dimension. Currently we support: +// 1. DENSE: each coordinate in this dimension is stored implicitly. +// 2. SPARSE_CSR: only the coordinates with non-zero elements are stored. The +// compression technique is the same what CSR uses. +// More types like a sparse dimension with a different compression technique +// could be added to the list in the future. +enum DimensionType : byte { + DENSE = 0, + SPARSE_CSR = 1, +} + +table Int32Vector { + values:[int]; +} + +table Uint16Vector { + values:[ushort] (force_align: 4); +} + +table Uint8Vector { + values:[ubyte] (force_align: 4); +} + +// Variable-typed buffer to store the index metadata for a sparse dimension. +// The widest type is Int32 instead of UInt32 because tensor's shape is a int32 +// vector. We don't want the per-dimensional index to overflow that range. +union SparseIndexVector { + Int32Vector, + Uint16Vector, + Uint8Vector +} + +table DimensionMetadata { + // Whether a dimension is dense or sparse. + format:DimensionType; + // Index metadata used for a dimension. + // - If format is DimensionType.DENSE then we use the dense_size field to + // store the size of that dimension. Each index in that dimension is + // stored implicitly. + // - If format is DimensionType.SPARSE_CSR then we use array_segments and + // array_indices to encode that dimension. array_segments represents how + // to segment the indices array, each segment corresponds to one element + // in the previous dimension. array_indices represents the index of the + // non-zero elements within this dimension (as those in the CSR matrix + // format, where the first array is row pointers and the second array is + // column indices). + dense_size:int; + array_segments:SparseIndexVector; + array_indices:SparseIndexVector; +} + +// Parameters to encode a sparse TfLite tensor. +table SparsityParameters { + // The traversal order of the dimensions defined in the `shape` field of the + // conceptual dense tensor. For a n-dimensional tensors with dims (d0, d1, + // ..., dn-1), + // - if not block sparse, the traversal_order is just a permutation of (d0, + // ..., dn-1). For example, a 2-D matrix stored in row-major order would + // have traversal_order = (d0, d1). + // - if block sparse with a k-dimensional block (0 <= k <= n), the + // traversal_order has n + k elements. The first n elements are still a + // permutation of (d0, ..., dn-1). The lask k elements are a permutation + // of (dn, ..., dn+k-1), defining how to traverse a block internally. For + // example, a 2-D matrix with 2-D blocks, both stored in row-major order + // would have traversal_order = (d0, d1, d2, d3). + traversal_order:[int]; + // For an n-dimensional tensor with a k-dimensional block (0 <= k <= n), + // stores how a block dimension in (dn, ..., dn+k-1) maps to the original + // tensor dimension in (d0, ..., dn). + // It's stored in the order of (dn, ..., dn+k-1). + // If not block-sparse, this field is NULL. + block_map:[int]; + // In the traversal order defined above, the metadata needed for + // each dimension to locate the non-zero values in the original dense tensor. + // The size of the dim_metadata array = the size of the traversal_order array + // = n + k. + dim_metadata:[DimensionMetadata]; +} + +table Tensor { + // The tensor shape. The meaning of each entry is operator-specific but + // builtin ops use: [batch size, height, width, number of channels] (That's + // Tensorflow's NHWC). + shape:[int]; + type:TensorType; + // An index that refers to the buffers table at the root of the model. Or, + // if there is no data buffer associated (i.e. intermediate results), then + // this is 0 (which refers to an always existent empty buffer). + // + // The data_buffer itself is an opaque container, with the assumption that the + // target device is little-endian. In addition, all builtin operators assume + // the memory is ordered such that if `shape` is [4, 3, 2], then index + // [i, j, k] maps to data_buffer[i*3*2 + j*2 + k]. + buffer:uint; + name:string; // For debugging and importing back into tensorflow. + quantization:QuantizationParameters; // Optional. + + is_variable:bool = false; + + // Parameters to encode a sparse tensor. See the example in + // tensorflow/lite/testdata/sparse_tensor.json. + sparsity:SparsityParameters; // Optional. + + // Encodes `shape` with unknown dimensions. Unknown dimensions are + // represented with -1. + shape_signature:[int]; // Optional. +} + +// A list of builtin operators. Builtin operators are slightly faster than custom +// ones, but not by much. Moreover, while custom operators accept an opaque +// object containing configuration parameters, builtins have a predetermined +// set of acceptable options. + +enum BuiltinOperator : byte { + ADD = 0, + AVERAGE_POOL_2D = 1, + CONCATENATION = 2, + CONV_2D = 3, + DEPTHWISE_CONV_2D = 4, + DEPTH_TO_SPACE = 5, + DEQUANTIZE = 6, + EMBEDDING_LOOKUP = 7, + FLOOR = 8, + FULLY_CONNECTED = 9, + HASHTABLE_LOOKUP = 10, + L2_NORMALIZATION = 11, + L2_POOL_2D = 12, + LOCAL_RESPONSE_NORMALIZATION = 13, + LOGISTIC = 14, + LSH_PROJECTION = 15, + LSTM = 16, + MAX_POOL_2D = 17, + MUL = 18, + RELU = 19, + // NOTE(aselle): RELU_N1_TO_1 used to be called RELU1, but it was renamed + // since different model developers use RELU1 in different ways. Never + // create another op called RELU1. + RELU_N1_TO_1 = 20, + RELU6 = 21, + RESHAPE = 22, + RESIZE_BILINEAR = 23, + RNN = 24, + SOFTMAX = 25, + SPACE_TO_DEPTH = 26, + SVDF = 27, + TANH = 28, + // TODO(aselle): Consider rename to CONCATENATE_EMBEDDINGS + CONCAT_EMBEDDINGS = 29, + SKIP_GRAM = 30, + CALL = 31, + CUSTOM = 32, + EMBEDDING_LOOKUP_SPARSE = 33, + PAD = 34, + UNIDIRECTIONAL_SEQUENCE_RNN = 35, + GATHER = 36, + BATCH_TO_SPACE_ND = 37, + SPACE_TO_BATCH_ND = 38, + TRANSPOSE = 39, + MEAN = 40, + SUB = 41, + DIV = 42, + SQUEEZE = 43, + UNIDIRECTIONAL_SEQUENCE_LSTM = 44, + STRIDED_SLICE = 45, + BIDIRECTIONAL_SEQUENCE_RNN = 46, + EXP = 47, + TOPK_V2 = 48, + SPLIT = 49, + LOG_SOFTMAX = 50, + // DELEGATE is a special op type for the operations which are delegated to + // other backends. + // WARNING: Experimental interface, subject to change + DELEGATE = 51, + BIDIRECTIONAL_SEQUENCE_LSTM = 52, + CAST = 53, + PRELU = 54, + MAXIMUM = 55, + ARG_MAX = 56, + MINIMUM = 57, + LESS = 58, + NEG = 59, + PADV2 = 60, + GREATER = 61, + GREATER_EQUAL = 62, + LESS_EQUAL = 63, + SELECT = 64, + SLICE = 65, + SIN = 66, + TRANSPOSE_CONV = 67, + SPARSE_TO_DENSE = 68, + TILE = 69, + EXPAND_DIMS = 70, + EQUAL = 71, + NOT_EQUAL = 72, + LOG = 73, + SUM = 74, + SQRT = 75, + RSQRT = 76, + SHAPE = 77, + POW = 78, + ARG_MIN = 79, + FAKE_QUANT = 80, + REDUCE_PROD = 81, + REDUCE_MAX = 82, + PACK = 83, + LOGICAL_OR = 84, + ONE_HOT = 85, + LOGICAL_AND = 86, + LOGICAL_NOT = 87, + UNPACK = 88, + REDUCE_MIN = 89, + FLOOR_DIV = 90, + REDUCE_ANY = 91, + SQUARE = 92, + ZEROS_LIKE = 93, + FILL = 94, + FLOOR_MOD = 95, + RANGE = 96, + RESIZE_NEAREST_NEIGHBOR = 97, + LEAKY_RELU = 98, + SQUARED_DIFFERENCE = 99, + MIRROR_PAD = 100, + ABS = 101, + SPLIT_V = 102, + UNIQUE = 103, + CEIL = 104, + REVERSE_V2 = 105, + ADD_N = 106, + GATHER_ND = 107, + COS = 108, + WHERE = 109, + RANK = 110, + ELU = 111, + REVERSE_SEQUENCE = 112, + MATRIX_DIAG = 113, + QUANTIZE = 114, + MATRIX_SET_DIAG = 115, + ROUND = 116, + HARD_SWISH = 117, + IF = 118, + WHILE = 119, + NON_MAX_SUPPRESSION_V4 = 120, + NON_MAX_SUPPRESSION_V5 = 121, + SCATTER_ND = 122, + SELECT_V2 = 123, + DENSIFY = 124, + SEGMENT_SUM = 125, + BATCH_MATMUL = 126 +} + + +// Options for the builtin operators. +union BuiltinOptions { + Conv2DOptions, + DepthwiseConv2DOptions, + ConcatEmbeddingsOptions, + LSHProjectionOptions, + Pool2DOptions, + SVDFOptions, + RNNOptions, + FullyConnectedOptions, + SoftmaxOptions, + ConcatenationOptions, + AddOptions, + L2NormOptions, + LocalResponseNormalizationOptions, + LSTMOptions, + ResizeBilinearOptions, + CallOptions, + ReshapeOptions, + SkipGramOptions, + SpaceToDepthOptions, + EmbeddingLookupSparseOptions, + MulOptions, + PadOptions, + GatherOptions, + BatchToSpaceNDOptions, + SpaceToBatchNDOptions, + TransposeOptions, + ReducerOptions, + SubOptions, + DivOptions, + SqueezeOptions, + SequenceRNNOptions, + StridedSliceOptions, + ExpOptions, + TopKV2Options, + SplitOptions, + LogSoftmaxOptions, + CastOptions, + DequantizeOptions, + MaximumMinimumOptions, + ArgMaxOptions, + LessOptions, + NegOptions, + PadV2Options, + GreaterOptions, + GreaterEqualOptions, + LessEqualOptions, + SelectOptions, + SliceOptions, + TransposeConvOptions, + SparseToDenseOptions, + TileOptions, + ExpandDimsOptions, + EqualOptions, + NotEqualOptions, + ShapeOptions, + PowOptions, + ArgMinOptions, + FakeQuantOptions, + PackOptions, + LogicalOrOptions, + OneHotOptions, + LogicalAndOptions, + LogicalNotOptions, + UnpackOptions, + FloorDivOptions, + SquareOptions, + ZerosLikeOptions, + FillOptions, + BidirectionalSequenceLSTMOptions, + BidirectionalSequenceRNNOptions, + UnidirectionalSequenceLSTMOptions, + FloorModOptions, + RangeOptions, + ResizeNearestNeighborOptions, + LeakyReluOptions, + SquaredDifferenceOptions, + MirrorPadOptions, + AbsOptions, + SplitVOptions, + UniqueOptions, + ReverseV2Options, + AddNOptions, + GatherNdOptions, + CosOptions, + WhereOptions, + RankOptions, + ReverseSequenceOptions, + MatrixDiagOptions, + QuantizeOptions, + MatrixSetDiagOptions, + HardSwishOptions, + IfOptions, + WhileOptions, + DepthToSpaceOptions, + NonMaxSuppressionV4Options, + NonMaxSuppressionV5Options, + ScatterNdOptions, + SelectV2Options, + DensifyOptions, + SegmentSumOptions, + BatchMatMulOptions +} + +enum Padding : byte { SAME, VALID } + +enum ActivationFunctionType : byte { + NONE = 0, + RELU = 1, + RELU_N1_TO_1 = 2, + RELU6 = 3, + TANH = 4, + SIGN_BIT = 5, +} + +table Conv2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + fused_activation_function:ActivationFunctionType; + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table Pool2DOptions { + padding:Padding; + stride_w:int; + stride_h:int; + filter_width:int; + filter_height:int; + fused_activation_function:ActivationFunctionType; +} + +table DepthwiseConv2DOptions { + // Parameters for DepthwiseConv version 1 or above. + padding:Padding; + stride_w:int; + stride_h:int; + // `depth_multiplier` is redundant. It's used by CPU kernels in + // TensorFlow 2.0 or below, but ignored in versions above. + // See comments in lite/c/builtin_op_data.h for more details. + depth_multiplier:int; + fused_activation_function:ActivationFunctionType; + // Parameters for DepthwiseConv version 2 or above. + dilation_w_factor:int = 1; + dilation_h_factor:int = 1; +} + +table ConcatEmbeddingsOptions { + num_channels:int; + num_columns_per_channel:[int]; + embedding_dim_per_channel:[int]; // This could be inferred from parameters. +} + +enum LSHProjectionType: byte { + UNKNOWN = 0, + SPARSE = 1, + DENSE = 2, +} + +table LSHProjectionOptions { + type: LSHProjectionType; +} + +table SVDFOptions { + rank:int; + fused_activation_function:ActivationFunctionType; + // For weights-only quantization, use asymmetric quantization for non + // constant inputs at evaluation time. + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow RNNCell. +table RNNOptions { + fused_activation_function:ActivationFunctionType; + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow dynamic_rnn with RNNCell. +table SequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; + asymmetric_quantize_inputs:bool; +} + +// An implementation of TensorFlow bidrectional_dynamic_rnn with RNNCell. +table BidirectionalSequenceRNNOptions { + time_major:bool; + fused_activation_function:ActivationFunctionType; + merge_outputs: bool; + asymmetric_quantize_inputs:bool; +} + +enum FullyConnectedOptionsWeightsFormat: byte { + DEFAULT = 0, + SHUFFLED4x16INT8 = 1, +} + +// An implementation of TensorFlow fully_connected (a.k.a Dense) layer. +table FullyConnectedOptions { + // Parameters for FullyConnected version 1 or above. + fused_activation_function:ActivationFunctionType; + + // Parameters for FullyConnected version 2 or above. + weights_format:FullyConnectedOptionsWeightsFormat = DEFAULT; + + // Parameters for FullyConnected version 5 or above. + // If set to true, then the number of dimension is preserved. Furthermore, + // all but the last dimension of the input and output shapes will be equal. + keep_num_dims: bool; + + // Parameters for FullyConnected version 7 or above. + // If set to true, then weights-only op will use asymmetric quantization for + // inputs. + asymmetric_quantize_inputs: bool; +} + +table SoftmaxOptions { + beta: float; +} + +// An implementation of TensorFlow concat. +table ConcatenationOptions { + axis:int; + fused_activation_function:ActivationFunctionType; +} + +table AddOptions { + fused_activation_function:ActivationFunctionType; +} + +table MulOptions { + fused_activation_function:ActivationFunctionType; +} + +table L2NormOptions { + fused_activation_function:ActivationFunctionType; +} + +table LocalResponseNormalizationOptions { + radius:int; + bias:float; + alpha:float; + beta:float; +} + +enum LSTMKernelType : byte { + // Full LSTM kernel which supports peephole and projection. + FULL = 0, + // Basic LSTM kernels. Equivalent to TensorFlow BasicLSTMCell. + BASIC = 1, +} + +// An implementation of TensorFlow LSTMCell and CoupledInputForgetGateLSTMCell +table LSTMOptions { + // Parameters for LSTM version 1 or above. + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // Parameters for LSTM version 2 or above. + // Basic kernel is only supported in version 2 or above. + kernel_type: LSTMKernelType = FULL; + + // Parameters for LSTM version 4 or above. + asymmetric_quantize_inputs: bool; +} + +// An implementation of TensorFlow dynamic_rnn with LSTMCell. +table UnidirectionalSequenceLSTMOptions { + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true then first dimension is sequence, otherwise batch. + time_major:bool; + + // Parameter for Unidirectional Sequence LSTM version 4. + asymmetric_quantize_inputs:bool; +} + +table BidirectionalSequenceLSTMOptions { + // Parameters supported by version 1: + fused_activation_function:ActivationFunctionType; + cell_clip: float; // Optional, 0.0 means no clipping + proj_clip: float; // Optional, 0.0 means no clipping + + // If true, store the outputs of both directions into the first output. + merge_outputs: bool; + + // Parameters supported by version 2: + // If true then first dimension is sequence, otherwise batch. + // Version 1 implementations assumed time_major to be true, so this default + // value should never change. + time_major: bool = true; + + // Parameters for version 3 or above. + asymmetric_quantize_inputs:bool; +} + +table ResizeBilinearOptions { + new_height: int (deprecated); + new_width: int (deprecated); + align_corners: bool; + half_pixel_centers: bool; +} + +table ResizeNearestNeighborOptions { + align_corners: bool; +} + +// A call operation options +table CallOptions { + // The subgraph index that needs to be called. + subgraph:uint; +} + +table PadOptions { +} + +table PadV2Options { +} + +table ReshapeOptions { + new_shape:[int]; +} + +table SpaceToBatchNDOptions { +} + +table BatchToSpaceNDOptions { +} + +table SkipGramOptions { + ngram_size: int; + max_skip_size: int; + include_all_ngrams: bool; +} + +table SpaceToDepthOptions { + block_size: int; +} + +table DepthToSpaceOptions { + block_size: int; +} + +table SubOptions { + fused_activation_function:ActivationFunctionType; +} + +table DivOptions { + fused_activation_function:ActivationFunctionType; +} + +table TopKV2Options { +} + +enum CombinerType : byte { + SUM = 0, + MEAN = 1, + SQRTN = 2, +} + +table EmbeddingLookupSparseOptions { + combiner:CombinerType; +} + +table GatherOptions { + axis: int; +} + +table TransposeOptions { +} + +table ExpOptions { +} + +table CosOptions { +} + +table ReducerOptions { + keep_dims: bool; +} + +table SqueezeOptions { + squeeze_dims:[int]; +} + +table SplitOptions { + num_splits: int; +} + +table SplitVOptions { + num_splits: int; +} + +table StridedSliceOptions { + begin_mask: int; + end_mask: int; + ellipsis_mask: int; + new_axis_mask: int; + shrink_axis_mask: int; +} + +table LogSoftmaxOptions { +} + +table CastOptions { + in_data_type: TensorType; + out_data_type: TensorType; +} + +table DequantizeOptions { +} + +table MaximumMinimumOptions { +} + +table TileOptions { +} + +table ArgMaxOptions { + output_type : TensorType; +} + +table ArgMinOptions { + output_type : TensorType; +} + +table GreaterOptions { +} + +table GreaterEqualOptions { +} + +table LessOptions { +} + +table LessEqualOptions { +} + +table NegOptions { +} + +table SelectOptions { +} + +table SliceOptions { +} + +table TransposeConvOptions { + padding:Padding; + stride_w:int; + stride_h:int; +} + +table ExpandDimsOptions { +} + +table SparseToDenseOptions { + validate_indices:bool; +} + +table EqualOptions { +} + +table NotEqualOptions { +} + +table ShapeOptions { + // Optional output type of the operation (int32 or int64). Defaults to int32. + out_type : TensorType; +} + +table RankOptions { +} + +table PowOptions { +} + +table FakeQuantOptions { + // Parameters supported by version 1: + min:float; + max:float; + num_bits:int; + + // Parameters supported by version 2: + narrow_range:bool; +} + +table PackOptions { + values_count:int; + axis:int; +} + +table LogicalOrOptions { +} + +table OneHotOptions { + axis:int; +} + +table AbsOptions { +} + + +table HardSwishOptions { +} + +table LogicalAndOptions { +} + +table LogicalNotOptions { +} + +table UnpackOptions { + num:int; + axis:int; +} + +table FloorDivOptions { +} + +table SquareOptions { +} + +table ZerosLikeOptions { +} + +table FillOptions { +} + +table FloorModOptions { +} + +table RangeOptions { +} + +table LeakyReluOptions { + alpha:float; +} + +table SquaredDifferenceOptions { +} + +enum MirrorPadMode : byte { + // Doesn't include borders. + REFLECT = 0, + // Includes borders. + SYMMETRIC = 1, +} + +table MirrorPadOptions { + mode:MirrorPadMode; +} + +table UniqueOptions { + idx_out_type:TensorType = INT32; +} + +table ReverseV2Options { +} + +table AddNOptions { +} + +table GatherNdOptions { +} + +table WhereOptions { +} + +table ReverseSequenceOptions { + seq_dim:int; + batch_dim:int = 0; +} + +table MatrixDiagOptions { +} + +table QuantizeOptions { +} + +table MatrixSetDiagOptions { +} + +table IfOptions { + then_subgraph_index:int; + else_subgraph_index:int; +} + +table WhileOptions { + cond_subgraph_index:int; + body_subgraph_index:int; +} + +table NonMaxSuppressionV4Options { +} + +table NonMaxSuppressionV5Options { +} + +table ScatterNdOptions { +} + +table SelectV2Options { +} + +table DensifyOptions { +} + +table SegmentSumOptions { +} + +table BatchMatMulOptions { + adjoint_lhs:bool; + adjoint_rhs:bool; +} + +// An OperatorCode can be an enum value (BuiltinOperator) if the operator is a +// builtin, or a string if the operator is custom. +table OperatorCode { + builtin_code:BuiltinOperator; + custom_code:string; + + // The version of the operator. The version need to be bumped whenever new + // parameters are introduced into an op. + version:int = 1; +} + +enum CustomOptionsFormat : byte { + FLEXBUFFERS = 0, +} + +// An operator takes tensors as inputs and outputs. The type of operation being +// performed is determined by an index into the list of valid OperatorCodes, +// while the specifics of each operations is configured using builtin_options +// or custom_options. +table Operator { + // Index into the operator_codes array. Using an integer here avoids + // complicate map lookups. + opcode_index:uint; + + // Optional input are indicated by -1. + inputs:[int]; + outputs:[int]; + + builtin_options:BuiltinOptions; + custom_options:[ubyte]; + custom_options_format:CustomOptionsFormat; + + // A list of booleans indicating the input tensors which are being mutated by + // this operator.(e.g. used by RNN and LSTM). + // For example, if the "inputs" array refers to 5 tensors and the second and + // fifth are mutable variables, then this list will contain + // [false, true, false, false, true]. + // + // If the list is empty, no variable is mutated in this operator. + // The list either has the same length as `inputs`, or is empty. + mutating_variable_inputs:[bool]; + + // A list of indices to the subgraph's "tensors" that are internal to an Op. + // Internal tensors are those that do not flow in or out of the operation, + // but instead are part of internal computation. As such, the operation's + // implementation may manage its memory more efficiently. They are needed + // however (i.e. not just an implementation detail) since they are part of the + // computation, which may require relevant metadata such as quantization + // parameters. + intermediates:[int]; +} + +// The root type, defining a subgraph, which typically represents an entire +// model. +table SubGraph { + // A list of all tensors used in this subgraph. + tensors:[Tensor]; + + // Indices of the tensors that are inputs into this subgraph. Note this is + // the list of non-static tensors that feed into the subgraph for inference. + inputs:[int]; + + // Indices of the tensors that are outputs out of this subgraph. Note this is + // the list of output tensors that are considered the product of the + // subgraph's inference. + outputs:[int]; + + // All operators, in execution order. + operators:[Operator]; + + // Name of this subgraph (used for debugging). + name:string; +} + +// Table of raw data buffers (used for constant tensors). Referenced by tensors +// by index. The generous alignment accommodates mmap-friendly data structures. +table Buffer { + data:[ubyte] (force_align: 16); +} + +table Metadata { + // A human readable string to uniquely identify a Metadata. + name:string; + // An index to the buffers table. + buffer:uint; +} + +table Model { + // Version of the schema. + version:uint; + + // A list of all operator codes used in this model. This is + // kept in order because operators carry an index into this + // vector. + operator_codes:[OperatorCode]; + + // All the subgraphs of the model. The 0th is assumed to be the main + // model. + subgraphs:[SubGraph]; + + // A description of the model. + description:string; + + // Buffers of the model. + // Note the 0th entry of this array must be an empty buffer (sentinel). + // This is a convention so that tensors without a buffer can provide 0 as + // their buffer. + buffers:[Buffer]; + + // Metadata about the model. Indirects into the existings buffers list. + // Deprecated, prefer to use metadata field. + metadata_buffer:[int]; + + // Metadata about the model. + metadata:[Metadata]; +} + +root_type Model; diff --git a/runtime/onert/sample/CMakeLists.txt b/runtime/onert/sample/CMakeLists.txt new file mode 100644 index 000000000..d853ba634 --- /dev/null +++ b/runtime/onert/sample/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(minimal) diff --git a/runtime/onert/sample/minimal/CMakeLists.txt b/runtime/onert/sample/minimal/CMakeLists.txt new file mode 100644 index 000000000..6f4b02761 --- /dev/null +++ b/runtime/onert/sample/minimal/CMakeLists.txt @@ -0,0 +1,10 @@ +if(NOT BUILD_MINIMAL_SAMPLE) + return() +endif(NOT BUILD_MINIMAL_SAMPLE) + +list(APPEND MINIMAL_SRCS "src/minimal.cc") + +add_executable(minimal ${MINIMAL_SRCS}) +target_link_libraries(minimal nnfw-dev pthread dl) + +install(TARGETS minimal DESTINATION bin) diff --git a/runtime/onert/sample/minimal/README.md b/runtime/onert/sample/minimal/README.md new file mode 100644 index 000000000..fecad6fb2 --- /dev/null +++ b/runtime/onert/sample/minimal/README.md @@ -0,0 +1,13 @@ +# minimal + +`minimal` is a simple driver to run `nnpackage` with nnfw API. + +It takes `nnpackage` as input. It uses **nnfwAPI** internally. + +It assumes model of float32 tensor type as an input. + +## Usage + +``` +$ ./minimal path_to_nnpackage_directory +``` diff --git a/runtime/onert/sample/minimal/src/minimal.cc b/runtime/onert/sample/minimal/src/minimal.cc new file mode 100644 index 000000000..d55569ba2 --- /dev/null +++ b/runtime/onert/sample/minimal/src/minimal.cc @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nnfw.h" +#include + +uint64_t num_elems(const nnfw_tensorinfo *ti) +{ + uint64_t n = 1; + for (uint32_t i = 0; i < ti->rank; ++i) + { + n *= ti->dims[i]; + } + return n; +} + +int main(const int argc, char **argv) +{ + nnfw_session *session = nullptr; + nnfw_create_session(&session); + + // Loading nnpackage + nnfw_load_model_from_file(session, argv[1]); + + // Use acl_neon backend for CONV_2D and acl_cl for otherwise. + // Note that defalut backend is acl_cl + nnfw_set_op_backend(session, "CONV_2D", "acl_neon"); + + // Compile model + nnfw_prepare(session); + + // Prepare input. Here we just allocate dummy input arrays. + std::vector input; + nnfw_tensorinfo ti; + nnfw_input_tensorinfo(session, 0, &ti); // get first input's info + uint32_t input_elements = num_elems(&ti); + input.resize(input_elements); + // TODO: Please add initialization for your input. + nnfw_set_input(session, 0, ti.dtype, input.data(), sizeof(float) * input_elements); + + // Prepare output + std::vector output; + nnfw_output_tensorinfo(session, 0, &ti); // get first output's info + uint32_t output_elements = num_elems(&ti); + output.resize(output_elements); + nnfw_set_output(session, 0, ti.dtype, output.data(), sizeof(float) * output_elements); + + // Do inference + nnfw_run(session); + + // TODO: Please print or compare the output value in your way. + + nnfw_close_session(session); + + return 0; +} diff --git a/runtime/onert/test/CMakeLists.txt b/runtime/onert/test/CMakeLists.txt new file mode 100644 index 000000000..0abdd4880 --- /dev/null +++ b/runtime/onert/test/CMakeLists.txt @@ -0,0 +1,15 @@ +set(TEST_ONERT test_onert) + +file(GLOB_RECURSE TESTS "*.cc") + +add_executable(${TEST_ONERT} ${TESTS}) + +target_include_directories(${TEST_ONERT} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../core/src) + +target_link_libraries(${TEST_ONERT} onert_core) +target_link_libraries(${TEST_ONERT} gtest) +target_link_libraries(${TEST_ONERT} gtest_main) +target_link_libraries(${TEST_ONERT} ${LIB_PTHREAD} dl) +add_test(${TEST_ONERT} ${TEST_ONERT}) + +install(TARGETS ${TEST_ONERT} DESTINATION unittest) diff --git a/runtime/onert/test/core/compiler/Scheduler.cc b/runtime/onert/test/core/compiler/Scheduler.cc new file mode 100644 index 000000000..926b82d94 --- /dev/null +++ b/runtime/onert/test/core/compiler/Scheduler.cc @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace +{ +using namespace onert; +using namespace ir; +using namespace backend; +using namespace operation; +using namespace exec; + +// +// Mock backends classes +// + +// Backend could be created without ShapeFixer. +// But it is used by scheduler to detect which operations are supported by backend. +struct MockShapeFixer : IShapeFixer +{ + void visit(const Add &) override {} + void visit(const Sub &) override {} + void visit(const Mul &) override {} + void visit(const FullyConnected &) override {} +}; + +struct MockConfigCPU : public IConfig +{ + std::string id() override { return "cpu"; } + bool initialize() override { return true; }; + bool SupportPermutation() override { return false; } +}; + +struct MockBackendCPU : public Backend +{ + std::shared_ptr config() const override { return std::make_shared(); } + std::unique_ptr + newContext(const Graph &, const std::shared_ptr &, bool) const override + { + return std::unique_ptr(new BackendContext{ + this, nullptr, nullptr, nullptr, nullptr, std::make_shared()}); + } +}; + +struct MockConfigGPU : public IConfig +{ + std::string id() override { return "gpu"; } + bool initialize() override { return true; }; + bool SupportPermutation() override { return false; } +}; + +struct MockBackendGPU : public Backend +{ + std::shared_ptr config() const override { return std::make_shared(); } + std::unique_ptr + newContext(const Graph &, const std::shared_ptr &, bool) const override + { + return std::unique_ptr(new BackendContext{ + this, nullptr, nullptr, nullptr, nullptr, std::make_shared()}); + } +}; + +struct MockConfigNPU : public IConfig +{ + std::string id() override { return "npu"; } + bool initialize() override { return true; }; + bool SupportPermutation() override { return false; } +}; + +struct MockBackendNPU : public Backend +{ + std::shared_ptr config() const override { return std::make_shared(); } + std::unique_ptr + newContext(const Graph &, const std::shared_ptr &, bool) const override + { + return std::unique_ptr(new BackendContext{ + this, nullptr, nullptr, nullptr, nullptr, std::make_shared()}); + } +}; + +// +// Constants +// + +const int OPERAND_ELEMS = 268203; +const int OPERAND_SIZE = OPERAND_ELEMS * 4; +const int OPERATION_SIZE = OPERAND_SIZE * 3; + +const std::string LINEAR("Linear"); +const std::string DATAFLOW("Dataflow"); +const std::string PARALLEL("Parallel"); + +// +// Helper functions +// + +// Set executor through environment variable +void setExecutor(const std::string &executor) { setenv("EXECUTOR", executor.c_str(), true); } + +// Set profiling mode through environment variable +void setProfilingMode(const bool value) { setenv("PROFILING_MODE", value ? "1" : "0", true); } + +// Calculate operation size by addition sizes of all input and output operands +uint32_t calcOpSize(const std::shared_ptr &graph, const OperationIndex &op_idx) +{ + uint32_t size = 0; + const auto &op = graph->operations().at(op_idx); + for (const auto &ind : op.getInputs() + op.getOutputs()) + size += graph->operands().at(ind).info().total_size(); + return size; +} + +// Set execution operation time. This method is needed since ExecutionTime has only +// 'updateOperationExecTime' method. +void setOperationExecTime(ExecTime &et, const Backend *backend, const std::string &operation, + bool quant, uint32_t op_size, int64_t time) +{ + // You shouldn't set negative time with this method since nnfw JSON deserializer can't read it + assert(time > 0); + int64_t prev_time = et.getOperationExecTime(backend, operation, quant, op_size); + int64_t time_to_set = prev_time == ExecTime::NOT_FOUND ? time : 2 * time - prev_time; + et.updateOperationExecTime(backend, operation, quant, op_size, time_to_set); + assert(et.getOperationExecTime(backend, operation, quant, op_size) == time); +} + +// Set same execution time for all given backends/operations +void setOperationsExecutionTime(const std::vector &backends, + const std::vector &op_names, + const std::vector &op_sizes, int64_t exec_time) +{ + assert(op_names.size() == op_sizes.size()); + ExecTime et(backends); + for (int i = 0; i < op_names.size(); ++i) + { + for (auto &backend : backends) + setOperationExecTime(et, backend, op_names[i], false, op_sizes[i], exec_time); + } + et.uploadOperationsExecTime(); +} + +// Set permute time from one backend to another. This method is needed since ExecutionTime has only +// 'updatePermuteTime' method. +void setPermutationTime(ExecTime &et, const Backend *from_backend, const Backend *to_backend, + bool quant, uint32_t op_size, int64_t time) +{ + // You shouldn't set negative time with this method since nnfw JSON deserializer can't read it + assert(time > 0); + int64_t prev_time = et.getPermuteTime(from_backend, to_backend, quant, op_size); + int64_t time_to_set = prev_time == ExecTime::NOT_FOUND ? time : 2 * time - prev_time; + et.updatePermuteTime(from_backend, to_backend, quant, op_size, time_to_set); + assert(et.getPermuteTime(from_backend, to_backend, quant, op_size) == time); +} + +// Set same permutation time between all given backends +void setPermutationsExecutionTime(const std::vector &backends, + const int operand_size, const int64_t exec_time) +{ + ExecTime et(backends); + for (const auto &backend : backends) + { + for (auto &other_backend : backends) + { + if (backend == other_backend) + continue; + setPermutationTime(et, backend, other_backend, false, operand_size, exec_time); + } + } + et.uploadOperationsExecTime(); +} + +// +// Functions for creating graphs +// + +using OIS = OperandIndexSequence; + +template +OperationIndex create(std::shared_ptr graph, Types &&... args) +{ + typename NodeT::Param op_params{Activation::NONE}; + auto op = std::make_unique(std::forward(args)..., op_params); + auto op_idx = graph->addOperation(std::move(op)); + // For now in scheduler test all operations in tested graphs has same size (for simplicity) + assert(calcOpSize(graph, op_idx) == OPERATION_SIZE); + return op_idx; +} + +// Create straight graph: Add->Sub->Mul +std::shared_ptr createStraightGraph() +{ + auto graph = std::make_shared(); + const TypeInfo float_op(DataType::FLOAT32); + + // Create add node + auto add_lhs_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto add_rhs_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto add_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + create(graph, OIS{add_lhs_idx, add_rhs_idx}, OIS{add_out_idx}); + + // Create sub node + auto sub_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto sub_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + create(graph, OIS{add_out_idx, sub_const_idx}, OIS{sub_out_idx}); + + // Create mul node + auto mul_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto mul_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + create(graph, OIS{sub_out_idx, mul_const_idx}, OIS{mul_out_idx}); + + graph->finishBuilding(); + return graph; +} + +/* Create branched graph: + * [Add] + * // \\ + * [Mul1] [FC2] + * || || + * [Mul2] [FC2] + * \\ // + * [Sub] + */ +std::shared_ptr createBranchedGraph() +{ + auto graph = std::make_shared(); + const TypeInfo float_op(DataType::FLOAT32); + + // Create add node + auto add_lhs_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto add_rhs_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto add_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + create(graph, OIS{add_lhs_idx, add_rhs_idx}, OIS{add_out_idx}); + + // Create mul1 node + auto mul1_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto mul1_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + create(graph, OIS{add_out_idx, mul1_const_idx}, OIS{mul1_out_idx}); + + // Create mul2 node + auto mul2_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto mul2_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + create(graph, OIS{mul1_out_idx, mul2_const_idx}, OIS{mul2_out_idx}); + + // Create fc1 node + auto fc1_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto fc1_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + create(graph, OIS{add_out_idx, fc1_const_idx}, OIS{fc1_out_idx}); + + // Create fc2 node + auto fc2_const_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + auto fc2_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + create(graph, OIS{fc1_out_idx, fc2_const_idx}, OIS{fc2_out_idx}); + + // Create add2 node + auto sub_out_idx = graph->addOperand(ir::Shape{OPERAND_ELEMS}, float_op); + create(graph, OIS{mul2_out_idx, fc2_out_idx}, OIS{sub_out_idx}); + + graph->finishBuilding(); + return graph; +} + +// +// Tests setup/teardown +// + +// SetUp/TearDown methods runs before/after each test and performs actions common for each test +class SchedulerTest : public ::testing::Test +{ +protected: + void SetUp() override + { + // Initialize mock backends + _cpu_backend = new MockBackendCPU(); + _gpu_backend = new MockBackendGPU(); + _npu_backend = new MockBackendNPU(); + _mock_backends = {_cpu_backend, _gpu_backend, _npu_backend}; + + // Remove previous profile data if it exists + if (!remove("exec_time.json")) + { + // DO NOTHING (no profile data) + } + + // Remember original value of 'EXECUTOR' environment variable + char *executor = std::getenv("EXECUTOR"); + _original_executor = executor == nullptr ? "" : executor; + + // Remember original value of 'PROFILING_MODE' environment variable + char *profiling_mode = std::getenv("PROFILING_MODE"); + _original_profiling_mode = profiling_mode == nullptr ? "" : profiling_mode; + } + + void TearDown() override + { + delete _cpu_backend; + delete _gpu_backend; + delete _npu_backend; + EXPECT_EQ(remove("exec_time.json"), 0); + setenv("EXECUTOR", _original_executor.c_str(), true); + setenv("PROFILING_MODE", _original_profiling_mode.c_str(), true); + } + + backend::BackendContexts buildBackendContexts(const Graph &graph) + { + backend::BackendContexts contexts; + for (auto backend : _mock_backends) + { + contexts.emplace(backend, backend->newContext(graph, nullptr, false)); + } + return contexts; + } + + const MockBackendCPU *_cpu_backend{nullptr}; + const MockBackendGPU *_gpu_backend{nullptr}; + const MockBackendNPU *_npu_backend{nullptr}; + std::vector _mock_backends; + + std::string _original_executor; + std::string _original_profiling_mode; +}; + +class SchedulerTestWithExecutorParam : public SchedulerTest, + public testing::WithParamInterface +{ +}; + +// +// HEScheduler tests +// + +// Test scheduler behavior for straight graph with known execution time of all nodes and permutes. +TEST_P(SchedulerTestWithExecutorParam, straight_graph_known_exec_time) +{ + setExecutor(GetParam()); + + // Prepare graph + auto graph(createStraightGraph()); + OperationIndex add_op_idx(0), sub_op_idx(1), mul_op_idx(2); + + // Set default execution and transfer time + setPermutationsExecutionTime(_mock_backends, OPERAND_SIZE, 1); + setOperationsExecutionTime(_mock_backends, {"Add", "Sub", "Mul"}, + {OPERATION_SIZE, OPERATION_SIZE, OPERATION_SIZE}, 1e4); + + // Test 1 + // Expected behaviour: scheduler assigns different backend to each node + { + // For each backend reduce execution time of one node + ExecTime et(_mock_backends); + setOperationExecTime(et, _cpu_backend, "Add", false, OPERATION_SIZE, 1); + setOperationExecTime(et, _gpu_backend, "Sub", false, OPERATION_SIZE, 1); + setOperationExecTime(et, _npu_backend, "Mul", false, OPERATION_SIZE, 1); + et.uploadOperationsExecTime(); + + // Test scheduler + auto backend_contexts = buildBackendContexts(*graph); + auto scheduler = compiler::HEScheduler(backend_contexts, + compiler::fetchCompilerOptionsFromGlobalConfig(*graph)); + const auto br = scheduler.schedule(*graph); + ASSERT_EQ(br->getBackend(add_op_idx)->config()->id(), "cpu"); + ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "gpu"); + ASSERT_EQ(br->getBackend(mul_op_idx)->config()->id(), "npu"); + } + + // Test 2 + // Expected behaviour: scheduler assigns single backend to all nodes because of big transfer time + { + // Increase transfer time + setPermutationsExecutionTime(_mock_backends, OPERAND_SIZE, 1e5); + + // Test scheduler + auto backend_contexts = buildBackendContexts(*graph); + auto scheduler = compiler::HEScheduler(backend_contexts, + compiler::fetchCompilerOptionsFromGlobalConfig(*graph)); + const auto br = scheduler.schedule(*graph); + ASSERT_EQ(br->getBackend(add_op_idx)->config()->id(), "cpu"); + ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "cpu"); + ASSERT_EQ(br->getBackend(mul_op_idx)->config()->id(), "cpu"); + } +} + +// Test scheduler behavior for branched graph with known execution time of all nodes and permutes +TEST_P(SchedulerTestWithExecutorParam, branched_graph_known_exec_time) +{ + const int64_t NPU_ET = 5000; + setExecutor(GetParam()); + + // Prepare graph + auto graph(createBranchedGraph()); + OperationIndex add_op_idx(0), mul1_op_idx(1), mul2_op_idx(2), fc1_op_idx(3), fc2_op_idx(4), + sub_op_idx(5); + + // Set default execution and transfer time + setPermutationsExecutionTime(_mock_backends, OPERAND_SIZE, 1000); + setOperationsExecutionTime(_mock_backends, {"Add", "Sub", "Mul", "FullyConnected"}, + {OPERATION_SIZE, OPERATION_SIZE, OPERATION_SIZE, OPERATION_SIZE}, 1e4); + + // Test 1 + // Expected behaviour: for dataflow and linear executors scheduler assigns fastest backend to all + // nodes, in case of parallel executor scheduler assigns different backends to branches. + { + // Reduce execution time + ExecTime et(_mock_backends); + setOperationExecTime(et, _npu_backend, "Add", false, OPERATION_SIZE, NPU_ET); + setOperationExecTime(et, _npu_backend, "Mul", false, OPERATION_SIZE, NPU_ET); + setOperationExecTime(et, _npu_backend, "Sub", false, OPERATION_SIZE, NPU_ET); + setOperationExecTime(et, _npu_backend, "FullyConnected", false, OPERATION_SIZE, NPU_ET); + setOperationExecTime(et, _gpu_backend, "Mul", false, OPERATION_SIZE, NPU_ET + 1000); + setOperationExecTime(et, _gpu_backend, "FullyConnected", false, OPERATION_SIZE, NPU_ET + 1000); + et.uploadOperationsExecTime(); + + // Test scheduler + auto backend_contexts = buildBackendContexts(*graph); + auto scheduler = compiler::HEScheduler(backend_contexts, + compiler::fetchCompilerOptionsFromGlobalConfig(*graph)); + const auto br = scheduler.schedule(*graph); + + std::string branch1_expected_backend("npu"), branch2_expected_backend("npu"); + if (GetParam() == PARALLEL) + { + branch1_expected_backend = + br->getBackend(mul1_op_idx)->config()->id() == "npu" ? "npu" : "gpu"; + branch2_expected_backend = branch1_expected_backend == "npu" ? "gpu" : "npu"; + } + + ASSERT_EQ(br->getBackend(add_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(mul1_op_idx)->config()->id(), branch1_expected_backend); + ASSERT_EQ(br->getBackend(mul2_op_idx)->config()->id(), branch1_expected_backend); + ASSERT_EQ(br->getBackend(fc1_op_idx)->config()->id(), branch2_expected_backend); + ASSERT_EQ(br->getBackend(fc2_op_idx)->config()->id(), branch2_expected_backend); + ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "npu"); + } + + // Test 2 + // Expected behaviour: scheduler assigns single backend to all nodes + { + // Increase execution time for GPU backend + ExecTime et(_mock_backends); + /* for parallel executor: set a time, that is larger than sum_of_other_branches_nodes_cnt * + * npu_exec_time so that npu is prefered: the ith branch will wait for npu until it finishes the + * [0;i-1] branches nodes in DFS order. In each branch it goes deep intul doesn't encounter + * branching or scheduler assigns another backend to a node*/ + setOperationExecTime(et, _gpu_backend, "Mul", false, OPERATION_SIZE, NPU_ET * 3 + 1); + setOperationExecTime(et, _gpu_backend, "FullyConnected", false, OPERATION_SIZE, NPU_ET * 3 + 1); + et.uploadOperationsExecTime(); + + // Test scheduler + auto backend_contexts = buildBackendContexts(*graph); + auto scheduler = compiler::HEScheduler(backend_contexts, + compiler::fetchCompilerOptionsFromGlobalConfig(*graph)); + const auto br = scheduler.schedule(*graph); + ASSERT_EQ(br->getBackend(add_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(mul1_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(mul2_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(fc1_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(fc2_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "npu"); + } +} + +// SchedulerTestWithExecutorParam tests are parameterized with executor name and runs three times - +// one time for each executor +INSTANTIATE_TEST_CASE_P(AllExecutors, SchedulerTestWithExecutorParam, + testing::Values(LINEAR, DATAFLOW, PARALLEL)); + +// Test scheduler behavior for branched graph and enabled profiling mode +TEST_F(SchedulerTest, branched_graph_profiling_mode) +{ + const int ET = 1e5; + + // Turn on profiling mode + setProfilingMode(true); + setExecutor(DATAFLOW); + + // Prepare graph + auto graph(createBranchedGraph()); + OperationIndex add_op_idx(0), mul1_op_idx(1), mul2_op_idx(2), fc1_op_idx(3), fc2_op_idx(4), + sub_op_idx(5); + + // Test 1 + // Expected behaviour: scheduler assigns backends to nodes with unknown execution time + { + // Set execution time for all backends/nodes except for cpu/Sub, npu/Mul, gpu/FC + ExecTime et(_mock_backends); + setOperationExecTime(et, _cpu_backend, "Add", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _cpu_backend, "Mul", false, OPERATION_SIZE, ET + 1); + setOperationExecTime(et, _cpu_backend, "FullyConnected", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _npu_backend, "Add", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _npu_backend, "FullyConnected", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _npu_backend, "Sub", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _gpu_backend, "Add", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _gpu_backend, "Mul", false, OPERATION_SIZE, ET + 1); + setOperationExecTime(et, _gpu_backend, "Sub", false, OPERATION_SIZE, ET); + et.uploadOperationsExecTime(); + + // Test scheduler + auto backend_contexts = buildBackendContexts(*graph); + auto scheduler = compiler::HEScheduler(backend_contexts, + compiler::fetchCompilerOptionsFromGlobalConfig(*graph)); + const auto br = scheduler.schedule(*graph); + ASSERT_EQ(br->getBackend(mul1_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(mul2_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(fc1_op_idx)->config()->id(), "gpu"); + ASSERT_EQ(br->getBackend(fc2_op_idx)->config()->id(), "gpu"); + ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "cpu"); + } + + // Test 2 + // Expected behaviour: scheduler shuffling backends, so different backends are assigned to + // neighbor nodes + { + // Set execution time for rest backends/nodes (cpu/Sub, npu/Mul, gpu/FC) + ExecTime et(_mock_backends); + setOperationExecTime(et, _cpu_backend, "Sub", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _npu_backend, "Mul", false, OPERATION_SIZE, ET + 1); + setOperationExecTime(et, _gpu_backend, "FullyConnected", false, OPERATION_SIZE, ET); + et.uploadOperationsExecTime(); + + // Test scheduler + auto backend_contexts = buildBackendContexts(*graph); + auto scheduler = compiler::HEScheduler(backend_contexts, + compiler::fetchCompilerOptionsFromGlobalConfig(*graph)); + const auto br = scheduler.schedule(*graph); + ASSERT_NE(br->getBackend(add_op_idx)->config()->id(), + br->getBackend(mul1_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(add_op_idx)->config()->id(), + br->getBackend(fc1_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(mul1_op_idx)->config()->id(), + br->getBackend(mul2_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(fc1_op_idx)->config()->id(), + br->getBackend(fc2_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(mul2_op_idx)->config()->id(), + br->getBackend(sub_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(fc2_op_idx)->config()->id(), + br->getBackend(sub_op_idx)->config()->id()); + } +} + +// TODO: Add tests with unknown execution and permutation time + +} // unnamed namespace diff --git a/runtime/onert/test/core/exec/ExecInstance.cc b/runtime/onert/test/core/exec/ExecInstance.cc new file mode 100644 index 000000000..7242486a0 --- /dev/null +++ b/runtime/onert/test/core/exec/ExecInstance.cc @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "ir/Graph.h" +#include "compiler/Compiler.h" +#include "exec/Execution.h" +#include "ir/operation/Add.h" + +namespace +{ + +using namespace onert::ir; + +class CompiledMockUpModel +{ +public: + CompiledMockUpModel() + { + // Model: two elementwise add operation + // model input: lhs, rhs1 + // model output: second add result (result2) + // constant: rhs2 + // result1 <= (lhs + rhs) + // result2 <= (result1 + rhs2) + // lhs, rhs1, rh2, result1, result2 shape: {1, 2, 2, 1} + // activation: none (constant) + graph = std::make_shared(); + // 1st add operands (result1 <= lhs + rhs1) + Shape shape{1, 2, 2, 1}; + TypeInfo type{DataType::FLOAT32}; + static float rhs2_data[4] = {3, 1, -1, 5}; + auto operand_lhs = graph->addOperand(shape, type); + auto operand_rhs1 = graph->addOperand(shape, type); + auto operand_result1 = graph->addOperand(shape, type); + auto operand_rhs2 = graph->addOperand(shape, type); + auto operand_result2 = graph->addOperand(shape, type); + graph->operands() + .at(operand_rhs2) + .data(std::make_unique(reinterpret_cast(&rhs2_data), 16)); + // 2nd add operations (result2 <= result1 + rhs2) + operation::Add::Param param1; + param1.activation = Activation::NONE; + auto input_set1 = OperandIndexSequence{operand_lhs, operand_rhs1}; + auto output_set1 = OperandIndexSequence{operand_result1}; + graph->addOperation(std::make_unique(input_set1, output_set1, param1)); + operation::Add::Param param2; + param2.activation = Activation::NONE; + auto input_set2 = OperandIndexSequence{operand_result1, operand_rhs2}; + auto output_set2 = OperandIndexSequence{operand_result2}; + graph->addOperation(std::make_unique(input_set2, output_set2, param2)); + // Identify model inputs and outputs + graph->addInput(operand_lhs); + graph->addInput(operand_rhs1); + graph->addOutput(operand_result2); + graph->finishBuilding(); + + // Compile + auto compiler = new onert::compiler::Compiler{graph}; + compiler->compile(); + compiler->release(executor); + delete compiler; + } + +public: + std::shared_ptr graph; + std::shared_ptr executor; +}; + +TEST(ExecInstance, simple) +{ + auto mockup = CompiledMockUpModel(); + auto graph = mockup.graph; + auto executor = mockup.executor; + + auto input1 = IOIndex{0}; + auto input2 = IOIndex{1}; + auto output = IOIndex{0}; + + const float input1_buffer[4] = {1, 0, -1, -2}; + const float input2_buffer[4] = {1, -3, 2, -4}; + float output_buffer[4] = {}; + const float output_expected[4] = {5, -2, 0, -1}; + + auto execution = new onert::exec::Execution(executor); + + execution->setInput(input1, reinterpret_cast(input1_buffer), 16); + execution->setInput(input2, reinterpret_cast(input2_buffer), 16); + execution->setOutput(output, reinterpret_cast(output_buffer), 16); + execution->execute(); + + for (auto i = 0; i < 4; i++) + { + EXPECT_EQ(output_buffer[i], output_expected[i]); + } + + delete execution; +} + +TEST(ExecInstance, twoCompile) +{ + auto mockup = CompiledMockUpModel(); + auto graph = mockup.graph; + auto executor1 = mockup.executor; + auto execution1 = new onert::exec::Execution(executor1); + + auto input1 = IOIndex{0}; + auto input2 = IOIndex{1}; + auto output = IOIndex{0}; + + const float exe1_input1_buffer[4] = {1, 0, -1, -2}; + const float exe1_input2_buffer[4] = {1, -3, 2, -4}; + float exe1_output_buffer[4] = {}; + const float exe1_output_expected[4] = {5, -2, 0, -1}; + + execution1->setInput(input1, reinterpret_cast(exe1_input1_buffer), 16); + execution1->setInput(input2, reinterpret_cast(exe1_input2_buffer), 16); + execution1->setOutput(output, reinterpret_cast(exe1_output_buffer), 16); + + // Make new executor: compile again + auto compiler = new onert::compiler::Compiler{graph}; + compiler->compile(); + std::shared_ptr executor2; + compiler->release(executor2); + auto execution2 = new onert::exec::Execution(executor2); + + const float exe2_input1_buffer[4] = {2, 1, -2, 0}; + const float exe2_input2_buffer[4] = {-3, 3, 1, 2}; + float exe2_output_buffer[4] = {}; + const float exe2_output_expected[4] = {2, 5, -2, 7}; + + execution2->setInput(input1, reinterpret_cast(exe2_input1_buffer), 16); + execution2->setInput(input2, reinterpret_cast(exe2_input2_buffer), 16); + execution2->setOutput(output, reinterpret_cast(exe2_output_buffer), 16); + + execution1->execute(); + execution2->execute(); + + for (auto i = 0; i < 4; i++) + { + EXPECT_EQ(exe1_output_buffer[i], exe1_output_expected[i]); + EXPECT_EQ(exe2_output_buffer[i], exe2_output_expected[i]); + } + + delete compiler; + delete execution1; + delete execution2; +} + +// Support two initialized execution instance then ordered execution +TEST(ExecInstance, twoExecution) +{ + auto mockup = CompiledMockUpModel(); + auto executor = mockup.executor; + auto input1 = IOIndex{0}; + auto input2 = IOIndex{1}; + auto output1 = IOIndex{0}; + + const float exe1_input1_buffer[4] = {1, 0, -1, -2}; + const float exe1_input2_buffer[4] = {1, -3, 2, -4}; + float exe1_output_buffer[4] = {}; + const float exe1_output_expected[4] = {5, -2, 0, -1}; + const float exe2_output_expected[4] = {2, 5, -2, 7}; + + auto execution1 = new onert::exec::Execution(executor); + execution1->setInput(input1, reinterpret_cast(exe1_input1_buffer), 16); + execution1->setInput(input2, reinterpret_cast(exe1_input2_buffer), 16); + execution1->setOutput(output1, reinterpret_cast(exe1_output_buffer), 16); + + const float exe2_input1_buffer[4] = {2, 1, -2, 0}; + const float exe2_input2_buffer[4] = {-3, 3, 1, 2}; + float exe2_output_buffer[4] = {}; + + // Make new execution + auto execution2 = new onert::exec::Execution(executor); + execution2->setInput(input1, reinterpret_cast(exe2_input1_buffer), 16); + execution2->setInput(input2, reinterpret_cast(exe2_input2_buffer), 16); + execution2->setOutput(output1, reinterpret_cast(exe2_output_buffer), 16); + + execution1->execute(); + execution2->execute(); + + for (auto i = 0; i < 4; i++) + { + EXPECT_EQ(exe1_output_buffer[i], exe1_output_expected[i]); + EXPECT_EQ(exe2_output_buffer[i], exe2_output_expected[i]); + } + + delete execution1; + delete execution2; +} + +class Inference +{ +public: + Inference(const float (&input1)[4], const float (&input2)[4], float (&output)[4], + std::shared_ptr &executor) + : _input1{input1}, _input2{input2}, _output{output}, _executor{executor} + { + // DO NOTHING + } + + void inference(void) + { + auto input1 = IOIndex{0}; + auto input2 = IOIndex{1}; + auto output1 = IOIndex{0}; + + auto execution = new onert::exec::Execution(_executor); + execution->setInput(input1, reinterpret_cast(_input1), 16); + execution->setInput(input2, reinterpret_cast(_input2), 16); + execution->setOutput(output1, reinterpret_cast(_output), 16); + + execution->execute(); + + delete execution; + } + +private: + const float (&_input1)[4]; + const float (&_input2)[4]; + float (&_output)[4]; + std::shared_ptr &_executor; +}; + +// Support multi-thread execution +TEST(ExecInstance, twoThreads) +{ + auto mockup = CompiledMockUpModel(); + auto executor = mockup.executor; + + const float exe1_input1_buffer[4] = {1, 0, -1, -2}; + const float exe1_input2_buffer[4] = {1, -3, 2, -4}; + float exe1_output_buffer[4] = {}; + const float exe1_output_expected[4] = {5, -2, 0, -1}; + + Inference execution1{exe1_input1_buffer, exe1_input2_buffer, exe1_output_buffer, executor}; + + const float exe2_input1_buffer[4] = {2, 1, -2, 0}; + const float exe2_input2_buffer[4] = {-3, 3, 1, 2}; + float exe2_output_buffer[4] = {}; + const float exe2_output_expected[4] = {2, 5, -2, 7}; + + Inference execution2{exe2_input1_buffer, exe2_input2_buffer, exe2_output_buffer, executor}; + + std::thread t1{&Inference::inference, &execution1}; + std::thread t2{&Inference::inference, &execution2}; + + t1.join(); + t2.join(); + + for (auto i = 0; i < 4; i++) + { + EXPECT_EQ(exe1_output_buffer[i], exe1_output_expected[i]); + EXPECT_EQ(exe2_output_buffer[i], exe2_output_expected[i]); + } +} + +// Support asynchronous execution +TEST(ExecInstance, async) +{ + auto mockup = CompiledMockUpModel(); + auto graph = mockup.graph; + auto executor = mockup.executor; + + auto input1 = IOIndex{0}; + auto input2 = IOIndex{1}; + auto output = IOIndex{0}; + + const float input1_buffer[4] = {1, 0, -1, -2}; + const float input2_buffer[4] = {1, -3, 2, -4}; + float output_buffer[4] = {}; + const float output_expected[4] = {5, -2, 0, -1}; + + auto execution = new onert::exec::Execution(executor); + + execution->setInput(input1, reinterpret_cast(input1_buffer), 16); + execution->setInput(input2, reinterpret_cast(input2_buffer), 16); + execution->setOutput(output, reinterpret_cast(output_buffer), 16); + execution->startExecute(); + execution->waitFinish(); + + for (auto i = 0; i < 4; i++) + { + EXPECT_EQ(output_buffer[i], output_expected[i]); + } + + delete execution; +} + +} // namespace diff --git a/runtime/onert/test/core/exec/ExecTime.test.cc b/runtime/onert/test/core/exec/ExecTime.test.cc new file mode 100644 index 000000000..ab8b79935 --- /dev/null +++ b/runtime/onert/test/core/exec/ExecTime.test.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "exec/ExecTime.h" +#include "backend/IConfig.h" +#include "backend/Backend.h" +#include +#include + +namespace +{ +using namespace onert; +using namespace exec; +using namespace backend; + +struct MockConfig : public IConfig +{ + std::string id() override { return "b1"; } + bool initialize() override { return true; }; + bool SupportPermutation() override { return false; } +}; + +struct MockBackend : public ::onert::backend::Backend +{ + std::shared_ptr config() const override + { + return std::make_shared(); + } + std::unique_ptr newContext(const ir::Graph &, + const std::shared_ptr &kb, + bool) const override + { + return nullptr; + } +}; + +TEST(ExecTime, roundtrip_ok) +{ + const auto *b = new MockBackend(); + std::vector bs = {b}; + { + ExecTime et(bs); + et.updateOperationExecTime(b, "op1", true, 100, 100); + et.updateOperationExecTime(b, "op1", true, 200, 200); + et.updateOperationExecTime(b, "op1", false, 100, 888); + et.uploadOperationsExecTime(); + } + { + ExecTime et(bs); + auto time = et.getOperationExecTime(b, "op1", true, 100); + ASSERT_EQ(time, 100); + // Check interpolation + time = et.getOperationExecTime(b, "op1", true, 150); + ASSERT_EQ(time, 150); + time = et.getOperationExecTime(b, "op1", false, 100); + ASSERT_EQ(time, 888); + et.uploadOperationsExecTime(); + } + // clean up + EXPECT_EQ(remove("exec_time.json"), 0); +} + +TEST(ExecTime, structure) +{ + + const auto *b = new MockBackend(); + std::vector bs = {b}; + { + ExecTime et(bs); + et.updateOperationExecTime(b, "op1", true, 100, 100); + et.updateOperationExecTime(b, "op1", true, 200, 200); + et.uploadOperationsExecTime(); + } + { + ExecTime et(bs); + auto time = et.getOperationExecTime(b, "op1", true, 100); + ASSERT_EQ(time, 100); + // Check interpolation + time = et.getOperationExecTime(b, "op1", true, 200); + ASSERT_EQ(time, 200); + et.uploadOperationsExecTime(); + } + // clean up + EXPECT_EQ(remove("exec_time.json"), 0); +} +} // unnamed namespace diff --git a/runtime/onert/test/core/interp/ExecManager.cc b/runtime/onert/test/core/interp/ExecManager.cc new file mode 100644 index 000000000..2b56357c2 --- /dev/null +++ b/runtime/onert/test/core/interp/ExecManager.cc @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include "ir/Graph.h" +#include "interp/InterpExecutor.h" +#include "exec/Execution.h" +#include "ir/operation/Add.h" + +namespace +{ + +using namespace onert::ir; +using InterpExecutor = onert::interp::InterpExecutor; +using Execution = onert::exec::Execution; + +class InterpExecutorTest : public ::testing::Test +{ +protected: + virtual void SetUp() {} + void CreateSimpleModel() + { + // Model: one elementwise add operation + // model input: lhs, rhs + // model output: add result + // lhs, rhs, result shape: {1, 2, 2, 1} + // activation: none (constant) + _graph = std::make_unique(); + + // Add operands + + Shape shape{1, 2, 2, 1}; + TypeInfo type{DataType::INT32}; + Shape shape_scalar(0); + TypeInfo type_scalar{DataType::INT32}; + + auto operand_lhs = _graph->addOperand(shape, type); + auto operand_rhs = _graph->addOperand(shape, type); + auto operand_result = _graph->addOperand(shape, type); + + // Add operations + + operation::Add::Param param; + param.activation = Activation::NONE; + auto input_set = OperandIndexSequence{operand_lhs, operand_rhs}; + auto output_set = OperandIndexSequence{operand_result}; + _graph->addOperation(std::make_unique(input_set, output_set, param)); + + // Identify model inputs and outputs + + _graph->getInputs().append(operand_lhs); + _graph->getInputs().append(operand_rhs); + _graph->getOutputs().append(operand_result); + + _graph->finishBuilding(); + + _executor = std::make_unique(*_graph); + } + + void CreateTwoStepModel() + { + // Model: two elementwise add operation + // model input: lhs, rhs1 + // model output: second add result (result2) + // constant: rhs2 + // result1 <= (lhs + rhs) + // result2 <= (result1 + rhs2) + // lhs, rhs1, rh2, result1, result2 shape: {1, 2, 2, 1} + // activation: none (constant) + _graph = std::make_unique(); + + // 1st add operands (result1 <= lhs + rhs1) + + Shape shape{1, 2, 2, 1}; + TypeInfo type{DataType::INT32}; + Shape shape_scalar(0); + TypeInfo type_scalar{DataType::INT32}; + + static int32_t rhs2_data[4] = {3, 1, -1, 5}; + + auto operand_lhs = _graph->addOperand(shape, type); + auto operand_rhs1 = _graph->addOperand(shape, type); + auto operand_result1 = _graph->addOperand(shape, type); + auto operand_rhs2 = _graph->addOperand(shape, type); + auto operand_result2 = _graph->addOperand(shape, type); + _graph->operands() + .at(operand_rhs2) + .data(std::make_unique(reinterpret_cast(&rhs2_data), 16)); + + // 2nd add operations (result2 <= result1 + rhs2) + + operation::Add::Param param1; + param1.activation = Activation::NONE; + auto input_set1 = OperandIndexSequence{operand_lhs, operand_rhs1}; + auto output_set1 = OperandIndexSequence{operand_result1}; + _graph->addOperation(std::make_unique(input_set1, output_set1, param1)); + + operation::Add::Param param2; + param2.activation = Activation::NONE; + auto input_set2 = OperandIndexSequence{operand_result1, operand_rhs2}; + auto output_set2 = OperandIndexSequence{operand_result2}; + _graph->addOperation(std::make_unique(input_set2, output_set2, param2)); + + // Identify model inputs and outputs + + _graph->getInputs().append(operand_lhs); + _graph->getInputs().append(operand_rhs1); + _graph->getOutputs().append(operand_result2); + + _graph->finishBuilding(); + + _executor = std::make_unique(*_graph); + } + + void CreateUnspecifiedDimensionsModel() + { + // Model: one elementwise add operation + // model input: lhs, rhs + // model output: add result + // lhs, rhs, result shape: {1, unknown, 2, 1} + // activation: none (constant) + _graph = std::make_unique(); + + // Add operands + + Shape shape{1, 0, 2, 1}; + TypeInfo type{DataType::INT32}; + Shape shape_scalar(0); + TypeInfo type_scalar{DataType::INT32}; + + auto operand_lhs = _graph->addOperand(shape, type); + auto operand_rhs = _graph->addOperand(shape, type); + + auto operand_activation = _graph->addOperand(shape_scalar, type_scalar); + _graph->operands() + .at(operand_activation) + .data( + std::make_unique(reinterpret_cast(&_activation_value), 4)); + + auto operand_result = _graph->addOperand(shape, type); + + // Add operations + + operation::Add::Param param; + param.activation = Activation::NONE; + auto input_set = OperandIndexSequence{operand_lhs, operand_rhs}; + auto output_set = OperandIndexSequence{operand_result}; + _graph->addOperation(std::make_unique(input_set, output_set, param)); + + // Identify model inputs and outputs + + _graph->getInputs().append(operand_lhs); + _graph->getInputs().append(operand_rhs); + _graph->getOutputs().append(operand_result); + + _graph->finishBuilding(); + + _executor = std::make_unique(*_graph); + } + + void createExecution() { _execution = std::make_unique(_executor); } + + virtual void TearDown() { _executor = nullptr; } + + std::unique_ptr _graph{nullptr}; + std::shared_ptr _executor{nullptr}; + std::unique_ptr _execution{nullptr}; + const int32_t _activation_value{0}; +}; + +TEST_F(InterpExecutorTest, create_empty) +{ + Graph graph; + graph.finishBuilding(); + _executor = std::make_unique(graph); + ASSERT_NE(_executor, nullptr); +} + +TEST_F(InterpExecutorTest, create_simple) +{ + CreateSimpleModel(); + ASSERT_NE(_executor, nullptr); +} + +TEST_F(InterpExecutorTest, setInput) +{ + CreateSimpleModel(); + createExecution(); + + auto input1 = IOIndex{0}; + const int32_t input1_buffer[4] = {1, 0, -1, -2}; + + EXPECT_THROW(_execution->setInput(input1, reinterpret_cast(input1_buffer), 4), + std::runtime_error); + EXPECT_THROW(_execution->setInput(input1, reinterpret_cast(input1_buffer), 12), + std::runtime_error); + EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast(input1_buffer), 16)); +} + +TEST_F(InterpExecutorTest, setOutput) +{ + CreateSimpleModel(); + createExecution(); + + auto output = IOIndex{0}; + auto output_idx = _graph->getOutputs().at(output); + + int32_t output_buffer[4] = {}; + + EXPECT_THROW(_execution->setOutput(output, reinterpret_cast(output_buffer), 4), + std::runtime_error); + EXPECT_THROW(_execution->setOutput(output, reinterpret_cast(output_buffer), 12), + std::runtime_error); + EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast(output_buffer), 16)); +} + +TEST_F(InterpExecutorTest, setInputForUnspecifiedDimensions) +{ + CreateUnspecifiedDimensionsModel(); + createExecution(); + + auto input1 = IOIndex{0}; + const int32_t input1_buffer[4] = {1, 0, -1, -2}; + + TypeInfo operand_type{DataType::INT32}; + Shape operand_shape{1, 2, 2, 1}; + + EXPECT_THROW(_execution->setInput(input1, operand_type, operand_shape, + reinterpret_cast(input1_buffer), 4), + std::runtime_error); + EXPECT_THROW(_execution->setInput(input1, operand_type, operand_shape, + reinterpret_cast(input1_buffer), 12), + std::runtime_error); + EXPECT_NO_THROW(_execution->setInput(input1, operand_type, operand_shape, + reinterpret_cast(input1_buffer), 16)); +} + +TEST_F(InterpExecutorTest, setOutputForUnspecifiedDimensions) +{ + CreateUnspecifiedDimensionsModel(); + createExecution(); + + auto output = IOIndex{0}; + auto output_idx = _graph->getOutputs().at(output); + + TypeInfo operand_type{DataType::INT32}; + Shape operand_shape{1, 2, 2, 1}; + + int32_t output_buffer[4] = {}; + + EXPECT_THROW(_execution->setOutput(output, operand_type, operand_shape, + reinterpret_cast(output_buffer), 4), + std::runtime_error); + EXPECT_THROW(_execution->setOutput(output, operand_type, operand_shape, + reinterpret_cast(output_buffer), 12), + std::runtime_error); + EXPECT_NO_THROW(_execution->setOutput(output, operand_type, operand_shape, + reinterpret_cast(output_buffer), 16)); +} + +TEST_F(InterpExecutorTest, execute) +{ + CreateSimpleModel(); + createExecution(); + + auto input1 = IOIndex{0}; + auto input2 = IOIndex{1}; + auto input1_idx = _graph->getInputs().at(input1); + auto input2_idx = _graph->getInputs().at(input2); + + const int32_t input1_buffer[4] = {1, 0, -1, -2}; + const int32_t input2_buffer[4] = {1, -3, 2, -4}; + + auto output = IOIndex{0}; + auto output_idx = _graph->getOutputs().at(output); + + int32_t output_buffer[4] = {}; + + EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast(input1_buffer), 16)); + EXPECT_NO_THROW(_execution->setInput(input2, reinterpret_cast(input2_buffer), 16)); + EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast(output_buffer), 16)); + EXPECT_NO_THROW(_execution->execute()); + EXPECT_EQ(output_buffer[0], 2); + EXPECT_EQ(output_buffer[1], -3); + EXPECT_EQ(output_buffer[2], 1); + EXPECT_EQ(output_buffer[3], -6); +} + +TEST_F(InterpExecutorTest, executeTwoStep) +{ + CreateTwoStepModel(); + createExecution(); + + auto input1 = IOIndex{0}; + auto input2 = IOIndex{1}; + auto input1_idx = _graph->getInputs().at(input1); + auto input2_idx = _graph->getInputs().at(input2); + + const int32_t input1_buffer[4] = {1, 0, -1, -2}; + const int32_t input2_buffer[4] = {1, -3, 2, -4}; + + auto output = IOIndex{0}; + auto output_idx = _graph->getOutputs().at(output); + + int32_t output_buffer[4] = {}; + + EXPECT_NO_THROW(_execution->setInput(input1, reinterpret_cast(input1_buffer), 16)); + EXPECT_NO_THROW(_execution->setInput(input2, reinterpret_cast(input2_buffer), 16)); + EXPECT_NO_THROW(_execution->setOutput(output, reinterpret_cast(output_buffer), 16)); + EXPECT_NO_THROW(_execution->execute()); + EXPECT_EQ(output_buffer[0], 5); + EXPECT_EQ(output_buffer[1], -2); + EXPECT_EQ(output_buffer[2], 0); + EXPECT_EQ(output_buffer[3], -1); +} + +} // namespace diff --git a/runtime/onert/test/graph/Graph.cc b/runtime/onert/test/graph/Graph.cc new file mode 100644 index 000000000..34e9fe002 --- /dev/null +++ b/runtime/onert/test/graph/Graph.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ir/Graph.h" + +TEST(Graph, inputs_and_outputs) +{ + onert::ir::Graph graph; + + onert::ir::OperandIndex index0{0u}; + onert::ir::OperandIndex index1{1u}; + + graph.addInput({index0}); + graph.addInput({index1}); + + onert::ir::OperandIndex index10{10u}; + onert::ir::OperandIndex index11{11u}; + onert::ir::OperandIndex index12{12u}; + + graph.addOutput({index10}); + graph.addOutput({index11}); + graph.addOutput({index12}); + + ASSERT_EQ(graph.getInputs().size(), 2); + ASSERT_EQ(graph.getOutputs().size(), 3); + + onert::ir::IOIndex io_index0{0}; + onert::ir::IOIndex io_index1{1}; + onert::ir::IOIndex io_index2{2}; + + ASSERT_EQ(graph.getInputs().at(io_index0), 0); + ASSERT_EQ(graph.getInputs().at(io_index1), 1); + + ASSERT_EQ(graph.getOutputs().at(io_index0), 10); + ASSERT_EQ(graph.getOutputs().at(io_index1), 11); + ASSERT_EQ(graph.getOutputs().at(io_index2), 12); +} diff --git a/runtime/onert/test/graph/Index.cc b/runtime/onert/test/graph/Index.cc new file mode 100644 index 000000000..358e64c82 --- /dev/null +++ b/runtime/onert/test/graph/Index.cc @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "util/Index.h" + +using Index = ::onert::util::Index; + +TEST(Index, index_test) +{ + Index idx1{1u}; + Index idx2{2u}; + Index idx3{idx1}; + + ASSERT_EQ(idx1, 1); + ASSERT_EQ(idx1, 1u); + ASSERT_EQ(idx1.value(), 1u); + ASSERT_NE(idx1, idx2); + ASSERT_EQ(idx1, idx3); +} diff --git a/runtime/onert/test/graph/MockNode.h b/runtime/onert/test/graph/MockNode.h new file mode 100644 index 000000000..60b4719ed --- /dev/null +++ b/runtime/onert/test/graph/MockNode.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ONERT_TEST_GRAPH_MOCK_NODE_H__ +#define __ONERT_TEST_GRAPH_MOCK_NODE_H__ + +#include "ir/Operation.h" +#include "ir/OperandIndexSequence.h" + +namespace onert_test +{ +namespace ir +{ + +class SimpleMock : public onert::ir::Operation +{ +public: + SimpleMock(const onert::ir::OperandIndexSequence &inputs, + const onert::ir::OperandIndexSequence &outputs) + : Operation{onert::ir::OperandConstraint::createAny()} + { + setInputs(inputs); + setOutputs(outputs); + } + +public: + void accept(onert::ir::OperationVisitor &) const override {} + onert::ir::OpCode opcode() const final { return onert::ir::OpCode::Invalid; } +}; + +} // namespace ir +} // namespace onert_test + +#endif // __ONERT_TEST_GRAPH_MOCK_NODE_H__ diff --git a/runtime/onert/test/graph/operand/IndexSet.cc b/runtime/onert/test/graph/operand/IndexSet.cc new file mode 100644 index 000000000..6215e0d24 --- /dev/null +++ b/runtime/onert/test/graph/operand/IndexSet.cc @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ir/OperandIndexSequence.h" + +using onert::ir::OperandIndex; +using onert::ir::OperandIndexSequence; + +TEST(graph_OperandIndexSequence, append) +{ + OperandIndexSequence iset{0, 2, 4, 8}; + + ASSERT_EQ(iset.size(), 4); + + iset.append(OperandIndex{10}); + + ASSERT_EQ(iset.size(), 5); + + onert::ir::IOIndex index1{1}; + onert::ir::IOIndex index2{4}; + + ASSERT_EQ(iset.at(index1), 2); + ASSERT_EQ(iset.at(index2), 10); + + ASSERT_TRUE(iset.contains(OperandIndex{2})); + ASSERT_TRUE(iset.contains(OperandIndex{10})); + ASSERT_FALSE(iset.contains(OperandIndex{11})); +} + +TEST(graph_OperandIndexSequence, replace) +{ + OperandIndexSequence iset{0, 1, 2, 3}; + + iset.replace(OperandIndex{1}, OperandIndex{9}); + ASSERT_FALSE(iset.contains(OperandIndex{1})); + ASSERT_TRUE(iset.contains(OperandIndex{9})); +} diff --git a/runtime/onert/test/graph/operand/LayoutSet.cc b/runtime/onert/test/graph/operand/LayoutSet.cc new file mode 100644 index 000000000..e35bddd8b --- /dev/null +++ b/runtime/onert/test/graph/operand/LayoutSet.cc @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ir/LayoutSet.h" + +using onert::ir::Layout; +using onert::ir::LayoutSet; + +TEST(graph_operand_LayoutSet, layout_set_operators) +{ + LayoutSet set1{Layout::NCHW}; + LayoutSet set2{Layout::NHWC}; + LayoutSet set3 = set1 | set2; + + ASSERT_EQ(set3.size(), 2); + + ASSERT_EQ((set3 - set1).size(), 1); + ASSERT_EQ((set3 - set1).contains(Layout::NHWC), true); + ASSERT_EQ((set3 - set2).size(), 1); + ASSERT_EQ((set3 - set2).contains(Layout::NCHW), true); + ASSERT_EQ((set3 - set3).size(), 0); + + ASSERT_EQ((set3 & set1).size(), 1); + ASSERT_EQ((set3 & set1).contains(Layout::NCHW), true); + ASSERT_EQ((set3 & set2).size(), 1); + ASSERT_EQ((set3 & set2).contains(Layout::NHWC), true); + ASSERT_EQ((set1 & set2).size(), 0); +} diff --git a/runtime/onert/test/graph/operand/Set.cc b/runtime/onert/test/graph/operand/Set.cc new file mode 100644 index 000000000..0d35b5581 --- /dev/null +++ b/runtime/onert/test/graph/operand/Set.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ir/Operands.h" + +TEST(graph_operand_Set, set_test) +{ + onert::ir::Operands set; + + onert::ir::Shape shape0{1, 2, 3}; + + onert::ir::Shape shape1(4); + shape1.dim(0) = 10; + shape1.dim(1) = 20; + shape1.dim(2) = 30; + shape1.dim(3) = 40; + + onert::ir::TypeInfo type{onert::ir::DataType::INT32}; + + set.emplace(shape0, type); + set.emplace(shape1, type); + + ASSERT_EQ(set.exist(onert::ir::OperandIndex{0u}), true); + ASSERT_EQ(set.exist(onert::ir::OperandIndex{1u}), true); + ASSERT_EQ(set.exist(onert::ir::OperandIndex{2u}), false); + + ASSERT_EQ(set.at(onert::ir::OperandIndex{0u}).shape().dim(0), 1); + ASSERT_EQ(set.at(onert::ir::OperandIndex{0u}).shape().dim(1), 2); + ASSERT_EQ(set.at(onert::ir::OperandIndex{0u}).shape().dim(2), 3); +} diff --git a/runtime/onert/test/graph/operand/UseDef.cc b/runtime/onert/test/graph/operand/UseDef.cc new file mode 100644 index 000000000..3e8b14b8b --- /dev/null +++ b/runtime/onert/test/graph/operand/UseDef.cc @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ir/Graph.h" +#include "ir/verifier/Verifier.h" +#include +#include "../MockNode.h" + +#include + +namespace +{ + +using IndexSet = onert::ir::OperandIndexSequence; +using Mock = onert_test::ir::SimpleMock; + +} // namespace + +TEST(graph_operand_usedef, usedef_test) +{ + onert::ir::Graph graph; + onert::ir::verifier::DAGChecker verifier; + + onert::ir::Shape shape(3); + onert::ir::TypeInfo type{onert::ir::DataType::INT32}; + + // Model Input/Output + auto input_operand = graph.addOperand(shape, type); + auto output_operand = graph.addOperand(shape, type); + + graph.addInput(input_operand); + graph.addOutput(output_operand); + + // MockNode1 + auto operand_index1 = graph.addOperand(shape, type); + auto mocknode_index1 = + graph.addOperation(std::make_unique(IndexSet{input_operand}, IndexSet{operand_index1})); + + // MockNode2 + auto operand_index2 = graph.addOperand(shape, type); + auto mocknode_index2 = + graph.addOperation(std::make_unique(IndexSet{input_operand}, IndexSet{operand_index2})); + + // MockNode3(two input) + auto multiinput_index = graph.addOperation( + std::make_unique(IndexSet{operand_index1, operand_index2}, IndexSet{output_operand})); + + graph.finishBuilding(); + + ASSERT_EQ(verifier.verify(graph), true); + + // Check def + ASSERT_EQ(graph.operands().at(operand_index1).getDef().contains(mocknode_index1), true); + ASSERT_EQ(graph.operands().at(operand_index2).getDef().contains(mocknode_index2), true); + ASSERT_EQ(graph.operands().at(output_operand).getDef().contains(multiinput_index), true); + + ASSERT_EQ(graph.operands().at(operand_index1).getDef().contains(mocknode_index2), false); + ASSERT_EQ(graph.operands().at(operand_index1).getDef().contains(multiinput_index), false); + + // Check use + ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(mocknode_index1), true); + ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(mocknode_index2), true); + ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(multiinput_index), false); + ASSERT_EQ(graph.operands().at(operand_index1).getUses().contains(multiinput_index), true); + ASSERT_EQ(graph.operands().at(operand_index2).getUses().contains(multiinput_index), true); + + ASSERT_EQ(graph.operands().at(input_operand).getUses().size(), 2); + ASSERT_EQ(graph.operands().at(operand_index1).getUses().size(), 1); + ASSERT_EQ(graph.operands().at(output_operand).getUses().size(), 0); +} diff --git a/runtime/onert/test/graph/operation/Set.cc b/runtime/onert/test/graph/operation/Set.cc new file mode 100644 index 000000000..088c44b8c --- /dev/null +++ b/runtime/onert/test/graph/operation/Set.cc @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "../MockNode.h" +#include "ir/Operations.h" + +using onert::ir::Operation; +using onert::ir::OperationIndex; +using onert::ir::Operations; + +TEST(graph_operation_Set, operation_test) +{ + Operations ops; + ops.push(std::unique_ptr(new onert_test::ir::SimpleMock({1, 2, 3, 4}, {5, 6, 7}))); + OperationIndex idx{0u}; + ASSERT_EQ(ops.at(idx).getInputs().size(), 4); + ASSERT_EQ(ops.at(idx).getOutputs().size(), 3); +} diff --git a/runtime/onert/test/graph/operation/SetIO.cc b/runtime/onert/test/graph/operation/SetIO.cc new file mode 100644 index 000000000..378c5b4b9 --- /dev/null +++ b/runtime/onert/test/graph/operation/SetIO.cc @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ir/Graph.h" +#include "ir/Index.h" +#include "ir/OperandIndexSequence.h" +#include "ir/operation/Conv2D.h" +#include "ir/operation/Concat.h" + +#include + +#include + +using Index = onert::ir::IOIndex; +using IndexSet = onert::ir::OperandIndexSequence; + +TEST(graph_operation_setIO, operation_setIO_conv) +{ + onert::ir::Graph graph; + + onert::ir::Shape shape{3}; + onert::ir::TypeInfo type{onert::ir::DataType::INT32}; + + // Add Conv + using Graph = onert::ir::operation::Conv2D; + + auto input_operand = graph.addOperand(shape, type); + auto kernel_operand = graph.addOperand(shape, type); + auto bias_operand = graph.addOperand(shape, type); + IndexSet inputs{input_operand, kernel_operand, bias_operand}; + + Graph::Param conv_params; + conv_params.padding.type = onert::ir::PaddingType::SAME; + conv_params.stride.horizontal = 1; + conv_params.stride.vertical = 1; + conv_params.activation = onert::ir::Activation::NONE; + + auto output_operand = graph.addOperand(shape, type).value(); + IndexSet outputs{output_operand}; + + auto conv = std::make_unique(inputs, outputs, conv_params); + + ASSERT_NE(conv, nullptr); + ASSERT_EQ(conv->getInputs().at(Index{0}).value(), inputs.at(0).value()); + conv->setInputs({8, 9, 10}); + ASSERT_NE(conv->getInputs().at(Index{0}).value(), inputs.at(0).value()); + ASSERT_EQ(conv->getInputs().at(Index{0}).value(), 8); +} + +TEST(graph_operation_setIO, operation_setIO_concat) +{ + onert::ir::Graph graph; + + onert::ir::Shape shape{3}; + + onert::ir::TypeInfo type{onert::ir::DataType::INT32}; + + using Graph = onert::ir::operation::Concat; + + // Add Concat + IndexSet inputs; + for (int i = 0; i < 6; ++i) + { + inputs.append(graph.addOperand(shape, type)); + } + + Graph::Param concat_params{0}; + + auto output_operand = graph.addOperand(shape, type).value(); + IndexSet outputs{output_operand}; + + auto concat = std::make_unique(inputs, outputs, concat_params); + + ASSERT_NE(concat, nullptr); + ASSERT_EQ(concat->getInputs().size(), 6); + ASSERT_EQ(concat->getInputs().at(Index{0}).value(), inputs.at(0).value()); + + concat->setInputs({80, 6, 9, 11}); + ASSERT_EQ(concat->getInputs().size(), 4); + ASSERT_NE(concat->getInputs().at(Index{0}).value(), inputs.at(0).value()); + ASSERT_EQ(concat->getInputs().at(Index{0}).value(), 80); + ASSERT_EQ(concat->getInputs().at(Index{2}).value(), 9); + ASSERT_THROW(concat->getInputs().at(Index{5}), std::out_of_range); +} diff --git a/runtime/onert/test/graph/verifier/Verifier.cc b/runtime/onert/test/graph/verifier/Verifier.cc new file mode 100644 index 000000000..f8c7557e3 --- /dev/null +++ b/runtime/onert/test/graph/verifier/Verifier.cc @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ir/Operation.h" +#include "ir/Graph.h" +#include "ir/verifier/Verifier.h" +#include +#include "ir/Operand.h" +#include "../MockNode.h" + +using IndexSet = onert::ir::OperandIndexSequence; +using Mock = onert_test::ir::SimpleMock; + +TEST(Verifier, dag_checker) +{ + onert::ir::Graph graph; + + onert::ir::Shape shape{3}; + onert::ir::TypeInfo type{onert::ir::DataType::INT32}; + + auto operand1 = graph.addOperand(shape, type); + auto operand2 = graph.addOperand(shape, type); + + graph.addInput(operand1); + graph.addOutput(operand2); + + graph.addOperation(std::make_unique(IndexSet{operand1}, IndexSet{operand2})); + + graph.finishBuilding(); + + onert::ir::verifier::DAGChecker verifier; + + ASSERT_EQ(verifier.verify(graph), true); +} diff --git a/runtime/onert/test/util/ObjectManager.cc b/runtime/onert/test/util/ObjectManager.cc new file mode 100644 index 000000000..5051bcfa6 --- /dev/null +++ b/runtime/onert/test/util/ObjectManager.cc @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "util/ObjectManager.h" +#include "util/Index.h" + +using namespace onert; + +struct TestTag; +using Index = typename util::Index; + +TEST(ObjectManager, emplace) +{ + util::ObjectManager man; + + auto index = man.emplace(100); + ASSERT_EQ(man.at(index), 100); +} + +TEST(ObjectManager, remove_1) +{ + util::ObjectManager man; + + Index index = man.emplace(100); + ASSERT_TRUE(man.exist(index)); + ASSERT_EQ(man.at(index), 100); + + man.remove(index); + ASSERT_FALSE(man.exist(index)); +} + +TEST(ObjectManager, remove_2) +{ + util::ObjectManager man; + + auto index0 = man.emplace(100); + auto index1 = man.emplace(200); + ASSERT_TRUE(man.exist(index0)); + ASSERT_EQ(man.at(index0), 100); + ASSERT_TRUE(man.exist(index1)); + ASSERT_EQ(man.at(index1), 200); + + man.remove(index0); + ASSERT_FALSE(man.exist(index0)); + ASSERT_TRUE(man.exist(index1)); + ASSERT_EQ(man.at(index1), 200); +} + +TEST(ObjectManager, push) +{ + util::ObjectManager man; + + auto index = man.push(std::unique_ptr{new int{100}}); + ASSERT_EQ(man.at(index), 100); +} + +TEST(ObjectManager, const_iterate) +{ + util::ObjectManager man; + + auto index0 = man.emplace(100); + auto index1 = man.emplace(200); + auto index2 = man.emplace(300); + + int sum = 0; + man.iterate([&](const Index &index, const int &val) { sum += val; }); + ASSERT_EQ(sum, 600); +} + +TEST(ObjectManager, non_const_iterate) +{ + util::ObjectManager man; + + auto index0 = man.emplace(100); + auto index1 = man.emplace(200); + auto index2 = man.emplace(300); + + man.iterate([&](const Index &index, int &val) { val += 1; }); + ASSERT_EQ(man.at(index0), 101); + ASSERT_EQ(man.at(index1), 201); + ASSERT_EQ(man.at(index2), 301); +} diff --git a/runtime/onert/test/util/ShapeInference.cc b/runtime/onert/test/util/ShapeInference.cc new file mode 100644 index 000000000..053b635f2 --- /dev/null +++ b/runtime/onert/test/util/ShapeInference.cc @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ir/Layout.h" +#include "util/ShapeInference.h" + +using namespace onert::ir; + +TEST(ShapeInference, Elementwise) +{ + Shape lhs_shape{1, 299, 299, 3}; + Shape rhs_shape{3}; + auto infered_shapes = onert::shape_inference::inferEltwiseShape(lhs_shape, rhs_shape); + auto infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.dim(0), 1); + ASSERT_EQ(infered_out_shape.dim(1), 299); + ASSERT_EQ(infered_out_shape.dim(2), 299); + ASSERT_EQ(infered_out_shape.dim(3), 3); +} + +TEST(ShapeInference, IncorrectElementwise) +{ + Shape lhs_shape{1, 299, 299, 3}; + Shape rhs_shape{5, 3}; + ASSERT_THROW(onert::shape_inference::inferEltwiseShape(lhs_shape, rhs_shape), std::runtime_error); +} + +TEST(ShapeInference, Pool2DNodeSame) +{ + Shape in_shape{10, 6, 12, 20}; + Stride stride{3, 7}; + Padding padding{PaddingType::SAME}; + + operation::AvgPool2D::Param avg_pool_param{3, 6, stride, padding, Activation::NONE}; + auto infered_shapes = onert::shape_inference::inferAvgPoolShape(in_shape, avg_pool_param); + auto infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20); + + operation::MaxPool2D::Param max_pool_param{3, 6, stride, padding, Activation::NONE}; + infered_shapes = onert::shape_inference::inferMaxPoolShape(in_shape, max_pool_param); + infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20); +} + +TEST(ShapeInference, Pool2DNodeValid) +{ + Shape in_shape{10, 6, 12, 20}; + Stride stride{3, 7}; + Padding padding{PaddingType::VALID}; + + operation::AvgPool2D::Param avg_pool_param{3, 6, stride, padding, Activation::NONE}; + auto infered_shapes = onert::shape_inference::inferAvgPoolShape(in_shape, avg_pool_param); + auto infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20); + + operation::MaxPool2D::Param max_pool_param{3, 6, stride, padding, Activation::NONE}; + infered_shapes = onert::shape_inference::inferMaxPoolShape(in_shape, max_pool_param); + infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20); +} + +TEST(ShapeInference, Pool2DNodeExplicit) +{ + Shape in_shape{10, 3, 5, 20}; + + Stride stride{3, 7}; + Padding padding{4, 3, 2, 1}; + + operation::AvgPool2D::Param avg_pool_param{3, 6, stride, padding, Activation::NONE}; + auto infered_shapes = onert::shape_inference::inferAvgPoolShape(in_shape, avg_pool_param); + auto infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20); + + operation::MaxPool2D::Param max_pool_param{3, 6, stride, padding, Activation::NONE}; + infered_shapes = onert::shape_inference::inferMaxPoolShape(in_shape, max_pool_param); + infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 20); +} + +TEST(ShapeInference, Conv2D) +{ + Shape in_shape{10, 6, 12, 20}; + Shape ker_shape{30, 3, 6, 20}; + + operation::Conv2D::Param param{Stride{3, 7}, Padding{PaddingType::VALID}, Activation::NONE}; + auto infered_shapes = onert::shape_inference::inferConv2DShape(in_shape, ker_shape, param); + auto infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 30); + + param = operation::Conv2D::Param{Stride{3, 7}, Padding{PaddingType::SAME}, Activation::NONE}; + infered_shapes = onert::shape_inference::inferConv2DShape(in_shape, ker_shape, param); + infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 30); + + param = operation::Conv2D::Param{Stride{3, 7}, Padding{4, 3, 2, 1}, Activation::NONE}; + infered_shapes = onert::shape_inference::inferConv2DShape(in_shape, ker_shape, param); + infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 3); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 30); +} + +TEST(ShapeInference, DepthwiseConv2D) +{ + Shape in_shape{10, 6, 12, 20}; + Shape ker_shape{1, 3, 6, 60}; + + operation::DepthwiseConv2D::Param param{Stride{3, 7}, Padding{PaddingType::VALID}, 3, + Activation::NONE}; + auto infered_shapes = + onert::shape_inference::inferDepthwiseConv2DShape(in_shape, ker_shape, param); + auto infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 1); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 60); + + param = operation::DepthwiseConv2D::Param{Stride{3, 7}, Padding{PaddingType::SAME}, 3, + Activation::NONE}; + infered_shapes = onert::shape_inference::inferDepthwiseConv2DShape(in_shape, ker_shape, param); + infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 60); + + param = operation::DepthwiseConv2D::Param{Stride{3, 7}, Padding{4, 3, 2, 1}, 3, Activation::NONE}; + infered_shapes = onert::shape_inference::inferDepthwiseConv2DShape(in_shape, ker_shape, param); + infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 4); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).N, 10); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).H, 3); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).W, 2); + ASSERT_EQ(infered_out_shape.asFeature(Layout::NHWC).C, 60); +} + +TEST(ShapeInference, Concat) +{ + Shape in1{10, 20, 30, 3, 50}; + Shape in2{10, 20, 30, 2, 50}; + Shape in3{10, 20, 30, 2, 50}; + + operation::Concat::Param param{3}; + auto infered_shapes = onert::shape_inference::inferConcatShape({in1, in2, in3}, param); + auto infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 5); + ASSERT_EQ(infered_out_shape.dim(0), 10); + ASSERT_EQ(infered_out_shape.dim(1), 20); + ASSERT_EQ(infered_out_shape.dim(2), 30); + ASSERT_EQ(infered_out_shape.dim(3), 7); + ASSERT_EQ(infered_out_shape.dim(4), 50); +} + +TEST(ShapeInference, FullyConnected) +{ + Shape in_shape{3, 4, 5, 6}; + Shape ker_shape{3, 10}; + auto infered_shapes = onert::shape_inference::inferFullyConnectedShape(in_shape, ker_shape); + auto infered_out_shape = infered_shapes[0]; + + ASSERT_EQ(infered_out_shape.rank(), 2); + ASSERT_EQ(infered_out_shape.dim(0), 36); + ASSERT_EQ(infered_out_shape.dim(1), 3); +} -- cgit v1.2.3