summaryrefslogtreecommitdiff
path: root/runtimes/neurun
diff options
context:
space:
mode:
Diffstat (limited to 'runtimes/neurun')
-rw-r--r--runtimes/neurun/CMakeLists.txt24
-rw-r--r--runtimes/neurun/src/backend/BackendManager.cc104
-rw-r--r--runtimes/neurun/src/backend/BackendManager.h45
-rw-r--r--runtimes/neurun/src/backend/IInitializerGenerator.h46
-rw-r--r--runtimes/neurun/src/backend/IStageGenerator.h68
-rw-r--r--runtimes/neurun/src/backend/ITensorBuilder.h57
-rw-r--r--runtimes/neurun/src/backend/acl_cl/CMakeLists.txt8
-rw-r--r--runtimes/neurun/src/backend/acl_cl/Config.cc (renamed from runtimes/neurun/src/backend/acl_cl/BackendConfig.cc)4
-rw-r--r--runtimes/neurun/src/backend/acl_cl/Config.h (renamed from runtimes/neurun/src/backend/acl_cl/BackendConfig.h)14
-rw-r--r--runtimes/neurun/src/backend/acl_cl/Convert.cc87
-rw-r--r--runtimes/neurun/src/backend/acl_cl/Convert.h47
-rw-r--r--runtimes/neurun/src/backend/acl_cl/InitializerGenerator.cc144
-rw-r--r--runtimes/neurun/src/backend/acl_cl/InitializerGenerator.h50
-rw-r--r--runtimes/neurun/src/backend/acl_cl/PluginClassesAllocator.cc43
-rw-r--r--runtimes/neurun/src/backend/acl_cl/StageGenerator.cc357
-rw-r--r--runtimes/neurun/src/backend/acl_cl/StageGenerator.h20
-rw-r--r--runtimes/neurun/src/backend/acl_cl/Swizzle.h95
-rw-r--r--runtimes/neurun/src/backend/acl_cl/TensorBuilder.cc193
-rw-r--r--runtimes/neurun/src/backend/acl_cl/TensorBuilder.h61
-rw-r--r--runtimes/neurun/src/backend/acl_cl/feature/View.h110
-rw-r--r--runtimes/neurun/src/backend/acl_cl/kernel/View.h87
-rw-r--r--runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.cc61
-rw-r--r--runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.h63
-rw-r--r--runtimes/neurun/src/backend/acl_cl/operand/CLTensor.cc81
-rw-r--r--runtimes/neurun/src/backend/acl_cl/operand/CLTensor.h67
-rw-r--r--runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.cc48
-rw-r--r--runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.h73
-rw-r--r--runtimes/neurun/src/backend/acl_cl/operand/Object.cc3
-rw-r--r--runtimes/neurun/src/backend/acl_cl/operand/Object.h14
-rw-r--r--runtimes/neurun/src/backend/cpu/CMakeLists.txt9
-rw-r--r--runtimes/neurun/src/backend/cpu/Config.cc (renamed from runtimes/neurun/src/backend/cpu/BackendConfig.cc)4
-rw-r--r--runtimes/neurun/src/backend/cpu/Config.h (renamed from runtimes/neurun/src/backend/cpu/BackendConfig.h)18
-rw-r--r--runtimes/neurun/src/backend/cpu/InitializerGenerator.cc208
-rw-r--r--runtimes/neurun/src/backend/cpu/InitializerGenerator.h50
-rw-r--r--runtimes/neurun/src/backend/cpu/MemoryAllocator.h123
-rw-r--r--runtimes/neurun/src/backend/cpu/MemoryPlanner.cc127
-rw-r--r--runtimes/neurun/src/backend/cpu/MemoryPlanner.h166
-rw-r--r--runtimes/neurun/src/backend/cpu/PluginClassesAllocator.cc43
-rw-r--r--runtimes/neurun/src/backend/cpu/StageGenerator.cc361
-rw-r--r--runtimes/neurun/src/backend/cpu/StageGenerator.h20
-rw-r--r--runtimes/neurun/src/backend/cpu/TensorBuilder.cc83
-rw-r--r--runtimes/neurun/src/backend/cpu/TensorBuilder.h47
-rw-r--r--runtimes/neurun/src/backend/cpu/operand/Object.cc3
-rw-r--r--runtimes/neurun/src/backend/cpu/operand/Object.h13
-rw-r--r--runtimes/neurun/src/backend/cpu/operand/Tensor.cc8
-rw-r--r--runtimes/neurun/src/backend/cpu/operand/Tensor.h42
-rw-r--r--runtimes/neurun/src/backend/interface/IConfig.h (renamed from runtimes/neurun/src/backend/IBackendConfig.h)15
-rw-r--r--runtimes/neurun/src/backend/interface/IStageGenerator.h72
-rw-r--r--runtimes/neurun/src/backend/interface/ITensorBuilder.h79
-rw-r--r--runtimes/neurun/src/backend/interface/operand/IObject.h (renamed from runtimes/neurun/src/backend/IObject.h)7
-rw-r--r--runtimes/neurun/src/backend/interface/operand/ITensor.h49
-rw-r--r--runtimes/neurun/src/codegen/IPlanBuilder.h43
-rw-r--r--runtimes/neurun/src/codegen/PlanBuilder.h86
-rw-r--r--runtimes/neurun/src/codegen/Planner.cc253
-rw-r--r--runtimes/neurun/src/codegen/Planner.h67
-rw-r--r--runtimes/neurun/src/compiler/BackendResolver.cc (renamed from runtimes/neurun/src/codegen/BackendResolver.cc)4
-rw-r--r--runtimes/neurun/src/compiler/BackendResolver.h (renamed from runtimes/neurun/src/codegen/BackendResolver.h)52
-rw-r--r--runtimes/neurun/src/compiler/Compiler.cc124
-rw-r--r--runtimes/neurun/src/compiler/Compiler.h73
-rw-r--r--runtimes/neurun/src/compiler/ConstantInitializer.cc188
-rw-r--r--runtimes/neurun/src/compiler/ConstantInitializer.h43
-rw-r--r--runtimes/neurun/src/compiler/OperationValidator.cc121
-rw-r--r--runtimes/neurun/src/compiler/OperationValidator.h56
-rw-r--r--runtimes/neurun/src/compiler/Plan.cc (renamed from runtimes/neurun/src/codegen/Plan.cc)0
-rw-r--r--runtimes/neurun/src/compiler/Plan.h (renamed from runtimes/neurun/src/codegen/Plan.h)23
-rw-r--r--runtimes/neurun/src/compiler/PlanBuilder.cc (renamed from runtimes/neurun/src/codegen/PlanBuilder.cc)41
-rw-r--r--runtimes/neurun/src/compiler/PlanBuilder.h72
-rw-r--r--runtimes/neurun/src/compiler/SubTensorAnalyzer.cc78
-rw-r--r--runtimes/neurun/src/compiler/SubTensorAnalyzer.h66
-rw-r--r--runtimes/neurun/src/compiler/SubTensorInfo.h84
-rw-r--r--runtimes/neurun/src/compiler/TensorInfo.h60
-rw-r--r--runtimes/neurun/src/compiler/operand/Context.cc (renamed from runtimes/neurun/src/codegen/operand/Context.cc)20
-rw-r--r--runtimes/neurun/src/compiler/operand/Context.h (renamed from runtimes/neurun/src/codegen/operand/Context.h)28
-rw-r--r--runtimes/neurun/src/compiler/operation/Sequence.cc (renamed from runtimes/neurun/src/codegen/operation/Sequence.cc)4
-rw-r--r--runtimes/neurun/src/compiler/operation/Sequence.h (renamed from runtimes/neurun/src/codegen/operation/Sequence.h)19
-rw-r--r--runtimes/neurun/src/dumper/dot/DotBuilder.cc85
-rw-r--r--runtimes/neurun/src/dumper/dot/DotBuilder.h79
-rw-r--r--runtimes/neurun/src/dumper/dot/DotDumper.cc115
-rw-r--r--runtimes/neurun/src/dumper/dot/DotDumper.h63
-rw-r--r--runtimes/neurun/src/dumper/dot/DotNodeInfo.cc108
-rw-r--r--runtimes/neurun/src/dumper/dot/DotNodeInfo.h71
-rw-r--r--runtimes/neurun/src/dumper/dot/DotOperandInfo.cc129
-rw-r--r--runtimes/neurun/src/dumper/dot/DotOperandInfo.h77
-rw-r--r--runtimes/neurun/src/dumper/dot/IDotInfo.h67
-rw-r--r--runtimes/neurun/src/exec/Sink.h144
-rw-r--r--runtimes/neurun/src/exec/Source.h147
-rw-r--r--runtimes/neurun/src/exec/interface/IFunction.h36
-rw-r--r--runtimes/neurun/src/frontend/compilation.cc5
-rw-r--r--runtimes/neurun/src/frontend/execution.cc221
-rw-r--r--runtimes/neurun/src/frontend/memory.cc4
-rw-r--r--runtimes/neurun/src/frontend/model.cc262
-rw-r--r--runtimes/neurun/src/frontend/wrapper/compilation.cc51
-rw-r--r--runtimes/neurun/src/frontend/wrapper/compilation.h10
-rw-r--r--runtimes/neurun/src/frontend/wrapper/execution.h20
-rw-r--r--runtimes/neurun/src/frontend/wrapper/model.cc20
-rw-r--r--runtimes/neurun/src/frontend/wrapper/model.h10
-rw-r--r--runtimes/neurun/src/graph/Graph.cc313
-rw-r--r--runtimes/neurun/src/graph/Graph.h79
-rw-r--r--runtimes/neurun/src/graph/Index.h5
-rw-r--r--runtimes/neurun/src/graph/Model.h40
-rw-r--r--runtimes/neurun/src/graph/dumper/Dumper.cc44
-rw-r--r--runtimes/neurun/src/graph/dumper/Dumper.h22
-rw-r--r--runtimes/neurun/src/graph/operand/BackendSet.cc77
-rw-r--r--runtimes/neurun/src/graph/operand/BackendSet.h72
-rw-r--r--runtimes/neurun/src/graph/operand/LowerInfo.h16
-rw-r--r--runtimes/neurun/src/graph/operand/ParentInfo.h79
-rw-r--r--runtimes/neurun/src/graph/operand/Shape4DConvert.h10
-rw-r--r--runtimes/neurun/src/graph/operation/AvgPool2D.h72
-rw-r--r--runtimes/neurun/src/graph/operation/LowerInfo.cc2
-rw-r--r--runtimes/neurun/src/graph/operation/LowerInfo.h6
-rw-r--r--runtimes/neurun/src/graph/operation/NodeVisitor.h56
-rw-r--r--runtimes/neurun/src/graph/operation/Permute.cc41
-rw-r--r--runtimes/neurun/src/graph/operation/Permute.h33
-rw-r--r--runtimes/neurun/src/graph/pass/OperandPass.cc (renamed from runtimes/neurun/src/graph/operation/NOP.cc)18
-rw-r--r--runtimes/neurun/src/graph/pass/OperandPass.h56
-rw-r--r--runtimes/neurun/src/graph/pass/OperationPass.cc (renamed from runtimes/neurun/src/graph/operation/Node.cc)19
-rw-r--r--runtimes/neurun/src/graph/pass/OperationPass.h71
-rw-r--r--runtimes/neurun/src/graph/pass/Pass.cc (renamed from runtimes/neurun/src/backend/cpu/MemoryAllocator.cc)13
-rw-r--r--runtimes/neurun/src/graph/pass/Pass.h55
-rw-r--r--runtimes/neurun/src/graph/pass/PermutationEliminationPass.cc192
-rw-r--r--runtimes/neurun/src/graph/pass/PermutationEliminationPass.h87
-rw-r--r--runtimes/neurun/src/graph/pass/PermutationInsertionPass.cc191
-rw-r--r--runtimes/neurun/src/graph/pass/PermutationInsertionPass.h57
-rw-r--r--runtimes/neurun/src/graph/verifier/IVerifier.cc72
-rw-r--r--runtimes/neurun/src/graph/verifier/Verifier.cc97
-rw-r--r--runtimes/neurun/src/graph/verifier/Verifier.h (renamed from runtimes/neurun/src/graph/verifier/IVerifier.h)12
-rw-r--r--runtimes/neurun/src/internal/Convert.cc59
-rw-r--r--runtimes/neurun/src/internal/Convert.h40
-rw-r--r--runtimes/neurun/src/internal/nnapi/feature/Reader.h75
-rw-r--r--runtimes/neurun/src/internal/nnapi/kernel/Reader.h70
-rw-r--r--runtimes/neurun/src/internal/nnapi/kernel/View.h88
-rw-r--r--runtimes/neurun/src/kernel/acl_cl/CLFunction.h55
-rw-r--r--runtimes/neurun/src/kernel/acl_cl/CMakeLists.txt4
-rw-r--r--runtimes/neurun/src/kernel/acl_cl/ConcatLayer.cc27
-rw-r--r--runtimes/neurun/src/kernel/acl_cl/ConcatLayer.h20
-rw-r--r--runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.cc94
-rw-r--r--runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.h67
-rw-r--r--runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.cc94
-rw-r--r--runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.h67
-rw-r--r--runtimes/neurun/src/kernel/cpu/AvgPoolLayer.cc38
-rw-r--r--runtimes/neurun/src/kernel/cpu/AvgPoolLayer.h4
-rw-r--r--runtimes/neurun/src/kernel/cpu/CMakeLists.txt2
-rw-r--r--runtimes/neurun/src/kernel/cpu/ConcatLayer.cc63
-rw-r--r--runtimes/neurun/src/kernel/cpu/ConcatLayer.h4
-rw-r--r--runtimes/neurun/src/kernel/cpu/ConvolutionLayer.cc146
-rw-r--r--runtimes/neurun/src/kernel/cpu/ConvolutionLayer.h4
-rw-r--r--runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.cc77
-rw-r--r--runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.h4
-rw-r--r--runtimes/neurun/src/kernel/cpu/MaxPoolLayer.cc37
-rw-r--r--runtimes/neurun/src/kernel/cpu/MaxPoolLayer.h4
-rw-r--r--runtimes/neurun/src/kernel/cpu/OperationUtils.cc2
-rw-r--r--runtimes/neurun/src/kernel/cpu/OperationUtils.h55
-rw-r--r--runtimes/neurun/src/kernel/cpu/PermuteLayer.cc201
-rw-r--r--runtimes/neurun/src/kernel/cpu/PermuteLayer.h58
-rw-r--r--runtimes/neurun/src/kernel/cpu/ReshapeLayer.h4
-rw-r--r--runtimes/neurun/src/kernel/cpu/SoftMaxLayer.cc72
-rw-r--r--runtimes/neurun/src/kernel/cpu/SoftMaxLayer.h4
-rw-r--r--runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.cc90
-rw-r--r--runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.h67
-rw-r--r--runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.cc90
-rw-r--r--runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.h67
-rw-r--r--runtimes/neurun/src/linear/Linear.cc152
-rw-r--r--runtimes/neurun/src/linear/Linear.h25
-rw-r--r--runtimes/neurun/src/model/operand/Data.h (renamed from runtimes/neurun/src/graph/operand/Data.h)10
-rw-r--r--runtimes/neurun/src/model/operand/DataType.h (renamed from runtimes/neurun/src/graph/operand/DataType.h)10
-rw-r--r--runtimes/neurun/src/model/operand/Index.h (renamed from runtimes/neurun/src/graph/operand/Index.h)14
-rw-r--r--runtimes/neurun/src/model/operand/IndexSet.cc (renamed from runtimes/neurun/src/graph/operand/IndexSet.cc)9
-rw-r--r--runtimes/neurun/src/model/operand/IndexSet.h (renamed from runtimes/neurun/src/graph/operand/IndexSet.h)11
-rw-r--r--runtimes/neurun/src/model/operand/Object.cc (renamed from runtimes/neurun/src/graph/operand/Object.cc)27
-rw-r--r--runtimes/neurun/src/model/operand/Object.h (renamed from runtimes/neurun/src/graph/operand/Object.h)39
-rw-r--r--runtimes/neurun/src/model/operand/Set.cc (renamed from runtimes/neurun/src/graph/operand/Set.cc)26
-rw-r--r--runtimes/neurun/src/model/operand/Set.h (renamed from runtimes/neurun/src/graph/operand/Set.h)11
-rw-r--r--runtimes/neurun/src/model/operand/Shape.cc (renamed from runtimes/neurun/src/graph/operand/Shape.cc)33
-rw-r--r--runtimes/neurun/src/model/operand/Shape.h (renamed from runtimes/neurun/src/graph/operand/Shape.h)24
-rw-r--r--runtimes/neurun/src/model/operand/TypeInfo.cc (renamed from runtimes/neurun/src/graph/operand/TypeInfo.cc)6
-rw-r--r--runtimes/neurun/src/model/operand/TypeInfo.h (renamed from runtimes/neurun/src/graph/operand/TypeInfo.h)14
-rw-r--r--runtimes/neurun/src/model/operation/AddNode.cc49
-rw-r--r--runtimes/neurun/src/model/operation/AddNode.h (renamed from runtimes/neurun/src/graph/operation/Reshape.h)37
-rw-r--r--runtimes/neurun/src/model/operation/AvgPool2DNode.cc (renamed from runtimes/neurun/src/graph/operation/AvgPool2D.cc)44
-rw-r--r--runtimes/neurun/src/model/operation/AvgPool2DNode.h (renamed from runtimes/neurun/src/graph/operation/MaxPool2D.h)52
-rw-r--r--runtimes/neurun/src/model/operation/ConcatNode.cc (renamed from runtimes/neurun/src/graph/operation/Concat.cc)26
-rw-r--r--runtimes/neurun/src/model/operation/ConcatNode.h (renamed from runtimes/neurun/src/graph/operation/Concat.h)33
-rw-r--r--runtimes/neurun/src/model/operation/Conv2DNode.cc (renamed from runtimes/neurun/src/graph/operation/Conv2D.cc)40
-rw-r--r--runtimes/neurun/src/model/operation/Conv2DNode.h (renamed from runtimes/neurun/src/graph/operation/Conv2D.h)52
-rw-r--r--runtimes/neurun/src/model/operation/FullyConnectedNode.cc (renamed from runtimes/neurun/src/graph/operation/FullyConnected.cc)31
-rw-r--r--runtimes/neurun/src/model/operation/FullyConnectedNode.h (renamed from runtimes/neurun/src/graph/operation/FullyConnected.h)41
-rw-r--r--runtimes/neurun/src/model/operation/Index.h (renamed from runtimes/neurun/src/graph/operation/Index.h)10
-rw-r--r--runtimes/neurun/src/model/operation/IndexList.cc (renamed from runtimes/neurun/src/graph/operation/IndexList.cc)6
-rw-r--r--runtimes/neurun/src/model/operation/IndexList.h (renamed from runtimes/neurun/src/graph/operation/IndexList.h)10
-rw-r--r--runtimes/neurun/src/model/operation/MaxPool2DNode.cc (renamed from runtimes/neurun/src/graph/operation/MaxPool2D.cc)44
-rw-r--r--runtimes/neurun/src/model/operation/MaxPool2DNode.h68
-rw-r--r--runtimes/neurun/src/model/operation/Node.Include.h27
-rw-r--r--runtimes/neurun/src/model/operation/Node.cc54
-rw-r--r--runtimes/neurun/src/model/operation/Node.h (renamed from runtimes/neurun/src/graph/operation/Node.h)43
-rw-r--r--runtimes/neurun/src/model/operation/NodeVisitor.h43
-rw-r--r--runtimes/neurun/src/model/operation/Op.lst (renamed from runtimes/neurun/src/graph/operation/Op.lst)18
-rw-r--r--runtimes/neurun/src/model/operation/OperandConstraint.cc28
-rw-r--r--runtimes/neurun/src/model/operation/OperandConstraint.h61
-rw-r--r--runtimes/neurun/src/model/operation/PermuteNode.cc41
-rw-r--r--runtimes/neurun/src/model/operation/PermuteNode.h62
-rw-r--r--runtimes/neurun/src/model/operation/ReshapeNode.cc (renamed from runtimes/neurun/src/graph/operation/Reshape.cc)29
-rw-r--r--runtimes/neurun/src/model/operation/ReshapeNode.h (renamed from runtimes/neurun/src/graph/operation/NOP.h)25
-rw-r--r--runtimes/neurun/src/model/operation/Set.cc (renamed from runtimes/neurun/src/graph/operation/Set.cc)4
-rw-r--r--runtimes/neurun/src/model/operation/Set.h (renamed from runtimes/neurun/src/graph/operation/Set.h)13
-rw-r--r--runtimes/neurun/src/model/operation/SoftmaxNode.cc (renamed from runtimes/neurun/src/graph/operation/Softmax.cc)31
-rw-r--r--runtimes/neurun/src/model/operation/SoftmaxNode.h (renamed from runtimes/neurun/src/graph/operation/Softmax.h)38
-rw-r--r--runtimes/neurun/src/util/Padding.cc (renamed from runtimes/neurun/src/internal/Padding.cc)13
-rw-r--r--runtimes/neurun/src/util/Padding.h (renamed from runtimes/neurun/src/internal/Padding.h)19
-rw-r--r--runtimes/neurun/src/util/Utils.cc42
-rw-r--r--runtimes/neurun/src/util/Utils.h43
-rw-r--r--runtimes/neurun/src/util/config/Config.lst34
-rw-r--r--runtimes/neurun/src/util/config/ConfigManager.cc74
-rw-r--r--runtimes/neurun/src/util/config/ConfigManager.h71
-rw-r--r--runtimes/neurun/src/util/feature/Coordinate4D.h89
-rw-r--r--runtimes/neurun/src/util/feature/nchw/View.h106
-rw-r--r--runtimes/neurun/src/util/feature/nhwc/Reader.h72
-rw-r--r--runtimes/neurun/src/util/feature/nhwc/Utils.h (renamed from runtimes/neurun/src/internal/nnapi/feature/Utils.h)23
-rw-r--r--runtimes/neurun/src/util/feature/nhwc/View.h (renamed from runtimes/neurun/src/internal/nnapi/feature/View.h)54
-rw-r--r--runtimes/neurun/src/util/logging.h (renamed from runtimes/neurun/src/logging.h)16
-rw-r--r--runtimes/neurun/test/backend/cpu/MemoryPlanner.cc127
-rw-r--r--runtimes/neurun/test/graph/Graph.cc16
-rw-r--r--runtimes/neurun/test/graph/MockNode.h (renamed from runtimes/neurun/test/graph/operation/MockNode.h)23
-rw-r--r--runtimes/neurun/test/graph/operand/IndexSet.cc21
-rw-r--r--runtimes/neurun/test/graph/operand/LayoutSet.cc16
-rw-r--r--runtimes/neurun/test/graph/operand/Set.cc22
-rw-r--r--runtimes/neurun/test/graph/operand/UseDef.cc102
-rw-r--r--runtimes/neurun/test/graph/operation/Insert.cc166
-rw-r--r--runtimes/neurun/test/graph/operation/Set.cc14
-rw-r--r--runtimes/neurun/test/graph/operation/SetIO.cc34
-rw-r--r--runtimes/neurun/test/graph/verifier/Verifier.cc37
230 files changed, 8449 insertions, 4966 deletions
diff --git a/runtimes/neurun/CMakeLists.txt b/runtimes/neurun/CMakeLists.txt
index 2cbd702b0..92547da2c 100644
--- a/runtimes/neurun/CMakeLists.txt
+++ b/runtimes/neurun/CMakeLists.txt
@@ -18,29 +18,23 @@ file(GLOB SOURCES_BACKEND "src/backend/*.cc")
file(GLOB_RECURSE SOURCES_INTERNAL "src/internal/*.cc")
file(GLOB_RECURSE SOURCES_GRAPH "src/graph/*.cc")
file(GLOB_RECURSE SOURCES_LINEAR "src/linear/*.cc")
-file(GLOB_RECURSE SOURCES_CODEGEN "src/codegen/*.cc")
+file(GLOB_RECURSE SOURCES_DUMPER "src/dumper/*.cc")
+file(GLOB_RECURSE SOURCES_COMPILER "src/compiler/*.cc")
file(GLOB_RECURSE SOURCES_VERIFIER "src/verifier/*.cc")
+file(GLOB_RECURSE SOURCES_UTIL "src/util/*.cc")
+file(GLOB_RECURSE SOURCES_MODEL "src/model/*.cc")
-set(SOURCES ${SOURCES} ${SOURCES_FRONTEND} ${SOURCES_BACKEND} ${SOURCES_INTERNAL} ${SOURCES_GRAPH} ${SOURCES_LINEAR} ${SOURCES_CODEGEN} ${SOURCES_VERIFIER})
-
-# NOTE For now ARMCompute is necessary
-# TODO Remove required package below(should be optional)
-nnfw_find_package(ARMCompute REQUIRED)
+set(SOURCES ${SOURCES} ${SOURCES_FRONTEND} ${SOURCES_BACKEND} ${SOURCES_INTERNAL} ${SOURCES_GRAPH} ${SOURCES_LINEAR} ${SOURCES_DUMPER} ${SOURCES_COMPILER} ${SOURCES_VERIFIER} ${SOURCES_UTIL} ${SOURCES_MODEL})
add_library(${LIB_NEURUN} SHARED ${SOURCES})
target_include_directories(${LIB_NEURUN} PUBLIC ${NNFW_INCLUDE_DIR})
target_include_directories(${LIB_NEURUN} PUBLIC ${NEURUN_INCLUDE_DIR})
target_include_directories(${LIB_NEURUN} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow)
-target_link_libraries(${LIB_NEURUN} arm_compute)
target_link_libraries(${LIB_NEURUN} tensorflow-lite)
-target_link_libraries(${LIB_NEURUN} nnfw_util)
-target_link_libraries(${LIB_NEURUN} nnfw_support_nnapi)
-
-# TODO This should be optional
-target_link_libraries(${LIB_NEURUN} ${LIB_NEURUN_BACKEND_CPU})
-target_link_libraries(${LIB_NEURUN} ${LIB_NEURUN_BACKEND_ACL_CL})
+target_link_libraries(${LIB_NEURUN} nnfw_lib_misc)
+target_link_libraries(${LIB_NEURUN} nnfw_lib_cpp14)
-target_compile_options(${LIB_NEURUN} PRIVATE -Wall -Wextra -Werror)
+target_compile_options(${LIB_NEURUN} PRIVATE -Wall -Wextra -Werror -Wno-unused-parameter)
set_target_properties(${LIB_NEURUN} PROPERTIES OUTPUT_NAME neuralnetworks)
@@ -58,6 +52,8 @@ target_link_libraries(${TEST_NEURUN} ${LIB_NEURUN})
target_link_libraries(${TEST_NEURUN} gtest)
target_link_libraries(${TEST_NEURUN} gtest_main)
target_link_libraries(${TEST_NEURUN} ${LIB_PTHREAD})
+target_link_libraries(${TEST_NEURUN} ${LIB_NEURUN_BACKEND_CPU})
+target_link_libraries(${TEST_NEURUN} ${LIB_NEURUN_BACKEND_ACL_CL})
add_test(${TEST_NEURUN} ${TEST_NEURUN})
install(TARGETS ${TEST_NEURUN} DESTINATION unittest)
diff --git a/runtimes/neurun/src/backend/BackendManager.cc b/runtimes/neurun/src/backend/BackendManager.cc
index fb7d69108..5d19d4015 100644
--- a/runtimes/neurun/src/backend/BackendManager.cc
+++ b/runtimes/neurun/src/backend/BackendManager.cc
@@ -14,36 +14,28 @@
* limitations under the License.
*/
+#include <dlfcn.h>
#include "BackendManager.h"
-#include "backend/acl_cl/BackendConfig.h"
-#include "backend/acl_cl/TensorBuilder.h"
-#include "backend/acl_cl/InitializerGenerator.h"
-#include "backend/acl_cl/StageGenerator.h"
-#include "backend/cpu/BackendConfig.h"
-#include "backend/cpu/TensorBuilder.h"
-#include "backend/cpu/InitializerGenerator.h"
-#include "backend/cpu/StageGenerator.h"
+#include "backend/interface/IConfig.h"
+#include "backend/interface/ITensorBuilder.h"
+#include "backend/interface/IStageGenerator.h"
+#include "util/logging.h"
+#include "util/config/ConfigManager.h"
namespace neurun
{
namespace backend
{
-Backend::Backend(const std::shared_ptr<neurun::backend::IBackendConfig> &backend_config,
- const std::shared_ptr<neurun::backend::IInitializerGenerator> &initializer_gen,
+Backend::Backend(const std::shared_ptr<neurun::backend::IConfig> &backend_config,
const std::shared_ptr<neurun::backend::IStageGenerator> &stage_gen)
- : _config(backend_config), _initializer_gen(initializer_gen), _stage_gen(stage_gen)
+ : _config(backend_config), _stage_gen(stage_gen)
{
backend_config->initialize();
}
-const std::shared_ptr<neurun::backend::IBackendConfig> Backend::config() const { return _config; }
-
-const std::shared_ptr<neurun::backend::IInitializerGenerator> Backend::initializer_gen() const
-{
- return _initializer_gen;
-}
+const std::shared_ptr<neurun::backend::IConfig> Backend::config() const { return _config; }
const std::shared_ptr<neurun::backend::IStageGenerator> Backend::stage_gen() const
{
@@ -55,34 +47,72 @@ const std::shared_ptr<neurun::backend::ITensorBuilder> Backend::tensor_builder()
return _stage_gen->tensor_builder();
}
-BackendManager::BackendManager(const neurun::graph::operand::Set &operands)
+template <typename T, class... Types>
+void BackendManager::loadObjectFromPlugin(std::shared_ptr<T> &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,
+ const neurun::model::operand::Set &operands)
{
- // Add arm_compute backend
+ const std::string backend_plugin = "libbackend_" + backend + ".so";
+ void *handle = dlopen(backend_plugin.c_str(), RTLD_LAZY | RTLD_LOCAL);
+ if (handle == nullptr)
{
- using namespace ::neurun::backend::acl_cl;
- auto acl_backend_initializer = std::make_shared<BackendConfig>();
- auto acl_tensor_builder = std::make_shared<TensorBuilder>();
- auto acl_initializer_gen = std::make_shared<InitializerGenerator>(operands);
- auto acl_stage_gen = std::make_shared<StageGenerator>(operands, acl_tensor_builder);
-
- // TODO Do not use magic string for backend id
- _gen_map["acl_cl"] = {acl_backend_initializer, acl_initializer_gen, acl_stage_gen};
+ fprintf(stderr, "BackendManager::loadBackend failed to load plugin of %s backend: %s\n",
+ backend.c_str(), dlerror());
+ abort();
}
+ VERBOSE(BackendManager::loadBackend) << "loaded " << backend_plugin << " as a plugin of "
+ << backend << " backend\n";
+
+ // load Config
+ std::shared_ptr<neurun::backend::IConfig> config;
+ loadObjectFromPlugin(config, std::string("allocate_Config"), handle);
+
+ // load TensorBuilder
+ std::shared_ptr<neurun::backend::ITensorBuilder> tensor_builder;
+ loadObjectFromPlugin(tensor_builder, std::string("allocate_TensorBuilder"), handle);
+
+ // load StageGenerator
+ std::shared_ptr<neurun::backend::IStageGenerator> stage_gen;
+ loadObjectFromPlugin(stage_gen, std::string("allocate_StageGenerator"), handle, operands,
+ tensor_builder);
+ _gen_map[config->id()] = {config, stage_gen};
+}
- // Add CPU backend
+BackendManager::BackendManager(const neurun::model::operand::Set &operands)
+{
+ const auto backends = config::ConfigManager::instance().get<std::string>("BACKENDS");
+ size_t prev_pos = 0;
+ auto pos = backends.find(";");
+ while (pos != std::string::npos)
+ {
+ loadBackend(backends.substr(prev_pos, pos - prev_pos), operands);
+ prev_pos = pos + 1;
+ pos = backends.find(";", prev_pos);
+ }
+ // if backends doesn't terminate with ";"
+ if (prev_pos < backends.size())
{
- using namespace ::neurun::backend::cpu;
- auto cpu_backend_initializer = std::make_shared<BackendConfig>();
- auto cpu_tensor_builder = std::make_shared<TensorBuilder>();
- auto cpu_initializer_gen = std::make_shared<InitializerGenerator>(operands);
- auto cpu_stage_gen = std::make_shared<StageGenerator>(operands, cpu_tensor_builder);
-
- // TODO Do not use magic string for backend id
- _gen_map["cpu"] = {cpu_backend_initializer, cpu_initializer_gen, cpu_stage_gen};
+ loadBackend(backends.substr(prev_pos), operands);
}
}
-Backend BackendManager::get(const std::string &key) { return _gen_map.at(key); }
+Backend *BackendManager::get(const std::string &key) { return &_gen_map.at(key); }
} // namespace backend
} // namespace neurun
diff --git a/runtimes/neurun/src/backend/BackendManager.h b/runtimes/neurun/src/backend/BackendManager.h
index 6f862ffe6..428542b1e 100644
--- a/runtimes/neurun/src/backend/BackendManager.h
+++ b/runtimes/neurun/src/backend/BackendManager.h
@@ -20,51 +20,72 @@
#include <memory>
#include <map>
-#include "graph/operand/Set.h"
+#include "model/operand/Set.h"
namespace neurun
{
namespace backend
{
-struct IBackendConfig;
-struct IInitializerGenerator;
+struct IConfig;
struct IStageGenerator;
struct ITensorBuilder;
class Backend
{
public:
- Backend(const std::shared_ptr<neurun::backend::IBackendConfig> &backend_config,
- const std::shared_ptr<neurun::backend::IInitializerGenerator> &initializer_gen,
+ Backend(const std::shared_ptr<neurun::backend::IConfig> &backend_config,
const std::shared_ptr<neurun::backend::IStageGenerator> &stage_gen);
- Backend(void) : _config(nullptr), _initializer_gen(nullptr), _stage_gen(nullptr)
+ Backend(void) : _config(nullptr), _stage_gen(nullptr)
{
// DO NOTHING
}
public:
- const std::shared_ptr<neurun::backend::IBackendConfig> config() const;
- const std::shared_ptr<neurun::backend::IInitializerGenerator> initializer_gen() const;
+ const std::shared_ptr<neurun::backend::IConfig> config() const;
const std::shared_ptr<neurun::backend::IStageGenerator> stage_gen() const;
const std::shared_ptr<neurun::backend::ITensorBuilder> tensor_builder() const;
private:
- std::shared_ptr<neurun::backend::IBackendConfig> _config;
- std::shared_ptr<neurun::backend::IInitializerGenerator> _initializer_gen;
+ std::shared_ptr<neurun::backend::IConfig> _config;
std::shared_ptr<neurun::backend::IStageGenerator> _stage_gen;
};
class BackendManager
{
public:
- BackendManager(const neurun::graph::operand::Set &operands);
+ BackendManager(const neurun::model::operand::Set &operands);
- Backend get(const std::string &key);
+ Backend *get(const std::string &key);
private:
std::map<std::string, Backend> _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 <typename T, class... Types>
+ void loadObjectFromPlugin(std::shared_ptr<T> &object_of_plugin_class,
+ const std::string obj_creator_func_name, void *handle,
+ Types &&... args);
+
+ /**
+ * @brief load backend plugin
+ *
+ * @param backend backend to be loaded
+ * @param operands operands to construct StageGenerator
+ *
+ * @return
+ */
+ void loadBackend(const std::string &backend, const neurun::model::operand::Set &operands);
};
} // namespace backend
diff --git a/runtimes/neurun/src/backend/IInitializerGenerator.h b/runtimes/neurun/src/backend/IInitializerGenerator.h
deleted file mode 100644
index 83cf87a52..000000000
--- a/runtimes/neurun/src/backend/IInitializerGenerator.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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 __INTERNAL_IINITIALIZER_GENERATOR_H__
-#define __INTERNAL_IINITIALIZER_GENERATOR_H__
-
-#include "arm_compute/core/ITensor.h"
-
-#include "graph/operation/Conv2D.h"
-#include "graph/operation/FullyConnected.h"
-
-using Initializer = std::function<void(::arm_compute::ITensor &)>;
-
-namespace neurun
-{
-namespace backend
-{
-
-struct IInitializerGenerator
-{
- virtual ~IInitializerGenerator() = default;
-
- virtual Initializer generateWeight(const graph::operation::Conv2D::Implicit::Node &node) = 0;
- virtual Initializer generateWeight(const graph::operation::FullyConnected::Node &node) = 0;
-
- virtual Initializer generateBias(const graph::operation::Conv2D::Implicit::Node &node) = 0;
- virtual Initializer generateBias(const graph::operation::FullyConnected::Node &node) = 0;
-};
-
-} // namespace backend
-} // namespace neurun
-
-#endif // __INTERNAL_IINITIALIZER_GENERATOR_H__
diff --git a/runtimes/neurun/src/backend/IStageGenerator.h b/runtimes/neurun/src/backend/IStageGenerator.h
deleted file mode 100644
index 05959e2b1..000000000
--- a/runtimes/neurun/src/backend/IStageGenerator.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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 __INTERNAL_ISTAGE_GENERATOR_H__
-#define __INTERNAL_ISTAGE_GENERATOR_H__
-
-#include <memory>
-#include <functional>
-
-#include <arm_compute/runtime/IFunction.h>
-
-#include "backend/ITensorBuilder.h"
-#include "graph/operation/Conv2D.h"
-#include "graph/operation/MaxPool2D.h"
-#include "graph/operation/AvgPool2D.h"
-#include "graph/operation/Concat.h"
-#include "graph/operation/FullyConnected.h"
-#include "graph/operation/Reshape.h"
-#include "graph/operation/Softmax.h"
-#include "graph/operation/NOP.h"
-
-struct IExecutionBuilder
-{
- virtual ~IExecutionBuilder() = default;
-
- virtual void append(std::unique_ptr<::arm_compute::IFunction> &&f) = 0;
-};
-
-using Stage = std::function<void(IExecutionBuilder &)>;
-
-namespace neurun
-{
-namespace backend
-{
-
-struct IStageGenerator
-{
- virtual ~IStageGenerator() = default;
-
- virtual std::shared_ptr<ITensorBuilder> tensor_builder() = 0;
-
- virtual Stage generate(const graph::operation::Conv2D::Implicit::Node &node) = 0;
- virtual Stage generate(const graph::operation::MaxPool2D::Implicit::Node &node) = 0;
- virtual Stage generate(const graph::operation::AvgPool2D::Implicit::Node &node) = 0;
- virtual Stage generate(const graph::operation::Concat::Node &node) = 0;
- virtual Stage generate(const graph::operation::FullyConnected::Node &node) = 0;
- virtual Stage generate(const graph::operation::Reshape::Node &node) = 0;
- virtual Stage generate(const graph::operation::Softmax::Node &node) = 0;
- virtual Stage generate(const graph::operation::NOP::Node &node) = 0;
-};
-
-} // namespace backend
-} // namespace neurun
-
-#endif // __INTERNAL_ISTAGE_GENERATOR_H__
diff --git a/runtimes/neurun/src/backend/ITensorBuilder.h b/runtimes/neurun/src/backend/ITensorBuilder.h
deleted file mode 100644
index c3a07ffeb..000000000
--- a/runtimes/neurun/src/backend/ITensorBuilder.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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 __INTERNAL_ITENSOR_BUILDER_H__
-#define __INTERNAL_ITENSOR_BUILDER_H__
-
-#include <map>
-#include <arm_compute/core/TensorInfo.h>
-
-#include "graph/operand/Index.h"
-#include "codegen/Plan.h"
-
-namespace neurun
-{
-namespace backend
-{
-
-struct ITensorBuilder
-{
- virtual ~ITensorBuilder(void) = default;
- virtual void mark(const ::neurun::graph::operand::Index &ind) = 0;
- // TODO Add an interface for adding subsumption info
- virtual void prepare(codegen::Plan &plan,
- const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx) = 0;
- virtual void allocate(void) = 0;
-};
-
-} // namespace backend
-} // namespace neurun
-
-#include <set>
-#include <memory>
-
-namespace neurun
-{
-namespace backend
-{
-
-using TensorBuilderSet = std::set<std::shared_ptr<backend::ITensorBuilder>>;
-
-} // namespace backend
-} // namespace neurun
-
-#endif // __INTERNAL_ITENSOR_BUILDER_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/CMakeLists.txt b/runtimes/neurun/src/backend/acl_cl/CMakeLists.txt
index d64c23a80..f1ea22bc5 100644
--- a/runtimes/neurun/src/backend/acl_cl/CMakeLists.txt
+++ b/runtimes/neurun/src/backend/acl_cl/CMakeLists.txt
@@ -1,17 +1,15 @@
file(GLOB_RECURSE SOURCES "*.cc")
-add_library(${LIB_NEURUN_BACKEND_ACL_CL} STATIC ${SOURCES})
+add_library(${LIB_NEURUN_BACKEND_ACL_CL} SHARED ${SOURCES})
target_include_directories(${LIB_NEURUN_BACKEND_ACL_CL} PUBLIC ${NNFW_INCLUDE_DIR})
target_include_directories(${LIB_NEURUN_BACKEND_ACL_CL} PUBLIC ${NEURUN_INCLUDE_DIR})
-target_include_directories(${LIB_NEURUN_BACKEND_ACL_CL} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow) # TODO Remove this file. We should not need this.
target_link_libraries(${LIB_NEURUN_BACKEND_ACL_CL} arm_compute)
-target_link_libraries(${LIB_NEURUN_BACKEND_ACL_CL} nnfw_support_nnapi)
target_link_libraries(${LIB_NEURUN_BACKEND_ACL_CL} ${LIB_NEURUN_KERNEL_ACL_CL})
+target_link_libraries(${LIB_NEURUN_BACKEND_ACL_CL} ${LIB_NEURUN})
-target_compile_options(${LIB_NEURUN_BACKEND_ACL_CL} PRIVATE -Wall -Wextra -Werror)
+target_compile_options(${LIB_NEURUN_BACKEND_ACL_CL} PRIVATE -Wall -Wextra -Werror -Wno-unused-parameter)
-set_target_properties(${LIB_NEURUN_BACKEND_ACL_CL} PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(${LIB_NEURUN_BACKEND_ACL_CL} PROPERTIES OUTPUT_NAME backend_acl_cl)
install(TARGETS ${LIB_NEURUN_BACKEND_ACL_CL} DESTINATION lib/neurun)
diff --git a/runtimes/neurun/src/backend/acl_cl/BackendConfig.cc b/runtimes/neurun/src/backend/acl_cl/Config.cc
index 6b3e6b3a3..cad9b8988 100644
--- a/runtimes/neurun/src/backend/acl_cl/BackendConfig.cc
+++ b/runtimes/neurun/src/backend/acl_cl/Config.cc
@@ -16,7 +16,7 @@
#include <arm_compute/runtime/CL/CLScheduler.h>
-#include "backend/acl_cl/BackendConfig.h"
+#include "backend/acl_cl/Config.h"
namespace neurun
{
@@ -25,7 +25,7 @@ namespace backend
namespace acl_cl
{
-void BackendConfig::initialize() { arm_compute::CLScheduler::get().default_init(); }
+void Config::initialize() { arm_compute::CLScheduler::get().default_init(); }
} // namespace acl_cl
} // namespace backend
diff --git a/runtimes/neurun/src/backend/acl_cl/BackendConfig.h b/runtimes/neurun/src/backend/acl_cl/Config.h
index 8eec9e795..cb43bfbe0 100644
--- a/runtimes/neurun/src/backend/acl_cl/BackendConfig.h
+++ b/runtimes/neurun/src/backend/acl_cl/Config.h
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#ifndef __NEURUN_BACKEND_ACL_CL_BACKEND_CONFIG_H__
-#define __NEURUN_BACKEND_ACL_CL_BACKEND_CONFIG_H__
+#ifndef __NEURUN_BACKEND_ACL_CL_CONFIG_H__
+#define __NEURUN_BACKEND_ACL_CL_CONFIG_H__
-#include "backend/IBackendConfig.h"
+#include "backend/interface/IConfig.h"
namespace neurun
{
@@ -26,20 +26,22 @@ namespace backend
namespace acl_cl
{
-class BackendConfig : public IBackendConfig
+class Config : public IConfig
{
public:
- BackendConfig()
+ Config()
{
// DO NOTHING
}
+ virtual std::string id() override { return "acl_cl"; }
virtual void initialize() override;
virtual graph::operand::Layout getOperandLayout() { return graph::operand::Layout::NCHW; }
+ virtual bool SupportSubTensorAlloc() override { return true; }
};
} // namespace acl_cl
} // namespace backend
} // namespace neurun
-#endif // __NEURUN_BACKEND_ACL_CL_BACKEND_CONFIG_H__
+#endif // __NEURUN_BACKEND_ACL_CL_CONFIG_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/Convert.cc b/runtimes/neurun/src/backend/acl_cl/Convert.cc
new file mode 100644
index 000000000..ed0a089c4
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/Convert.cc
@@ -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.
+ */
+
+#include "Convert.h"
+
+#include "Swizzle.h"
+#include "model/operand/DataType.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+::arm_compute::TensorShape asTensorShape(const ::neurun::model::operand::Shape &shape,
+ 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).value(), shape.dim(axis), apply_dim_correction);
+ }
+
+ return res;
+}
+
+::arm_compute::DataType asDataType(const ::neurun::model::operand::DataType &type)
+{
+ switch (type)
+ {
+ case ::neurun::model::operand::DataType::SCALAR_FLOAT32:
+ case ::neurun::model::operand::DataType::TENSOR_FLOAT32:
+ return ::arm_compute::DataType::F32;
+ case ::neurun::model::operand::DataType::SCALAR_INT32:
+ case ::neurun::model::operand::DataType::TENSOR_INT32:
+ return ::arm_compute::DataType::S32;
+ case ::neurun::model::operand::DataType::SCALAR_UINT32:
+ return ::arm_compute::DataType::U32;
+ case ::neurun::model::operand::DataType::TENSOR_QUANT8_ASYMM:
+ return ::arm_compute::DataType::QASYMM8;
+ 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 ::neurun::model::operand::Shape &shape,
+ const ::neurun::model::operand::TypeInfo &typeInfo)
+{
+ return ::arm_compute::TensorInfo(asTensorShape(shape), 1, asDataType(typeInfo.type()),
+ asQuantizationInfo(typeInfo.scale(), typeInfo.offset()));
+}
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace neurun
diff --git a/runtimes/neurun/src/backend/acl_cl/Convert.h b/runtimes/neurun/src/backend/acl_cl/Convert.h
new file mode 100644
index 000000000..1a233fb87
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/Convert.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 __NEURUN_BACKEND_ACL_CL_CONVERT_H__
+#define __NEURUN_BACKEND_ACL_CL_CONVERT_H__
+
+#include <arm_compute/core/TensorInfo.h>
+#include <arm_compute/core/SubTensorInfo.h>
+#include <arm_compute/core/TensorShape.h>
+
+#include "model/operand/Object.h"
+#include "model/operand/Shape.h"
+#include "model/operand/TypeInfo.h"
+#include "misc/feature/Shape.h"
+#include "misc/kernel/Shape.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+::arm_compute::TensorShape asTensorShape(const ::neurun::model::operand::Shape &shape,
+ bool apply_dim_correction = true);
+::arm_compute::DataType asDataType(const ::neurun::model::operand::DataType &type);
+::arm_compute::TensorInfo asTensorInfo(const ::neurun::model::operand::Shape &shape,
+ const ::neurun::model::operand::TypeInfo &typeInfo);
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ACL_CL_CONVERT_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.cc b/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.cc
deleted file mode 100644
index 9a681b3de..000000000
--- a/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * 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/acl_cl/InitializerGenerator.h"
-
-#include <arm_compute/core/Coordinates.h>
-
-#include "backend/acl_cl/kernel/View.h"
-#include "internal/nnapi/kernel/Reader.h"
-#include "util/kernel/IndexIterator.h"
-
-namespace neurun
-{
-namespace backend
-{
-namespace acl_cl
-{
-
-InitializerGenerator::InitializerGenerator(const neurun::graph::operand::Set &ctx) : _ctx(ctx)
-{
- // DO NOTHING
-}
-
-Initializer
-InitializerGenerator::generateWeight(const graph::operation::Conv2D::Implicit::Node &node)
-{
- const ::neurun::graph::operand::Index ker_index{node.getInputs().at(1)};
-
- const auto ker_shape = _ctx.at(ker_index).shape().asKernel();
- auto ker_base = _ctx.at(ker_index).data().base();
- auto ker_size = _ctx.at(ker_index).data().size();
-
- return [ker_shape, ker_base, ker_size](::arm_compute::ITensor &tensor) {
- const ::internal::nnapi::kernel::Reader<float> from{ker_shape, ker_base, ker_size};
- ::internal::arm_compute::kernel::View<float> into{&tensor};
-
- ::nnfw::util::kernel::iterate(ker_shape)
- << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(nth, ch, row, col);
- into.at(nth, ch, row, col) = value;
- };
- };
-}
-
-Initializer InitializerGenerator::generateWeight(const graph::operation::FullyConnected::Node &node)
-{
- const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
-
- const auto num_output = _ctx.at(weight_index).shape().dim(0);
- auto weight_base = _ctx.at(weight_index).data().base();
- auto weight_size = _ctx.at(weight_index).data().size();
-
- // NOTE We assume that input is a feature map
- // TODO Remove this restriction!
- const auto ifm_shape = _ctx.at(input_index).shape().asFeature();
-
- return [num_output, ifm_shape, weight_base, weight_size](::arm_compute::ITensor &tensor) {
- const ::nnfw::util::kernel::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H, ifm_shape.W};
- const ::internal::nnapi::kernel::Reader<float> from{ker_shape, weight_base, weight_size};
-
- ::nnfw::util::kernel::iterate(ker_shape)
- << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(nth, ch, row, col);
-
- uint32_t offset = 0;
-
- // ARM Compute Library uses 'NCHW' ordering
- offset += nth * ifm_shape.C * ifm_shape.H * ifm_shape.W;
- offset += ch * ifm_shape.H * ifm_shape.W;
- offset += row * ifm_shape.W;
- offset += col;
-
- const ::arm_compute::Coordinates coordinate{offset};
-
- auto into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate));
-
- *into = value;
- };
- };
-}
-
-Initializer InitializerGenerator::generateBias(const graph::operation::Conv2D::Implicit::Node &node)
-{
- // TODO Refactor so we can reuse the common code
-
- const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)};
-
- auto bias_base = _ctx.at(bias_index).data().base();
- const auto bias_size = _ctx.at(bias_index).shape().asVector();
-
- return [bias_base, bias_size](::arm_compute::ITensor &tensor) {
- for (int32_t n = 0; n < bias_size; ++n)
- {
- const ::arm_compute::Coordinates coordinate{n};
-
- float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate));
-
- const float *from = reinterpret_cast<const float *>(bias_base) + n;
- const auto value = *from;
-
- *into = value;
- }
- };
-}
-
-Initializer InitializerGenerator::generateBias(const graph::operation::FullyConnected::Node &node)
-{
- const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)};
-
- auto bias_base = _ctx.at(bias_index).data().base();
- const auto bias_size = _ctx.at(bias_index).shape().asVector();
-
- return [bias_base, bias_size](::arm_compute::ITensor &tensor) {
- for (int32_t n = 0; n < bias_size; ++n)
- {
- const ::arm_compute::Coordinates coordinate{n};
-
- float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate));
-
- const float *from = reinterpret_cast<const float *>(bias_base) + n;
- const auto value = *from;
-
- *into = value;
- }
- };
-}
-
-} // namespace acl_cl
-} // namespace backend
-} // namespace neurun
diff --git a/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.h b/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.h
deleted file mode 100644
index 78b7efb5e..000000000
--- a/runtimes/neurun/src/backend/acl_cl/InitializerGenerator.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 __NEURUN_BACKEND_ACL_CL_INITIALIZER_GENERATOR_H__
-#define __NEURUN_BACKEND_ACL_CL_INITIALIZER_GENERATOR_H__
-
-#include "backend/IInitializerGenerator.h"
-
-#include "graph/operand/Set.h"
-
-namespace neurun
-{
-namespace backend
-{
-namespace acl_cl
-{
-
-class InitializerGenerator : public IInitializerGenerator
-{
-public:
- InitializerGenerator(const neurun::graph::operand::Set &ctx);
-
- Initializer generateWeight(const graph::operation::Conv2D::Implicit::Node &node) override;
- Initializer generateWeight(const graph::operation::FullyConnected::Node &node) override;
-
- Initializer generateBias(const graph::operation::Conv2D::Implicit::Node &node) override;
- Initializer generateBias(const graph::operation::FullyConnected::Node &node) override;
-
-private:
- const neurun::graph::operand::Set &_ctx;
-};
-
-} // namespace acl_cl
-} // namespace backend
-} // namespace neurun
-
-#endif // __NEURUN_BACKEND_ACL_CL_INITIALIZER_GENERATOR_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/PluginClassesAllocator.cc b/runtimes/neurun/src/backend/acl_cl/PluginClassesAllocator.cc
new file mode 100644
index 000000000..f33e71d33
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/PluginClassesAllocator.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 <memory>
+#include "TensorBuilder.h"
+#include "StageGenerator.h"
+#include "Config.h"
+#include "util/logging.h"
+
+extern "C" {
+neurun::backend::acl_cl::TensorBuilder *allocate_TensorBuilder()
+{
+ VERBOSE(allocate_TensorBuilder) << "loaded from acl_cl\n";
+ return new neurun::backend::acl_cl::TensorBuilder;
+}
+
+neurun::backend::acl_cl::StageGenerator *allocate_StageGenerator(
+ const neurun::model::operand::Set &operand_ctx,
+ const std::shared_ptr<neurun::backend::acl_cl::TensorBuilder> &tensor_builder)
+{
+ VERBOSE(allocate_StageGenerator) << "loaded from acl_cl\n";
+ return new neurun::backend::acl_cl::StageGenerator(operand_ctx, tensor_builder);
+}
+
+neurun::backend::acl_cl::Config *allocate_Config()
+{
+ VERBOSE(allocate_Config) << "loaded from acl_cl\n";
+ return new neurun::backend::acl_cl::Config;
+}
+}
diff --git a/runtimes/neurun/src/backend/acl_cl/StageGenerator.cc b/runtimes/neurun/src/backend/acl_cl/StageGenerator.cc
index c63698fd8..89bbd7bd2 100644
--- a/runtimes/neurun/src/backend/acl_cl/StageGenerator.cc
+++ b/runtimes/neurun/src/backend/acl_cl/StageGenerator.cc
@@ -16,6 +16,8 @@
#include "backend/acl_cl/StageGenerator.h"
+#include "kernel/acl_cl/CLFunction.h"
+
#include <arm_compute/runtime/CL/functions/CLConvolutionLayer.h>
#include <arm_compute/runtime/CL/functions/CLPoolingLayer.h>
#include <arm_compute/runtime/CL/functions/CLActivationLayer.h>
@@ -25,20 +27,27 @@
#include "kernel/acl_cl/ConcatLayer.h"
-#include "internal/Padding.h"
+#include "util/Padding.h"
-#include "graph/operand/Index.h"
+#include "model/operand/Index.h"
-#include "logging.h"
+#include "util/logging.h"
#include "NeuralNetworks.h"
-#include "support/nnapi/Utils.h"
+#include "util/Utils.h"
template <typename T> std::unique_ptr<T> make_layer(void) { return std::unique_ptr<T>{new T}; }
-::arm_compute::PadStrideInfo asPadStringInfo(const ::internal::Padding &padding,
- const ::internal::Stride &stride)
+std::unique_ptr<::neurun::kernel::acl_cl::CLFunction>
+make_cl_function(std::unique_ptr<::arm_compute::IFunction> &&layer)
+{
+ return std::unique_ptr<::neurun::kernel::acl_cl::CLFunction>(
+ new ::neurun::kernel::acl_cl::CLFunction(std::move(layer)));
+}
+
+::arm_compute::PadStrideInfo asPadStringInfo(const neurun::util::Padding &padding,
+ const neurun::util::Stride &stride)
{
return ::arm_compute::PadStrideInfo{stride.horizontal,
stride.vertical,
@@ -86,7 +95,9 @@ void ActivationBuilder::appendReLU(::arm_compute::ICLTensor *ifm_alloc)
fn->configure(ifm_alloc, nullptr, act_info);
- _builder.append(std::move(fn));
+ auto acl_fn = make_cl_function(std::move(fn));
+
+ _builder.append(std::move(acl_fn));
}
void ActivationBuilder::append(FuseCode code, ::arm_compute::ICLTensor *ifm_alloc)
@@ -113,25 +124,27 @@ void ActivationBuilder::append(FuseCode code, ::arm_compute::ICLTensor *ifm_allo
//
// StageGenerator
//
-StageGenerator::StageGenerator(const neurun::graph::operand::Set &ctx,
+StageGenerator::StageGenerator(const neurun::model::operand::Set &ctx,
const std::shared_ptr<TensorBuilder> &tensor_builder)
: _ctx(ctx), _tensor_builder(tensor_builder)
{
// DO NOTHING
}
-Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &node)
+void StageGenerator::visit(const model::operation::Conv2DNode &node)
{
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
- const ::neurun::graph::operand::Index ker_index{node.getInputs().at(1)};
- const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)};
+ using model::operation::Conv2DNode;
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(Conv2DNode::Input::INPUT)};
+ const auto ker_index{node.getInputs().at(Conv2DNode::Input::KERNEL)};
+ const auto bias_index{node.getInputs().at(Conv2DNode::Input::BIAS)};
- const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index};
- const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index};
+ const auto vstride_index{node.param().vstride_index};
+ const auto hstride_index{node.param().hstride_index};
- const ::neurun::graph::operand::Index padding_index{node.param().padding_index};
- const ::neurun::graph::operand::Index activation_index{node.param().activation_index};
+ const auto padding_index{node.param().padding_index};
+ const auto activation_index{node.param().activation_index};
const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
@@ -143,7 +156,7 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n
assert((ANEURALNETWORKS_PADDING_SAME == padding_type) ||
(ANEURALNETWORKS_PADDING_VALID == padding_type));
- ::internal::Stride stride;
+ neurun::util::Stride stride;
stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>();
stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>();
@@ -151,64 +164,67 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n
// Construct operation parameters
struct Param
{
- int ofm_index;
- int ifm_index;
- int ker_index;
- int bias_index;
+ model::operand::Index ofm_index;
+ model::operand::Index ifm_index;
+ model::operand::Index ker_index;
+ model::operand::Index bias_index;
- ::internal::Padding padding;
- ::internal::Stride stride;
+ neurun::util::Padding padding;
+ neurun::util::Stride stride;
FuseCode activation;
};
Param param;
- param.ofm_index = ofm_index.asInt();
- param.ifm_index = ifm_index.asInt();
- param.ker_index = ker_index.asInt();
- param.bias_index = bias_index.asInt();
+ param.ofm_index = ofm_index;
+ param.ifm_index = ifm_index;
+ param.ker_index = ker_index;
+ param.bias_index = bias_index;
param.stride = stride;
param.padding =
(padding_type == ANEURALNETWORKS_PADDING_SAME)
- ? ::internal::same_padding(ifm_shape, ofm_shape, stride, ker_shape.W, ker_shape.H)
- : ::internal::valid_padding();
+ ? neurun::util::same_padding(ifm_shape, ofm_shape, stride, ker_shape.W, ker_shape.H)
+ : neurun::util::valid_padding();
param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get();
- auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get();
- auto ker_alloc = tensors->at(::neurun::graph::operand::Index{param.ker_index}).get();
- auto bias_alloc = tensors->at(::neurun::graph::operand::Index{param.bias_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto ofm_alloc = tensors->at(param.ofm_index).get();
+ auto ifm_alloc = tensors->at(param.ifm_index).get();
+ auto ker_alloc = tensors->at(param.ker_index).get();
+ auto bias_alloc = tensors->at(param.bias_index).get();
const auto conv_info = asPadStringInfo(param.padding, param.stride);
std::unique_ptr<::arm_compute::CLConvolutionLayer> fn{new ::arm_compute::CLConvolutionLayer};
- fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info);
+ fn->configure(ifm_alloc->handle(), ker_alloc->handle(), bias_alloc->handle(),
+ ofm_alloc->handle(), conv_info);
- builder.append(std::move(fn));
+ auto acl_fn = make_cl_function(std::move(fn));
- ActivationBuilder{builder}.append(param.activation, ofm_alloc);
- };
+ builder.append(std::move(acl_fn));
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc->handle());
+ });
}
-Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node &node)
+void StageGenerator::visit(const model::operation::MaxPool2DNode &node)
{
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(model::operation::MaxPool2DNode::Input::INPUT)};
- const ::neurun::graph::operand::Index kh_index{node.param().kh_index};
- const ::neurun::graph::operand::Index kw_index{node.param().kw_index};
+ const auto kh_index{node.param().kh_index};
+ const auto kw_index{node.param().kw_index};
- const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index};
- const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index};
+ const auto vstride_index{node.param().vstride_index};
+ const auto hstride_index{node.param().hstride_index};
- const ::neurun::graph::operand::Index padding_index{node.param().padding_index};
+ const auto padding_index{node.param().padding_index};
const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
@@ -225,22 +241,22 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node
// Construct operation parameters
struct Param
{
- int ofm_index;
- int ifm_index;
+ model::operand::Index ofm_index;
+ model::operand::Index ifm_index;
uint32_t kw;
uint32_t kh;
- ::internal::Padding padding;
- ::internal::Stride stride;
+ neurun::util::Padding padding;
+ neurun::util::Stride stride;
// TODO Add 'activation' field
};
Param param;
- param.ofm_index = ofm_index.asInt();
- param.ifm_index = ifm_index.asInt();
+ param.ofm_index = ofm_index;
+ param.ifm_index = ifm_index;
param.kh = kh;
param.kw = kw;
@@ -249,8 +265,8 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node
param.stride.horizontal = hstride;
param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME)
- ? ::internal::same_padding(ifm_shape, ofm_shape, param.stride, kw, kh)
- : ::internal::valid_padding();
+ ? neurun::util::same_padding(ifm_shape, ofm_shape, param.stride, kw, kh)
+ : neurun::util::valid_padding();
VERBOSE(MaxPool2D) << "IFM_H: " << ifm_shape.H << std::endl;
VERBOSE(MaxPool2D) << "IFM_W: " << ifm_shape.W << std::endl;
@@ -267,9 +283,9 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get();
- auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto ofm_alloc = tensors->at(param.ofm_index).get();
+ auto ifm_alloc = tensors->at(param.ifm_index).get();
::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::MAX,
::arm_compute::Size2D{param.kw, param.kh},
@@ -277,24 +293,26 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node
std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer};
- fn->configure(ifm_alloc, ofm_alloc, info);
+ fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info);
- builder.append(std::move(fn));
- };
+ auto acl_fn = make_cl_function(std::move(fn));
+
+ builder.append((std::move(acl_fn)));
+ });
}
-Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node &node)
+void StageGenerator::visit(const model::operation::AvgPool2DNode &node)
{
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(model::operation::AvgPool2DNode::Input::INPUT)};
- const ::neurun::graph::operand::Index kh_index{node.param().kh_index};
- const ::neurun::graph::operand::Index kw_index{node.param().kw_index};
+ const auto kh_index{node.param().kh_index};
+ const auto kw_index{node.param().kw_index};
- const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index};
- const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index};
+ const auto vstride_index{node.param().vstride_index};
+ const auto hstride_index{node.param().hstride_index};
- const ::neurun::graph::operand::Index padding_index{node.param().padding_index};
+ const auto padding_index{node.param().padding_index};
const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
@@ -314,22 +332,22 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node
// Construct operation parameters
struct Param
{
- int ofm_index;
- int ifm_index;
+ model::operand::Index ofm_index;
+ model::operand::Index ifm_index;
uint32_t kw;
uint32_t kh;
- ::internal::Padding padding;
- ::internal::Stride stride;
+ neurun::util::Padding padding;
+ neurun::util::Stride stride;
// TODO Add 'activation' field
};
Param param;
- param.ofm_index = ofm_index.asInt();
- param.ifm_index = ifm_index.asInt();
+ param.ofm_index = ofm_index;
+ param.ifm_index = ifm_index;
param.kh = kh;
param.kw = kw;
@@ -338,8 +356,8 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node
param.stride.horizontal = hstride;
param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME)
- ? ::internal::same_padding(ifm_shape, ofm_shape, param.stride, kw, kh)
- : ::internal::valid_padding();
+ ? neurun::util::same_padding(ifm_shape, ofm_shape, param.stride, kw, kh)
+ : neurun::util::valid_padding();
VERBOSE(AvgPool2D) << "IFM_H: " << ifm_shape.H << std::endl;
VERBOSE(AvgPool2D) << "IFM_W: " << ifm_shape.W << std::endl;
@@ -349,7 +367,7 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node
VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl;
VERBOSE(AvgPool2D) << "STRIDE_H: " << vstride << std::endl;
VERBOSE(AvgPool2D) << "STRIDE_W: " << hstride << std::endl;
- VERBOSE(AvgPool2D) << "PAD: " << ::nnfw::support::nnapi::to_string(padding_type) << std::endl;
+ VERBOSE(AvgPool2D) << "PAD: " << neurun::util::to_string(padding_type) << std::endl;
VERBOSE(AvgPool2D) << "PAD(T): " << param.padding.top << std::endl;
VERBOSE(AvgPool2D) << "PAD(B): " << param.padding.bottom << std::endl;
VERBOSE(AvgPool2D) << "PAD(L): " << param.padding.left << std::endl;
@@ -357,9 +375,9 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get();
- auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto ofm_alloc = tensors->at(param.ofm_index).get();
+ auto ifm_alloc = tensors->at(param.ifm_index).get();
::arm_compute::PoolingLayerInfo info{
::arm_compute::PoolingType::AVG, ::arm_compute::Size2D{param.kw, param.kh},
@@ -367,170 +385,207 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node
std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer};
- fn->configure(ifm_alloc, ofm_alloc, info);
+ fn->configure(ifm_alloc->handle(), ofm_alloc->handle(), info);
- builder.append(std::move(fn));
- };
+ auto acl_fn = make_cl_function(std::move(fn));
+
+ builder.append((std::move(acl_fn)));
+ });
}
-Stage StageGenerator::generate(const graph::operation::Concat::Node &node)
+void StageGenerator::visit(const model::operation::ConcatNode &node)
{
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index axis_index{node.param().axis_index};
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto axis_index{node.param().axis_index};
struct Param
{
- int32_t output_index;
- std::vector<int32_t> input_indexes;
+ model::operand::Index output_index;
+ std::vector<model::operand::Index> input_indexes;
int32_t axis;
};
Param param;
- param.output_index = ofm_index.asInt();
+ param.output_index = ofm_index;
for (const auto &e : node.getInputs())
{
- param.input_indexes.emplace_back(e.asInt());
+ param.input_indexes.emplace_back(e);
}
param.axis = _ctx.at(axis_index).asScalar<int32_t>();
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ // If tensor allocator allocate as subtensor
+ bool canEliminate = true;
+ for (auto ifm_ind : param.input_indexes)
+ {
+ if (!tensors->isSubTensorOf(param.output_index, ifm_ind))
+ {
+ canEliminate = false;
+ break;
+ }
+ }
+ if (canEliminate)
+ {
+ // If concat eliminated, return with nothing to do
+ return;
+ }
+
+ auto output_alloc = tensors->at(param.output_index).get();
- std::vector<::arm_compute::ICLTensor *> input_allocs;
+ std::vector<::neurun::backend::acl_cl::operand::ICLTensor *> input_allocs;
for (auto ifm_ind : param.input_indexes)
{
- input_allocs.emplace_back(tensors->at(::neurun::graph::operand::Index{ifm_ind}).get());
+ input_allocs.emplace_back(
+ dynamic_cast<::neurun::backend::acl_cl::operand::CLTensor *>(tensors->at(ifm_ind).get()));
}
std::unique_ptr<::neurun::kernel::acl_cl::ConcatLayer> fn{
new ::neurun::kernel::acl_cl::ConcatLayer};
- fn->configure(input_allocs, param.axis, output_alloc);
+ fn->configure(input_allocs, param.axis,
+ dynamic_cast<::neurun::backend::acl_cl::operand::CLTensor *>(output_alloc));
- builder.append(std::move(fn));
- };
+ auto acl_fn = make_cl_function(std::move(fn));
+
+ builder.append(std::move(acl_fn));
+ });
}
-Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &node)
+void StageGenerator::visit(const model::operation::FullyConnectedNode &node)
{
- const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
- const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)};
- const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)};
- const ::neurun::graph::operand::Index activation_index{node.param().activation_index};
+ using model::operation::FullyConnectedNode;
+
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(FullyConnectedNode::Input::INPUT)};
+ const auto weight_index{node.getInputs().at(FullyConnectedNode::Input::WEIGHT)};
+ const auto bias_index{node.getInputs().at(FullyConnectedNode::Input::BIAS)};
+ const auto activation_index{node.param().activation_index};
// Construct operation parameters
struct Param
{
- int output_index;
+ model::operand::Index output_index;
- int input_index;
- int weight_index;
- int bias_index;
+ model::operand::Index input_index;
+ model::operand::Index weight_index;
+ model::operand::Index bias_index;
FuseCode activation;
};
Param param;
- param.output_index = output_index.asInt();
- param.input_index = input_index.asInt();
- param.weight_index = weight_index.asInt();
- param.bias_index = bias_index.asInt();
+ param.output_index = output_index;
+ param.input_index = input_index;
+ param.weight_index = weight_index;
+ param.bias_index = bias_index;
param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get();
- auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get();
- auto weight_alloc = tensors->at(::neurun::graph::operand::Index{param.weight_index}).get();
- auto bias_alloc = tensors->at(::neurun::graph::operand::Index{param.bias_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto output_alloc = tensors->at(param.output_index).get();
+ auto input_alloc = tensors->at(param.input_index).get();
+ auto weight_alloc = tensors->at(param.weight_index).get();
+ auto bias_alloc = tensors->at(param.bias_index).get();
auto fn = make_layer<::arm_compute::CLFullyConnectedLayer>();
- fn->configure(input_alloc, weight_alloc, bias_alloc, output_alloc);
+ fn->configure(input_alloc->handle(), weight_alloc->handle(), bias_alloc->handle(),
+ output_alloc->handle());
- builder.append(std::move(fn));
+ auto acl_fn = make_cl_function(std::move(fn));
- ActivationBuilder{builder}.append(param.activation, output_alloc);
- };
+ builder.append(std::move(acl_fn));
+
+ ActivationBuilder{builder}.append(param.activation, output_alloc->handle());
+ });
}
-Stage StageGenerator::generate(const graph::operation::Reshape::Node &node)
+void StageGenerator::visit(const model::operation::ReshapeNode &node)
{
- const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(model::operation::ReshapeNode::Input::INPUT)};
struct Param
{
- int output_index;
- int input_index;
+ model::operand::Index output_index;
+ model::operand::Index input_index;
};
Param param;
- param.output_index = output_index.asInt();
- param.input_index = input_index.asInt();
+ param.output_index = output_index;
+ param.input_index = input_index;
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get();
- auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto output_alloc = tensors->at(param.output_index).get();
+ auto input_alloc = tensors->at(param.input_index).get();
auto fn = make_layer<::arm_compute::CLReshapeLayer>();
- fn->configure(input_alloc, output_alloc);
+ fn->configure(input_alloc->handle(), output_alloc->handle());
- builder.append(std::move(fn));
- };
+ auto acl_fn = make_cl_function(std::move(fn));
+
+ builder.append(std::move(acl_fn));
+ });
}
-Stage StageGenerator::generate(const graph::operation::Softmax::Node &node)
+void StageGenerator::visit(const model::operation::SoftmaxNode &node)
{
- const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
- const ::neurun::graph::operand::Index scale_index{node.param().scale_index};
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(model::operation::SoftmaxNode::Input::INPUT)};
+ const auto scale_index{node.param().scale_index};
assert(_ctx.at(scale_index).shape().rank() == 0);
struct Param
{
- int output_index;
- int input_index;
+ model::operand::Index output_index;
+ model::operand::Index input_index;
float scale;
};
Param param;
- param.output_index = output_index.asInt();
- param.input_index = input_index.asInt();
+ param.output_index = output_index;
+ param.input_index = input_index;
param.scale = _ctx.at(scale_index).asScalar<float>();
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get();
- auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto output_alloc = tensors->at(param.output_index).get();
+ auto input_alloc = tensors->at(param.input_index).get();
auto fn = make_layer<::arm_compute::CLSoftmaxLayer>();
- fn->configure(input_alloc, output_alloc, param.scale);
+ fn->configure(input_alloc->handle(), output_alloc->handle(), param.scale);
- builder.append(std::move(fn));
- };
+ auto acl_fn = make_cl_function(std::move(fn));
+
+ builder.append(std::move(acl_fn));
+ });
}
-Stage StageGenerator::generate(const graph::operation::NOP::Node & /* node */)
+void StageGenerator::visit(const model::operation::PermuteNode & /* node */)
{
- // DO NOTHING
- return nullptr;
+ throw "Unsupported";
+}
+
+void StageGenerator::visit(const model::operation::AddNode &)
+{
+ VERBOSE(Add) << "generate CPU Add" << std::endl;
+
+ throw std::runtime_error("NYI");
}
} // namespace acl_cl
diff --git a/runtimes/neurun/src/backend/acl_cl/StageGenerator.h b/runtimes/neurun/src/backend/acl_cl/StageGenerator.h
index 921604649..1dac2592b 100644
--- a/runtimes/neurun/src/backend/acl_cl/StageGenerator.h
+++ b/runtimes/neurun/src/backend/acl_cl/StageGenerator.h
@@ -17,9 +17,9 @@
#ifndef __NEURUN_BACKEND_ACL_CL_STAGE_GENERATOR_H__
#define __NEURUN_BACKEND_ACL_CL_STAGE_GENERATOR_H__
-#include "backend/IStageGenerator.h"
+#include "backend/interface/IStageGenerator.h"
-#include "graph/operand/Set.h"
+#include "model/operand/Set.h"
#include "backend/acl_cl/TensorBuilder.h"
namespace neurun
@@ -32,22 +32,18 @@ namespace acl_cl
class StageGenerator : public IStageGenerator
{
public:
- StageGenerator(const neurun::graph::operand::Set &ctx,
+ StageGenerator(const neurun::model::operand::Set &ctx,
const std::shared_ptr<TensorBuilder> &tensor_builder);
virtual std::shared_ptr<ITensorBuilder> tensor_builder() override { return _tensor_builder; }
- virtual Stage generate(const graph::operation::Conv2D::Implicit::Node &node) override;
- virtual Stage generate(const graph::operation::MaxPool2D::Implicit::Node &node) override;
- virtual Stage generate(const graph::operation::AvgPool2D::Implicit::Node &node) override;
- virtual Stage generate(const graph::operation::Concat::Node &node) override;
- virtual Stage generate(const graph::operation::FullyConnected::Node &node) override;
- virtual Stage generate(const graph::operation::Reshape::Node &node) override;
- virtual Stage generate(const graph::operation::Softmax::Node &node) override;
- virtual Stage generate(const graph::operation::NOP::Node &node) override;
+#define OP(InternalName, IsNnApi, NnApiName) \
+ virtual void visit(const model::operation::InternalName &) override;
+#include "model/operation/Op.lst"
+#undef OP
private:
- const neurun::graph::operand::Set &_ctx;
+ const neurun::model::operand::Set &_ctx;
std::shared_ptr<TensorBuilder> _tensor_builder;
};
diff --git a/runtimes/neurun/src/backend/acl_cl/Swizzle.h b/runtimes/neurun/src/backend/acl_cl/Swizzle.h
new file mode 100644
index 000000000..838e57162
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/Swizzle.h
@@ -0,0 +1,95 @@
+/*
+ * 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 __NEURUN_BACKEND_ACL_CL_SWIZZLE_H__
+#define __NEURUN_BACKEND_ACL_CL_SWIZZLE_H__
+
+#include <cassert>
+
+namespace neurun
+{
+namespace backend
+{
+namespace acl_cl
+{
+
+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 T/F Lite / NNAPI axis (based on ...NHWC) to ARMCompute axis (WHCN...)
+inline ARMComputeAxis ToARMComputeAxis(uint32_t rank, uint32_t axis)
+{
+ assert(rank > axis);
+ const ARMComputeAxis reversed{(rank - axis) - 1};
+
+ if (rank < 4)
+ {
+ return reversed;
+ }
+
+ // DEPTH
+ if (0 == reversed.value())
+ {
+ return ARMComputeAxis{2};
+ }
+ // WIDTH
+ if (1 == reversed.value())
+ {
+ return ARMComputeAxis{0};
+ }
+ // HEIGHT
+ if (2 == reversed.value())
+ {
+ return ARMComputeAxis{1};
+ }
+
+ // ELSE
+ return reversed;
+}
+
+template <typename T> inline T ReorderBits(T in, size_t numOfBits)
+{
+ assert(numOfBits > 0);
+ T out = 0;
+ for (int32_t i = numOfBits - 1; i >= 0; --i)
+ {
+ const uint32_t toShift = numOfBits - ToARMComputeAxis(numOfBits, i).value() - 1;
+ out += ((in & 1) << toShift);
+ in >>= 1;
+ }
+ return out;
+}
+
+} // namespace acl_cl
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ACL_CL_SWIZZLE_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/TensorBuilder.cc b/runtimes/neurun/src/backend/acl_cl/TensorBuilder.cc
index 05943c26a..b5c038200 100644
--- a/runtimes/neurun/src/backend/acl_cl/TensorBuilder.cc
+++ b/runtimes/neurun/src/backend/acl_cl/TensorBuilder.cc
@@ -17,8 +17,12 @@
#include "backend/acl_cl/TensorBuilder.h"
#include <cassert>
+#include <stack>
#include "operand/Object.h"
+#include "Convert.h"
+
+#include "util/logging.h"
namespace neurun
{
@@ -32,34 +36,124 @@ TensorBuilder::TensorBuilder()
// DO NOTHING
}
-void TensorBuilder::mark(const ::neurun::graph::operand::Index &ind)
+void TensorBuilder::registerTensorInfo(const model::operand::Index &ind,
+ const compiler::TensorInfo &info)
+{
+ assert(_tensors.size() == 0);
+
+ _tensor_info_map.insert({ind, info});
+}
+
+void TensorBuilder::registerSubTensorInfo(const model::operand::Index &ind,
+ const compiler::SubTensorInfo &info)
{
assert(_tensors.size() == 0);
- _inds.insert(ind);
+ _subtensor_info_map.insert({ind, info});
+}
+
+void TensorBuilder::notifyFirstUse(const model::operand::Index &)
+{
+ // DO NOTHING
+}
+
+void TensorBuilder::notifyLastUse(const model::operand::Index &)
+{
+ // DO NOTHING
}
-void TensorBuilder::prepare(codegen::Plan &plan,
- const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx)
+void TensorBuilder::prepare(void)
{
assert(_tensors.size() == 0);
// TODO Handle SubTensor(subsumption)
// Currently this TensorBuilder does not have subsumption info yet
+ // Allocated subtensor will be mapped to _subtensors instead of _tensors
+ assert(_subtensors.size() == 0);
- for (auto ind_int : _inds)
+ for (auto &entry : _tensor_info_map)
{
- ::neurun::graph::operand::Index ind{ind_int};
- auto tensor = std::make_shared<::arm_compute::CLTensor>();
- tensor->allocator()->init(tensor_info_ctx.at(ind.asInt()));
- plan.operands().set(ind, std::make_shared<operand::Object>(tensor));
+ auto ind = entry.first;
+ const auto &info = entry.second;
+ auto tensor = std::make_shared<::neurun::backend::acl_cl::operand::CLTensor>(info);
_tensors[ind] = tensor;
}
+
+ // 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)
+ for (auto &entry : _subtensor_info_map)
+ {
+ model::operand::Index ind = entry.first;
+
+ std::stack<model::operand::Index> stack;
+ stack.push(ind);
+
+ while (!stack.empty())
+ {
+ const auto current = stack.top();
+ const auto &info = _subtensor_info_map.at(current);
+
+ // Already generated CLSubTensor
+ if (_subtensors.find(current) != _subtensors.end())
+ {
+ stack.pop();
+ continue;
+ }
+
+ auto parent = info.parent();
+ std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor> parent_tensor;
+
+ if (_tensors.find(parent) != _tensors.end())
+ {
+ // Parent is allocated as tensor
+ parent_tensor = _tensors[parent];
+ }
+ else if (_subtensors.find(parent) != _subtensors.end())
+ {
+ // Parent is allocated as subtensor
+ parent_tensor = _subtensors[parent];
+ }
+ else
+ {
+ // Cannot find allocated parent tensor: allocate parent first
+ assert(_subtensor_info_map.find(parent) != _subtensor_info_map.end());
+ stack.push(parent);
+ continue;
+ }
+ assert(parent_tensor != nullptr);
+
+ // Child's type should be same with parent
+ assert(info.type().offset() == parent_tensor->info()->quantization_info().offset);
+ assert(info.type().scale() == parent_tensor->info()->quantization_info().scale);
+ assert(asDataType(info.type().type()) == parent_tensor->info()->data_type());
+ auto shape = asTensorShape(info.shape());
+
+ // Only support axis: 3 (channel)
+ ::arm_compute::Coordinates coordinates;
+ coordinates.set_num_dimensions(4);
+ assert(info.offset().h() == 0);
+ assert(info.offset().n() == 0);
+ assert(info.offset().w() == 0);
+ coordinates[2] = info.offset().c();
+ auto tensor = std::make_shared<::neurun::backend::acl_cl::operand::CLSubTensor>(
+ parent_tensor.get(), shape, coordinates, true);
+ _subtensors[current] = tensor;
+ stack.pop();
+ }
+ }
}
void TensorBuilder::allocate(void)
{
- assert(_inds.size() == _tensors.size());
+ assert(_tensor_info_map.size() == _tensors.size());
for (const auto &tensor_entry : _tensors)
{
@@ -68,10 +162,83 @@ void TensorBuilder::allocate(void)
}
}
-std::shared_ptr<::arm_compute::CLTensor>
-TensorBuilder::at(const ::neurun::graph::operand::Index &ind)
+std::shared_ptr<::neurun::backend::operand::ITensor>
+TensorBuilder::tensorAt(const model::operand::Index &ind)
+{
+ if (_tensors.find(ind) != _tensors.end())
+ {
+ return _tensors.at(ind);
+ }
+ else
+ {
+ return _subtensors.at(ind);
+ }
+}
+
+std::shared_ptr<backend::operand::IObject>
+TensorBuilder::wrapTensor(const model::operand::Index &ind)
{
- return _tensors.at(ind);
+ if (_objects.find(ind) != _objects.end())
+ {
+ return _objects.at(ind);
+ }
+ else
+ {
+ if (_tensors.find(ind) != _tensors.end())
+ {
+ return _objects[ind] = std::make_shared<operand::Object>(_tensors.at(ind));
+ }
+ else
+ {
+ return _objects[ind] = std::make_shared<operand::Object>(_subtensors.at(ind));
+ }
+ }
+}
+
+void TensorBuilder::iterate(const IterateFunction &fn)
+{
+ for (auto it : _tensors)
+ {
+ fn(it.first);
+ }
+ for (auto it : _subtensors)
+ {
+ fn(it.first);
+ }
+}
+
+std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor>
+TensorBuilder::at(const ::neurun::model::operand::Index &ind)
+{
+ if (_tensors.find(ind) != _tensors.end())
+ {
+ return _tensors.at(ind);
+ }
+ else
+ {
+ return _subtensors.at(ind);
+ }
+}
+
+bool TensorBuilder::isSubTensorOf(const model::operand::Index &parent,
+ const model::operand::Index &child)
+{
+ if (_subtensor_info_map.find(child) == _subtensor_info_map.end())
+ {
+ return false;
+ }
+
+ if (_subtensors.find(child) == _subtensors.end())
+ {
+ return false;
+ }
+
+ if (_subtensor_info_map.at(child).parent() != parent)
+ {
+ return false;
+ }
+
+ return true;
}
} // namespace acl_cl
diff --git a/runtimes/neurun/src/backend/acl_cl/TensorBuilder.h b/runtimes/neurun/src/backend/acl_cl/TensorBuilder.h
index 0a0f4e9ca..64d81721a 100644
--- a/runtimes/neurun/src/backend/acl_cl/TensorBuilder.h
+++ b/runtimes/neurun/src/backend/acl_cl/TensorBuilder.h
@@ -17,12 +17,12 @@
#ifndef __NEURUN_BACKEND_ACL_CL_TENSOR_BUILDER_H__
#define __NEURUN_BACKEND_ACL_CL_TENSOR_BUILDER_H__
-#include "backend/ITensorBuilder.h"
+#include "backend/interface/ITensorBuilder.h"
+#include "backend/acl_cl/operand/CLTensor.h"
+#include "backend/acl_cl/operand/CLSubTensor.h"
+#include "backend/acl_cl/operand/Object.h"
#include <unordered_map>
-#include <unordered_set>
-
-#include <arm_compute/runtime/CL/CLTensor.h>
namespace neurun
{
@@ -31,23 +31,60 @@ namespace backend
namespace acl_cl
{
-class Plan;
-
class TensorBuilder : public ITensorBuilder
{
public:
TensorBuilder();
- virtual void mark(const ::neurun::graph::operand::Index &ind) override;
- virtual void prepare(codegen::Plan &plan,
- const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx) override;
+ /**
+ * @brief Register tensor information to allocate on ACL-CL backend
+ * @param[in] ind Operand index
+ * @param[in] info Tensor information
+ */
+ virtual void registerTensorInfo(const model::operand::Index &ind,
+ const compiler::TensorInfo &info) override;
+ /**
+ * @brief Register subtensor information to allocate on ACL-CL backend
+ * @param[in] ind Operand index
+ * @param[in] info Tensor information
+ */
+ virtual void registerSubTensorInfo(const model::operand::Index &ind,
+ const compiler::SubTensorInfo &info) override;
+
+ virtual void notifyFirstUse(const model::operand::Index &) override;
+ virtual void notifyLastUse(const model::operand::Index &) override;
+
+ virtual void prepare(void) override;
virtual void allocate(void) override;
- std::shared_ptr<::arm_compute::CLTensor> at(const ::neurun::graph::operand::Index &ind);
+ virtual std::shared_ptr<::neurun::backend::operand::ITensor>
+ tensorAt(const model::operand::Index &ind) override;
+ virtual std::shared_ptr<backend::operand::IObject>
+ wrapTensor(const model::operand::Index &ind) override;
+ virtual void iterate(const IterateFunction &fn) override;
+
+ std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor>
+ at(const ::neurun::model::operand::Index &ind);
+ /**
+ * @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 model::operand::Index &parent, const model::operand::Index &child);
private:
- std::unordered_set<graph::operand::Index> _inds;
- std::unordered_map<graph::operand::Index, std::shared_ptr<::arm_compute::CLTensor>> _tensors;
+ std::unordered_map<model::operand::Index, compiler::TensorInfo> _tensor_info_map;
+ std::unordered_map<model::operand::Index, compiler::SubTensorInfo> _subtensor_info_map;
+ std::unordered_map<model::operand::Index,
+ std::shared_ptr<::neurun::backend::acl_cl::operand::CLTensor>>
+ _tensors;
+ std::unordered_map<model::operand::Index,
+ std::shared_ptr<::neurun::backend::acl_cl::operand::CLSubTensor>>
+ _subtensors;
+ std::unordered_map<model::operand::Index,
+ std::shared_ptr<::neurun::backend::acl_cl::operand::Object>>
+ _objects;
};
} // namespace acl_cl
diff --git a/runtimes/neurun/src/backend/acl_cl/feature/View.h b/runtimes/neurun/src/backend/acl_cl/feature/View.h
deleted file mode 100644
index 12025ce01..000000000
--- a/runtimes/neurun/src/backend/acl_cl/feature/View.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * 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 __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__
-#define __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__
-
-#include "util/feature/Reader.h"
-
-#include <arm_compute/core/ITensor.h>
-
-#include <cassert>
-
-namespace internal
-{
-namespace arm_compute
-{
-namespace feature
-{
-
-template <typename T> class View;
-
-template <> class View<float> final : public nnfw::util::feature::Reader<float>
-{
-public:
- View(::arm_compute::ITensor *tensor) : _tensor{tensor}
- {
- assert(tensor->info()->data_type() == ::arm_compute::DataType::F32);
-
- // TODO Validate whether tensor is a feature map, or not
-
- _shape.C = tensor->info()->dimension(2);
- _shape.H = tensor->info()->dimension(1);
- _shape.W = tensor->info()->dimension(0);
- }
-
-public:
- const ::nnfw::util::feature::Shape &shape(void) const { return _shape; }
-
-public:
- float at(uint32_t ch, uint32_t row, uint32_t col) const override
- {
- const auto offset = feature_index_to_byte_offset(ch, row, col);
-
- float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset);
-
- return *ptr;
- }
- float 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);
-
- float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset);
-
- return *ptr;
- }
-
-public:
- float &at(uint32_t ch, uint32_t row, uint32_t col)
- {
- const auto offset = feature_index_to_byte_offset(ch, row, col);
-
- float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset);
-
- return *ptr;
- }
- float &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);
-
- float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset);
-
- return *ptr;
- }
-
-private:
- size_t feature_index_to_byte_offset(uint32_t ch, uint32_t row, uint32_t col) const
- {
- // ARM Compute uses CHW ordering
- return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row, ch});
- }
- size_t feature_index_to_byte_offset(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const
- {
- // ARM Compute uses CHW ordering
- return _tensor->info()->offset_element_in_bytes(
- ::arm_compute::Coordinates{col, row, ch, batch});
- }
-
-private:
- ::nnfw::util::feature::Shape _shape;
- ::arm_compute::ITensor *_tensor;
-};
-
-} // namespace feature
-} // namespace arm_compute
-} // namespace internal
-
-#endif // __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/kernel/View.h b/runtimes/neurun/src/backend/acl_cl/kernel/View.h
deleted file mode 100644
index aec9a8892..000000000
--- a/runtimes/neurun/src/backend/acl_cl/kernel/View.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 __INTERNAL_ARM_COMPUTE_KERNEL_VIEW_H__
-#define __INTERNAL_ARM_COMPUTE_KERNEL_VIEW_H__
-
-#include "util/kernel/Shape.h"
-#include "util/kernel/Reader.h"
-
-#include <arm_compute/core/ITensor.h>
-
-#include <cassert>
-
-namespace internal
-{
-namespace arm_compute
-{
-namespace kernel
-{
-
-template <typename T> class View;
-
-template <> class View<float> final : public nnfw::util::kernel::Reader<float>
-{
-public:
- View(::arm_compute::ITensor *tensor) : _tensor{tensor}
- {
- assert(tensor->info()->data_type() == ::arm_compute::DataType::F32);
-
- _shape.N = tensor->info()->dimension(3);
- _shape.C = tensor->info()->dimension(2);
- _shape.H = tensor->info()->dimension(1);
- _shape.W = tensor->info()->dimension(0);
- }
-
-public:
- const ::nnfw::util::kernel::Shape &shape(void) const { return _shape; }
-
-public:
- float at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const override
- {
- const auto offset = kernel_index_to_byte_offset(nth, ch, row, col);
-
- float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset);
-
- return *ptr;
- }
-
-public:
- float &at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col)
- {
- const auto offset = kernel_index_to_byte_offset(nth, ch, row, col);
-
- float *ptr = reinterpret_cast<float *>(_tensor->buffer() + offset);
-
- return *ptr;
- }
-
-private:
- size_t kernel_index_to_byte_offset(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const
- {
- return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row, ch, nth});
- }
-
-private:
- ::nnfw::util::kernel::Shape _shape;
- ::arm_compute::ITensor *_tensor;
-};
-
-} // namespace kernel
-} // namespace arm_compute
-} // namespace internal
-
-#endif // __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.cc b/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.cc
new file mode 100644
index 000000000..f64b521dd
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.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 "CLSubTensor.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+CLSubTensor::CLSubTensor(ICLTensor *parent, const arm_compute::TensorShape &tensor_shape,
+ const arm_compute::Coordinates &coords, bool extend_parent)
+ : _cl_sub_tensor(std::make_shared<arm_compute::CLSubTensor>(parent->handle(), tensor_shape,
+ coords, extend_parent))
+{
+ // DO NOTHING
+}
+
+arm_compute::CLSubTensor *CLSubTensor::handle() const { return _cl_sub_tensor.get(); }
+
+arm_compute::CLSubTensor *CLSubTensor::handle() { return _cl_sub_tensor.get(); }
+
+void CLSubTensor::map(bool blocking) { _cl_sub_tensor->map(blocking); }
+
+void CLSubTensor::unmap() { _cl_sub_tensor->unmap(); }
+
+uint8_t *CLSubTensor::doMap(cl::CommandQueue &q, bool blocking)
+{
+ assert(cl_buffer().get() == nullptr);
+ return static_cast<uint8_t *>(q.enqueueMapBuffer(cl_buffer(), blocking ? CL_TRUE : CL_FALSE,
+ CL_MAP_READ | CL_MAP_WRITE, 0,
+ info()->total_size()));
+}
+
+void CLSubTensor::doUnmap(cl::CommandQueue &q)
+{
+ assert(cl_buffer().get() == nullptr);
+ q.enqueueUnmapMemObject(cl_buffer(), buffer());
+}
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace neurun
diff --git a/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.h b/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.h
new file mode 100644
index 000000000..cef78c196
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/operand/CLSubTensor.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 __NEURUN_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__
+#define __NEURUN_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__
+
+#include <arm_compute/runtime/CL/CLSubTensor.h>
+#include "ICLTensor.h"
+#include "compiler/SubTensorInfo.h"
+
+namespace neurun
+{
+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, bool extend_parent = false);
+
+public:
+ arm_compute::CLSubTensor *handle() const override;
+ arm_compute::CLSubTensor *handle() override;
+
+public:
+ void map(bool blocking = true);
+ void unmap();
+
+protected:
+ uint8_t *doMap(cl::CommandQueue &q, bool blocking) override;
+ virtual void doUnmap(cl::CommandQueue &q) override;
+
+private:
+ std::shared_ptr<arm_compute::CLSubTensor> _cl_sub_tensor;
+};
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ACL_CL_OPERAND_CL_SUB_TENSOR_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.cc b/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.cc
new file mode 100644
index 000000000..e7b718df3
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.cc
@@ -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.
+ */
+
+#include <arm_compute/runtime/CL/CLScheduler.h>
+#include <arm_compute/runtime/CL/CLMemory.h>
+#include <arm_compute/runtime/CL/CLMemoryRegion.h>
+#include "CLTensor.h"
+
+#include "backend/acl_cl/Convert.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+CLTensor::CLTensor(const compiler::TensorInfo &info)
+ : _cl_tensor(std::make_shared<arm_compute::CLTensor>())
+{
+ auto acl_cl_info = asTensorInfo(info.shape(), info.typeInfo());
+ allocator()->init(acl_cl_info);
+}
+
+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(); }
+
+uint8_t *CLTensor::doMap(cl::CommandQueue &q, bool blocking)
+{
+ return allocator()->map(q, blocking);
+}
+
+void CLTensor::doUnmap(cl::CommandQueue &q) { allocator()->unmap(q, buffer()); }
+
+// handle() is Deprecated on acl v18.11
+// TODO Update this
+#if 0
+void CLTensor::setBuffer(void *host_ptr)
+{
+ // create empty MemoryRegion: just context. Since flag isn't used here, no matter which flag to
+ // pass
+ auto memory = arm_compute::CLMemory(std::make_shared<arm_compute::CLBufferMemoryRegion>(
+ arm_compute::CLScheduler::get().context(), CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, 0));
+
+ // set buffer
+ auto mem = reinterpret_cast<cl::Buffer *>(memory.region()->handle());
+ *mem = cl::Buffer(arm_compute::CLScheduler::get().context(),
+ CL_MEM_USE_HOST_PTR | CL_MEM_READ_WRITE, info()->total_size(), host_ptr);
+ // set correct buffer size
+ memory.region()->set_size(info()->total_size());
+ // import memory
+ allocator()->import_memory(memory);
+}
+#endif
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace neurun
diff --git a/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.h b/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.h
new file mode 100644
index 000000000..31c96e201
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/operand/CLTensor.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 __NEURUN_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__
+#define __NEURUN_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__
+
+#include <arm_compute/core/TensorInfo.h>
+#include <arm_compute/runtime/CL/CLTensor.h>
+#include <arm_compute/runtime/CL/CLScheduler.h>
+#include "arm_compute/runtime/CL/CLTensorAllocator.h"
+#include "ICLTensor.h"
+#include "compiler/TensorInfo.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+class CLTensor : public ICLTensor
+{
+public:
+ CLTensor() = delete;
+
+public:
+ CLTensor(const compiler::TensorInfo &info);
+
+public:
+ arm_compute::CLTensor *handle() const override;
+ arm_compute::CLTensor *handle() override;
+
+public:
+ arm_compute::CLTensorAllocator *allocator();
+ void map(bool blocking = true);
+ void unmap();
+ void setBuffer(void *host_ptr);
+
+protected:
+ uint8_t *doMap(cl::CommandQueue &q, bool blocking) override;
+ void doUnmap(cl::CommandQueue &q) override;
+
+private:
+ std::shared_ptr<arm_compute::CLTensor> _cl_tensor;
+};
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ACL_CL_OPERAND_CL_TENSOR_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.cc b/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.cc
new file mode 100644
index 000000000..23d723de4
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.cc
@@ -0,0 +1,48 @@
+#include "ICLTensor.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+size_t ICLTensor::total_size() const { return info()->total_size(); }
+
+size_t ICLTensor::dimension(size_t index) const { return info()->dimension(index); }
+
+size_t ICLTensor::num_dimensions() const { return info()->num_dimensions(); }
+
+size_t ICLTensor::calcOffset(const neurun::util::feature::Coordinate4D &coords)
+{
+ int32_t N = coords.n();
+ int32_t C = coords.c();
+ int32_t H = coords.h();
+ int32_t W = coords.w();
+
+ ::arm_compute::Coordinates coordinates{W, H, C, N};
+ return info()->offset_element_in_bytes(coordinates);
+}
+
+arm_compute::DataType ICLTensor::data_type() const { return info()->data_type(); }
+
+uint8_t *ICLTensor::buffer() const { return handle()->buffer(); }
+
+const cl::Buffer &ICLTensor::cl_buffer() const { return handle()->cl_buffer(); }
+
+arm_compute::ITensorInfo *ICLTensor::info() const { return handle()->info(); }
+
+arm_compute::ITensorInfo *ICLTensor::info() { return handle()->info(); }
+
+void ICLTensor::map(cl::CommandQueue &q, bool blocking) { return handle()->map(q, blocking); }
+
+void ICLTensor::unmap(cl::CommandQueue &q) { return handle()->unmap(q); }
+
+void ICLTensor::clear(cl::CommandQueue &q) { return handle()->clear(q); }
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace neurun
diff --git a/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.h b/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.h
new file mode 100644
index 000000000..226fbf814
--- /dev/null
+++ b/runtimes/neurun/src/backend/acl_cl/operand/ICLTensor.h
@@ -0,0 +1,73 @@
+/*
+ * 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 __NEURUN_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__
+#define __NEURUN_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__
+
+#include <arm_compute/core/ITensorInfo.h>
+#include <arm_compute/core/CL/ICLTensor.h>
+#include "backend/interface/operand/ITensor.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace acl_cl
+{
+namespace operand
+{
+
+class ICLTensor : public ::neurun::backend::operand::ITensor
+{
+public:
+ ICLTensor() = default;
+ ICLTensor(const ICLTensor &) = delete;
+ ICLTensor &operator=(const ICLTensor &) = delete;
+ ICLTensor(ICLTensor &&) = default;
+ ICLTensor &operator=(ICLTensor &&) = default;
+ virtual ~ICLTensor() = default;
+
+public:
+ virtual arm_compute::ICLTensor *handle() = 0;
+ virtual arm_compute::ICLTensor *handle() const = 0;
+
+public:
+ uint8_t *buffer() const override;
+ size_t total_size() const override;
+ size_t dimension(size_t index) const override;
+ size_t num_dimensions() const override;
+ size_t calcOffset(const neurun::util::feature::Coordinate4D &coords) override;
+
+public:
+ arm_compute::DataType data_type() const;
+ const cl::Buffer &cl_buffer() const;
+ arm_compute::ITensorInfo *info() const;
+ arm_compute::ITensorInfo *info();
+ void map(cl::CommandQueue &q, bool blocking = true);
+ void unmap(cl::CommandQueue &q);
+ void clear(cl::CommandQueue &q);
+
+protected:
+ virtual uint8_t *doMap(cl::CommandQueue &q, bool blocking) = 0;
+ virtual void doUnmap(cl::CommandQueue &q) = 0;
+};
+
+} // namespace operand
+} // namespace acl_cl
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ACL_CL_OPERAND_I_CL_TENSOR_H__
diff --git a/runtimes/neurun/src/backend/acl_cl/operand/Object.cc b/runtimes/neurun/src/backend/acl_cl/operand/Object.cc
index 98b96a11a..a84fa2366 100644
--- a/runtimes/neurun/src/backend/acl_cl/operand/Object.cc
+++ b/runtimes/neurun/src/backend/acl_cl/operand/Object.cc
@@ -27,7 +27,8 @@ namespace acl_cl
namespace operand
{
-void Object::access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const
+void Object::access(
+ const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const
{
auto &queue = ::arm_compute::CLScheduler::get().queue();
diff --git a/runtimes/neurun/src/backend/acl_cl/operand/Object.h b/runtimes/neurun/src/backend/acl_cl/operand/Object.h
index da33c0549..4ba22b269 100644
--- a/runtimes/neurun/src/backend/acl_cl/operand/Object.h
+++ b/runtimes/neurun/src/backend/acl_cl/operand/Object.h
@@ -18,9 +18,9 @@
#define __NEURUN_BACKEND_ACL_CL_OPERAND_OBJECT_H__
#include <memory>
-#include <arm_compute/core/CL/ICLTensor.h>
-#include "backend/IObject.h"
+#include "backend/interface/operand/IObject.h"
+#include "backend/acl_cl/operand/ICLTensor.h"
namespace neurun
{
@@ -37,19 +37,21 @@ public:
Object() = default;
public:
- Object(const std::shared_ptr<::arm_compute::ICLTensor> &tensor) : _tensor{tensor}
+ Object(const std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor> &tensor)
+ : _tensor{tensor}
{
// DO NOTHING
}
public:
- ::arm_compute::ICLTensor *ptr(void) const override { return _tensor.get(); }
+ ::neurun::backend::acl_cl::operand::ICLTensor *ptr(void) const override { return _tensor.get(); }
private:
- std::shared_ptr<::arm_compute::ICLTensor> _tensor;
+ std::shared_ptr<::neurun::backend::acl_cl::operand::ICLTensor> _tensor;
public:
- void access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const override;
+ void
+ access(const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const override;
};
} // namespace operand
diff --git a/runtimes/neurun/src/backend/cpu/CMakeLists.txt b/runtimes/neurun/src/backend/cpu/CMakeLists.txt
index 95e9af687..dc4406a65 100644
--- a/runtimes/neurun/src/backend/cpu/CMakeLists.txt
+++ b/runtimes/neurun/src/backend/cpu/CMakeLists.txt
@@ -1,19 +1,18 @@
file(GLOB_RECURSE SOURCES "*.cc")
-add_library(${LIB_NEURUN_BACKEND_CPU} STATIC ${SOURCES})
+add_library(${LIB_NEURUN_BACKEND_CPU} SHARED ${SOURCES})
target_include_directories(${LIB_NEURUN_BACKEND_CPU} PUBLIC ${NNFW_INCLUDE_DIR})
target_include_directories(${LIB_NEURUN_BACKEND_CPU} PUBLIC ${NEURUN_INCLUDE_DIR})
target_include_directories(${LIB_NEURUN_BACKEND_CPU} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow)
-target_link_libraries(${LIB_NEURUN_BACKEND_CPU} arm_compute) # TODO We should not need this
target_link_libraries(${LIB_NEURUN_BACKEND_CPU} tensorflow-lite)
-target_link_libraries(${LIB_NEURUN_BACKEND_CPU} nnfw_util)
-target_link_libraries(${LIB_NEURUN_BACKEND_CPU} nnfw_support_nnapi)
+target_link_libraries(${LIB_NEURUN_BACKEND_CPU} nnfw_lib_misc)
+target_link_libraries(${LIB_NEURUN_BACKEND_CPU} nnfw_lib_cpp14)
target_link_libraries(${LIB_NEURUN_BACKEND_CPU} ${LIB_NEURUN_KERNEL_CPU})
+target_link_libraries(${LIB_NEURUN_BACKEND_CPU} ${LIB_NEURUN})
target_compile_options(${LIB_NEURUN_BACKEND_CPU} PRIVATE -Wall -Wextra -Werror)
-set_target_properties(${LIB_NEURUN_BACKEND_CPU} PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(${LIB_NEURUN_BACKEND_CPU} PROPERTIES OUTPUT_NAME backend_cpu)
install(TARGETS ${LIB_NEURUN_BACKEND_CPU} DESTINATION lib/neurun)
diff --git a/runtimes/neurun/src/backend/cpu/BackendConfig.cc b/runtimes/neurun/src/backend/cpu/Config.cc
index 34fc3491a..001ba9d02 100644
--- a/runtimes/neurun/src/backend/cpu/BackendConfig.cc
+++ b/runtimes/neurun/src/backend/cpu/Config.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "backend/cpu/BackendConfig.h"
+#include "backend/cpu/Config.h"
namespace neurun
{
@@ -23,7 +23,7 @@ namespace backend
namespace cpu
{
-void BackendConfig::initialize()
+void Config::initialize()
{
// DO NOTHING
}
diff --git a/runtimes/neurun/src/backend/cpu/BackendConfig.h b/runtimes/neurun/src/backend/cpu/Config.h
index 109235bb1..ad9ca0ee8 100644
--- a/runtimes/neurun/src/backend/cpu/BackendConfig.h
+++ b/runtimes/neurun/src/backend/cpu/Config.h
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#ifndef __NEURUN_BACKEND_CPU_BACKEND_CONFIG_H__
-#define __NEURUN_BACKEND_CPU_BACKEND_CONFIG_H__
+#ifndef __NEURUN_BACKEND_CPU_CONFIG_H__
+#define __NEURUN_BACKEND_CPU_CONFIG_H__
-#include "backend/IBackendConfig.h"
+#include "backend/interface/IConfig.h"
namespace neurun
{
@@ -26,20 +26,26 @@ namespace backend
namespace cpu
{
-class BackendConfig : public IBackendConfig
+class Config : public IConfig
{
public:
- BackendConfig()
+ Config()
{
// DO NOTHING
}
+ virtual std::string id() override { return "cpu"; }
virtual void initialize() override;
virtual graph::operand::Layout getOperandLayout() { return graph::operand::Layout::NHWC; }
+ virtual bool SupportSubTensorAlloc() override
+ {
+ // NOTE CPU allocator cannot support subtensor allocation yet
+ return false;
+ }
};
} // namespace cpu
} // namespace backend
} // namespace neurun
-#endif // __NEURUN_BACKEND_CPU_BACKEND_CONFIG_H__
+#endif // __NEURUN_BACKEND_CPU_CONFIG_H__
diff --git a/runtimes/neurun/src/backend/cpu/InitializerGenerator.cc b/runtimes/neurun/src/backend/cpu/InitializerGenerator.cc
deleted file mode 100644
index 7b08c7131..000000000
--- a/runtimes/neurun/src/backend/cpu/InitializerGenerator.cc
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * 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 "InitializerGenerator.h"
-
-#include "internal/nnapi/kernel/Reader.h"
-#include "internal/nnapi/kernel/View.h"
-#include "util/kernel/IndexIterator.h"
-
-#include "NeuralNetworks.h"
-
-namespace neurun
-{
-namespace backend
-{
-namespace cpu
-{
-
-InitializerGenerator::InitializerGenerator(const neurun::graph::operand::Set &ctx) : _ctx(ctx)
-{
- // DO NOTHING
-}
-
-Initializer
-InitializerGenerator::generateWeight(const graph::operation::Conv2D::Implicit::Node &node)
-{
- const ::neurun::graph::operand::Index ker_index{node.getInputs().at(1)};
-
- const auto ker_shape = _ctx.at(ker_index).shape().asKernel();
- auto ker_base = _ctx.at(ker_index).data().base();
- auto ker_size = _ctx.at(ker_index).data().size();
-
- return [ker_shape, ker_base, ker_size](::arm_compute::ITensor &tensor) {
- const ::internal::nnapi::kernel::Reader<float> from{ker_shape, ker_base, ker_size};
- ::internal::nnapi::kernel::View<float> into{&tensor};
-
- ::nnfw::util::kernel::iterate(ker_shape)
- << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(nth, ch, row, col);
- into.at(nth, row, col, ch) = value;
- };
- };
-}
-
-Initializer InitializerGenerator::generateWeight(const graph::operation::FullyConnected::Node &node)
-{
- const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
-
- const auto num_output = _ctx.at(weight_index).shape().dim(0);
- auto weight_base = _ctx.at(weight_index).data().base();
- auto weight_size = _ctx.at(weight_index).data().size();
- auto weight_type = _ctx.at(weight_index).typeInfo().type();
-
- // NOTE We assume that input is a feature map
- // TODO Remove this restriction!
- const auto ifm_shape = _ctx.at(input_index).shape().asFeature();
-
- switch (weight_type)
- {
- case ::neurun::graph::operand::DataType::TENSOR_FLOAT32:
- {
- return [num_output, ifm_shape, weight_base, weight_size](::arm_compute::ITensor &tensor) {
- const ::nnfw::util::kernel::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H,
- ifm_shape.W};
- const ::internal::nnapi::kernel::Reader<float> from{ker_shape, weight_base, weight_size};
-
- ::nnfw::util::kernel::iterate(ker_shape)
- << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(nth, ch, row, col);
-
- uint32_t offset = 0;
-
- // NNAPI uses NHWC ordering
- offset += nth * ifm_shape.H * ifm_shape.W * ifm_shape.C;
- offset += row * ifm_shape.W * ifm_shape.C;
- offset += col * ifm_shape.C;
- offset += ch;
-
- const ::arm_compute::Coordinates coordinate{offset};
-
- auto into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate));
-
- *into = value;
- };
- };
- }
- case ::neurun::graph::operand::DataType::TENSOR_QUANT8_ASYMM:
- {
- return [num_output, ifm_shape, weight_base, weight_size](::arm_compute::ITensor &tensor) {
- const ::nnfw::util::kernel::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H,
- ifm_shape.W};
- const ::internal::nnapi::kernel::Reader<uint8_t> from{ker_shape, weight_base, weight_size};
- ::nnfw::util::kernel::iterate(ker_shape)
- << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(nth, ch, row, col);
- uint32_t offset = 0;
-
- // NNAPI uses NHWC ordering
- offset += nth * ifm_shape.H * ifm_shape.W * ifm_shape.C;
- offset += row * ifm_shape.W * ifm_shape.C;
- offset += col * ifm_shape.C;
- offset += ch;
-
- const ::arm_compute::Coordinates coordinate{offset};
-
- auto into = reinterpret_cast<uint8_t *>(tensor.ptr_to_element(coordinate));
-
- *into = value;
- };
- };
- }
- default:
- {
- throw std::runtime_error("Not supported weight type");
- }
- }
-}
-
-Initializer InitializerGenerator::generateBias(const graph::operation::Conv2D::Implicit::Node &node)
-{
- // TODO Refactor so we can reuse the common code
-
- const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)};
-
- auto bias_base = _ctx.at(bias_index).data().base();
- const auto bias_size = _ctx.at(bias_index).shape().asVector();
-
- return [bias_base, bias_size](::arm_compute::ITensor &tensor) {
- for (int32_t n = 0; n < bias_size; ++n)
- {
- const ::arm_compute::Coordinates coordinate{n};
-
- float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate));
-
- const float *from = reinterpret_cast<const float *>(bias_base) + n;
- const auto value = *from;
-
- *into = value;
- }
- };
-}
-
-Initializer InitializerGenerator::generateBias(const graph::operation::FullyConnected::Node &node)
-{
- const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)};
-
- auto bias_base = _ctx.at(bias_index).data().base();
- auto bias_type = _ctx.at(bias_index).typeInfo().type();
- const auto bias_size = _ctx.at(bias_index).shape().asVector();
-
- switch (bias_type)
- {
- case ::neurun::graph::operand::DataType::TENSOR_FLOAT32:
- {
- return [bias_base, bias_size](::arm_compute::ITensor &tensor) {
- for (int32_t n = 0; n < bias_size; ++n)
- {
- const ::arm_compute::Coordinates coordinate{n};
-
- float *into = reinterpret_cast<float *>(tensor.ptr_to_element(coordinate));
-
- const float *from = reinterpret_cast<const float *>(bias_base) + n;
- const auto value = *from;
-
- *into = value;
- }
- };
- }
- case ::neurun::graph::operand::DataType::TENSOR_QUANT8_ASYMM:
- {
- return [bias_base, bias_size](::arm_compute::ITensor &tensor) {
- for (int32_t n = 0; n < bias_size; ++n)
- {
- const ::arm_compute::Coordinates coordinate{n};
-
- uint8_t *into = reinterpret_cast<uint8_t *>(tensor.ptr_to_element(coordinate));
-
- const uint8_t *from = reinterpret_cast<const uint8_t *>(bias_base) + n;
- const auto value = *from;
-
- *into = value;
- }
- };
- }
- default:
- {
- throw std::runtime_error("Not supported bias type");
- }
- }
-}
-
-} // namespace cpu
-} // namespace backend
-} // namespace neurun
diff --git a/runtimes/neurun/src/backend/cpu/InitializerGenerator.h b/runtimes/neurun/src/backend/cpu/InitializerGenerator.h
deleted file mode 100644
index 42d37f48b..000000000
--- a/runtimes/neurun/src/backend/cpu/InitializerGenerator.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 __NEURUN_BACKEND_CPU_INITIALIZER_GENERATOR_H__
-#define __NEURUN_BACKEND_CPU_INITIALIZER_GENERATOR_H__
-
-#include "backend/IInitializerGenerator.h"
-
-#include "graph/operand/Set.h"
-
-namespace neurun
-{
-namespace backend
-{
-namespace cpu
-{
-
-class InitializerGenerator : public IInitializerGenerator
-{
-public:
- InitializerGenerator(const neurun::graph::operand::Set &ctx);
-
- Initializer generateWeight(const graph::operation::Conv2D::Implicit::Node &node) override;
- Initializer generateWeight(const graph::operation::FullyConnected::Node &node) override;
-
- Initializer generateBias(const graph::operation::Conv2D::Implicit::Node &node) override;
- Initializer generateBias(const graph::operation::FullyConnected::Node &node) override;
-
-private:
- const neurun::graph::operand::Set &_ctx;
-};
-
-} // namespace cpu
-} // namespace backend
-} // namespace neurun
-
-#endif // __NEURUN_BACKEND_CPU_INITIALIZER_GENERATOR_H__
diff --git a/runtimes/neurun/src/backend/cpu/MemoryAllocator.h b/runtimes/neurun/src/backend/cpu/MemoryAllocator.h
deleted file mode 100644
index e3550ac07..000000000
--- a/runtimes/neurun/src/backend/cpu/MemoryAllocator.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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 __INTERNAL_CPU_MEMORY_ALLOCATOR_H__
-#define __INTERNAL_CPU_MEMORY_ALLOCATOR_H__
-
-#include "arm_compute/runtime/ITensorAllocator.h"
-#include "arm_compute/runtime/Memory.h"
-
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-namespace arm_compute
-{
-class Coordinates;
-class TensorInfo;
-class Tensor;
-};
-
-/** Basic implementation of a CPU memory tensor allocator. */
-class TensorAllocator : public ITensorAllocator
-{
-public:
- /** Default constructor. */
- TensorAllocator(Tensor *owner = nullptr);
- /** Default destructor */
- ~TensorAllocator();
-
- /** Make ITensorAllocator's init methods available */
- using ITensorAllocator::init;
-
- /** Shares the same backing memory with another tensor allocator, while the tensor info might be
- * different.
- * In other words this can be used to create a sub-tensor from another tensor while sharing the
- * same memory.
- *
- * @note TensorAllocator have to be of the same specialized type.
- *
- * @param[in] allocator The allocator that owns the backing memory to be shared. Ownership becomes
- * shared afterwards.
- * @param[in] coords The starting coordinates of the new tensor inside the parent tensor.
- * @param[in] sub_info The new tensor information (e.g. shape etc)
- */
- void init(const TensorAllocator &allocator, const Coordinates &coords, TensorInfo sub_info);
-
- /** Returns the pointer to the allocated data. */
- uint8_t *data() const;
-
- /** Allocate size specified by TensorInfo of CPU memory.
- *
- * @note The tensor must not already be allocated when calling this function.
- *
- */
- void allocate() override;
-
- /** Free allocated CPU memory.
- *
- * @note The tensor must have been allocated when calling this function.
- *
- */
- void free() override;
- /** Import an existing memory as a tensor's backing memory
- *
- * @warning If the tensor is flagged to be managed by a memory manager,
- * this call will lead to an error.
- * @warning Ownership of memory depends on the way the @ref Memory object was constructed
- * @note Calling free on a tensor with imported memory will just clear
- * the internal pointer value.
- *
- * @param[in] memory Memory to import
- *
- * @return error status
- */
- arm_compute::Status import_memory(Memory memory);
- /** Associates the tensor with a memory group
- *
- * @param[in] associated_memory_group Memory group to associate the tensor with
- */
- void set_associated_memory_group(MemoryGroup *associated_memory_group);
-
-protected:
- /** No-op for CPU memory
- *
- * @return A pointer to the beginning of the tensor's allocation.
- */
- uint8_t *lock() override;
-
- /** No-op for CPU memory. */
- void unlock() override;
-
-private:
- MemoryGroup *_associated_memory_group; /**< Registered memory manager */
- Memory _memory; /**< CPU memory */
- Tensor *_owner; /**< Owner of the allocator */
-};
-
-namespace internal
-{
-namespace cpu
-{
-
-class MemoryAllocator : public
-{
-};
-
-} // namespace cpu
-} // namespace internal
-
-#endif // __INTERNAL_CPU_MEMORY_ALLOCATOR_H__
diff --git a/runtimes/neurun/src/backend/cpu/MemoryPlanner.cc b/runtimes/neurun/src/backend/cpu/MemoryPlanner.cc
new file mode 100644
index 000000000..2d0995b8a
--- /dev/null
+++ b/runtimes/neurun/src/backend/cpu/MemoryPlanner.cc
@@ -0,0 +1,127 @@
+/*
+ * 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 <cassert>
+
+namespace neurun
+{
+namespace backend
+{
+namespace cpu
+{
+
+Allocator::Allocator(uint32_t capacity)
+{
+ assert(!_base && capacity != 0);
+
+ _base = new uint8_t[capacity];
+
+ VERBOSE(ALLOC) << "allocation capacity: " << capacity << std::endl;
+ VERBOSE(ALLOC) << "base pointer: " << static_cast<void *>(_base) << std::endl;
+}
+
+Allocator::~Allocator() { delete[] _base; }
+
+void BumpPlanner::claim(const model::operand::Index &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 model::operand::Index &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(model::operand::Index) 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 model::operand::Index &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 model::operand::Index &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.");
+}
+
+} // namespace cpu
+} // namespace backend
+} // namespace neurun
diff --git a/runtimes/neurun/src/backend/cpu/MemoryPlanner.h b/runtimes/neurun/src/backend/cpu/MemoryPlanner.h
new file mode 100644
index 000000000..4b2661223
--- /dev/null
+++ b/runtimes/neurun/src/backend/cpu/MemoryPlanner.h
@@ -0,0 +1,166 @@
+/*
+ * 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 __NEURUN_BACKEND_CPU_MEMORY_PLANNER_H__
+#define __NEURUN_BACKEND_CPU_MEMORY_PLANNER_H__
+
+#include <map>
+#include <unordered_map>
+
+#include "model/operand/Index.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace cpu
+{
+
+/**
+ * @brief Structure to have memory offset and size
+ */
+struct Block
+{
+ uint32_t offset;
+ uint32_t size;
+};
+
+/**
+ * @brief Class to allocate memory
+ */
+class Allocator
+{
+public:
+ Allocator(uint32_t capacity);
+ ~Allocator();
+ /**
+ * @brief Get memory base pointer
+ * @return base pointer
+ */
+ uint8_t *base() const { return _base; }
+
+private:
+ uint8_t *_base = nullptr;
+};
+
+/**
+ * @brief Interface to plan memory
+ */
+struct IMemoryPlanner
+{
+ using MemoryPlans = std::unordered_map<model::operand::Index, Block>;
+
+ /**
+ * @brief Claim memory for operand
+ * @param[in] index The operand index
+ * @param[in] size The size of the memory
+ */
+ virtual void claim(const model::operand::Index &, size_t) = 0;
+ /**
+ * @brief Release memory for operand
+ * @param[in] index The operand index
+ */
+ virtual void release(const model::operand::Index &) = 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;
+};
+
+/**
+ * @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
+ */
+ virtual void claim(const model::operand::Index &, size_t) override;
+ /**
+ * @brief Release memory for operand by bump way
+ * @param[in] index The operand index
+ */
+ virtual void release(const model::operand::Index &) override;
+ /**
+ * @brief Get capacity for memory planning
+ * @return The value of capacity
+ */
+ virtual uint32_t capacity() override { return _capacity; }
+ /**
+ * @brief Get MemoryPlans
+ * @return MemoryPlans
+ */
+ virtual 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
+ */
+ virtual void claim(const model::operand::Index &, size_t) override;
+ /**
+ * @brief Release memory for operand by firstfit way
+ * @param[in] index The operand index
+ */
+ virtual void release(const model::operand::Index &) override;
+ /**
+ * @brief Get capacity for memory planning
+ * @return The value of capacity
+ */
+ virtual uint32_t capacity() override { return _capacity; }
+ /**
+ * @brief Get MemoryPlans
+ * @return MemoryPlans
+ */
+ virtual 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<uint32_t, model::operand::Index> _claim_table;
+};
+
+} // namespace cpu
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_CPU_MEMORY_PLANNER_H__
diff --git a/runtimes/neurun/src/backend/cpu/PluginClassesAllocator.cc b/runtimes/neurun/src/backend/cpu/PluginClassesAllocator.cc
new file mode 100644
index 000000000..26d4d8858
--- /dev/null
+++ b/runtimes/neurun/src/backend/cpu/PluginClassesAllocator.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 <memory>
+#include "TensorBuilder.h"
+#include "StageGenerator.h"
+#include "Config.h"
+#include "util/logging.h"
+
+extern "C" {
+neurun::backend::cpu::TensorBuilder *allocate_TensorBuilder()
+{
+ VERBOSE(allocate_TensorBuilder) << "loaded from CPU\n";
+ return new neurun::backend::cpu::TensorBuilder;
+}
+
+neurun::backend::cpu::StageGenerator *
+allocate_StageGenerator(const neurun::model::operand::Set &operand_ctx,
+ const std::shared_ptr<neurun::backend::cpu::TensorBuilder> &tensor_builder)
+{
+ VERBOSE(allocate_StageGenerator) << "loaded from CPU\n";
+ return new neurun::backend::cpu::StageGenerator(operand_ctx, tensor_builder);
+}
+
+neurun::backend::cpu::Config *allocate_Config()
+{
+ VERBOSE(allocate_Config) << "loaded from CPU\n";
+ return new neurun::backend::cpu::Config;
+}
+}
diff --git a/runtimes/neurun/src/backend/cpu/StageGenerator.cc b/runtimes/neurun/src/backend/cpu/StageGenerator.cc
index b7a3fa24a..c53b320a4 100644
--- a/runtimes/neurun/src/backend/cpu/StageGenerator.cc
+++ b/runtimes/neurun/src/backend/cpu/StageGenerator.cc
@@ -18,7 +18,8 @@
#include <stdexcept>
-#include "internal/Padding.h"
+#include "cpp14/memory.h"
+#include "util/Padding.h"
#include "kernel/cpu/OperationUtils.h"
#include "kernel/cpu/ConvolutionLayer.h"
#include "kernel/cpu/AvgPoolLayer.h"
@@ -27,12 +28,13 @@
#include "kernel/cpu/FullyConnectedLayer.h"
#include "kernel/cpu/ReshapeLayer.h"
#include "kernel/cpu/SoftMaxLayer.h"
+#include "kernel/cpu/PermuteLayer.h"
+#include "backend/BackendManager.h"
+#include "backend/interface/IConfig.h"
-#include "logging.h"
+#include "util/logging.h"
-#include "support/nnapi/Utils.h"
-
-#include "logging.h"
+#include "util/Utils.h"
namespace neurun
{
@@ -41,25 +43,27 @@ namespace backend
namespace cpu
{
-StageGenerator::StageGenerator(const neurun::graph::operand::Set &operand_ctx,
+StageGenerator::StageGenerator(const neurun::model::operand::Set &operand_ctx,
const std::shared_ptr<TensorBuilder> &tensor_builder)
: _ctx(operand_ctx), _tensor_builder(tensor_builder)
{
// DO NOTHING
}
-Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &node)
+void StageGenerator::visit(const model::operation::Conv2DNode &node)
{
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
- const ::neurun::graph::operand::Index ker_index{node.getInputs().at(1)};
- const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)};
+ using model::operation::Conv2DNode;
+
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(Conv2DNode::Input::INPUT)};
+ const auto ker_index{node.getInputs().at(Conv2DNode::Input::KERNEL)};
+ const auto bias_index{node.getInputs().at(Conv2DNode::Input::BIAS)};
- const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index};
- const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index};
+ const auto vstride_index{node.param().vstride_index};
+ const auto hstride_index{node.param().hstride_index};
- const ::neurun::graph::operand::Index padding_index{node.param().padding_index};
- const ::neurun::graph::operand::Index activation_index{node.param().activation_index};
+ const auto padding_index{node.param().padding_index};
+ const auto activation_index{node.param().activation_index};
const PaddingCode padding_type =
static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>());
@@ -67,7 +71,7 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n
assert((ANEURALNETWORKS_PADDING_SAME == padding_type) ||
(ANEURALNETWORKS_PADDING_VALID == padding_type));
- ::internal::Stride stride;
+ util::Stride stride;
stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>();
stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>();
@@ -75,28 +79,28 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n
// Construct operation parameters
struct Param
{
- int ofm_index;
- int ifm_index;
- int ker_index;
- int bias_index;
+ model::operand::Index ofm_index;
+ model::operand::Index ifm_index;
+ model::operand::Index ker_index;
+ model::operand::Index bias_index;
::neurun::kernel::cpu::Shape ofm_shape;
::neurun::kernel::cpu::Shape ifm_shape;
::neurun::kernel::cpu::Shape ker_shape;
::neurun::kernel::cpu::Shape bias_shape;
- ::internal::Padding padding;
- ::internal::Stride stride;
+ util::Padding padding;
+ util::Stride stride;
FuseCode activation;
};
Param param;
- param.ofm_index = ofm_index.asInt();
- param.ifm_index = ifm_index.asInt();
- param.ker_index = ker_index.asInt();
- param.bias_index = bias_index.asInt();
+ param.ofm_index = ofm_index;
+ param.ifm_index = ifm_index;
+ param.ker_index = ker_index;
+ param.bias_index = bias_index;
param.ofm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(ofm_index));
param.ifm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(ifm_index));
@@ -105,21 +109,21 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n
param.stride = stride;
param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME)
- ? ::internal::same_padding(_ctx.at(ifm_index).shape().asFeature(),
- _ctx.at(ofm_index).shape().asFeature(), stride,
- _ctx.at(ker_index).shape().asKernel().W,
- _ctx.at(ker_index).shape().asKernel().H)
- : ::internal::valid_padding();
+ ? util::same_padding(_ctx.at(ifm_index).shape().asFeature(),
+ _ctx.at(ofm_index).shape().asFeature(), stride,
+ _ctx.at(ker_index).shape().asKernel().W,
+ _ctx.at(ker_index).shape().asKernel().H)
+ : util::valid_padding();
param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index});
- auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index});
- auto ker_alloc = tensors->at(::neurun::graph::operand::Index{param.ker_index});
- auto bias_alloc = tensors->at(::neurun::graph::operand::Index{param.bias_index});
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto ofm_alloc = tensors->at(param.ofm_index);
+ auto ifm_alloc = tensors->at(param.ifm_index);
+ auto ker_alloc = tensors->at(param.ker_index);
+ auto bias_alloc = tensors->at(param.bias_index);
std::unique_ptr<::neurun::kernel::cpu::ConvolutionLayer> fn{
new ::neurun::kernel::cpu::ConvolutionLayer};
@@ -130,24 +134,22 @@ Stage StageGenerator::generate(const graph::operation::Conv2D::Implicit::Node &n
param.stride.vertical, param.activation, ofm_alloc->buffer(), param.ofm_shape);
builder.append(std::move(fn));
- };
+ });
}
-Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node &node)
+void StageGenerator::visit(const model::operation::MaxPool2DNode &node)
{
- VERBOSE(MaxPool2D) << "generate CPU MaxPool2D" << std::endl;
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(model::operation::MaxPool2DNode::Input::INPUT)};
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
+ const auto kh_index{node.param().kh_index};
+ const auto kw_index{node.param().kw_index};
- const ::neurun::graph::operand::Index kh_index{node.param().kh_index};
- const ::neurun::graph::operand::Index kw_index{node.param().kw_index};
+ const auto vstride_index{node.param().vstride_index};
+ const auto hstride_index{node.param().hstride_index};
- const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index};
- const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index};
-
- const ::neurun::graph::operand::Index padding_index{node.param().padding_index};
- const ::neurun::graph::operand::Index activation_index{node.param().activation_index};
+ const auto padding_index{node.param().padding_index};
+ const auto activation_index{node.param().activation_index};
const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>();
const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>();
@@ -161,8 +163,8 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node
// Construct operation parameters
struct Param
{
- int ofm_index;
- int ifm_index;
+ model::operand::Index ofm_index;
+ model::operand::Index ifm_index;
uint32_t kw;
uint32_t kh;
@@ -170,16 +172,16 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node
::neurun::kernel::cpu::Shape ofm_shape;
::neurun::kernel::cpu::Shape ifm_shape;
- ::internal::Padding padding;
- ::internal::Stride stride;
+ util::Padding padding;
+ util::Stride stride;
FuseCode activation;
};
Param param;
- param.ofm_index = ofm_index.asInt();
- param.ifm_index = ifm_index.asInt();
+ param.ofm_index = ofm_index;
+ param.ifm_index = ifm_index;
param.kh = kh;
param.kw = kw;
@@ -192,30 +194,17 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node
param.padding =
(padding_type == ANEURALNETWORKS_PADDING_SAME)
- ? ::internal::same_padding(_ctx.at(ifm_index).shape().asFeature(),
- _ctx.at(ofm_index).shape().asFeature(), param.stride, kw, kh)
- : ::internal::valid_padding();
+ ? util::same_padding(_ctx.at(ifm_index).shape().asFeature(),
+ _ctx.at(ofm_index).shape().asFeature(), param.stride, kw, kh)
+ : util::valid_padding();
param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
- VERBOSE(MaxPool2D) << "IFM_H: " << _ctx.at(ifm_index).shape().asFeature().H << std::endl;
- VERBOSE(MaxPool2D) << "IFM_W: " << _ctx.at(ifm_index).shape().asFeature().W << std::endl;
- VERBOSE(MaxPool2D) << "OFM_H: " << _ctx.at(ofm_index).shape().asFeature().H << std::endl;
- VERBOSE(MaxPool2D) << "OFM_W: " << _ctx.at(ofm_index).shape().asFeature().W << std::endl;
- VERBOSE(MaxPool2D) << "KER_H: " << kh << std::endl;
- VERBOSE(MaxPool2D) << "KER_W: " << kw << std::endl;
- VERBOSE(MaxPool2D) << "STRIDE_H: " << vstride << std::endl;
- VERBOSE(MaxPool2D) << "STRIDE_W: " << hstride << std::endl;
- VERBOSE(MaxPool2D) << "PAD(T): " << param.padding.top << std::endl;
- VERBOSE(MaxPool2D) << "PAD(B): " << param.padding.bottom << std::endl;
- VERBOSE(MaxPool2D) << "PAD(L): " << param.padding.left << std::endl;
- VERBOSE(MaxPool2D) << "PAD(R): " << param.padding.right << std::endl;
-
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get();
- auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto ofm_alloc = tensors->at(param.ofm_index).get();
+ auto ifm_alloc = tensors->at(param.ifm_index).get();
std::unique_ptr<::neurun::kernel::cpu::MaxPoolLayer> fn{
new ::neurun::kernel::cpu::MaxPoolLayer};
@@ -226,24 +215,22 @@ Stage StageGenerator::generate(const graph::operation::MaxPool2D::Implicit::Node
param.ofm_shape);
builder.append(std::move(fn));
- };
+ });
}
-Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node &node)
+void StageGenerator::visit(const model::operation::AvgPool2DNode &node)
{
- VERBOSE(AvgPool2D) << "generate CPU AvgPool2D" << std::endl;
-
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto ifm_index{node.getInputs().at(model::operation::AvgPool2DNode::Input::INPUT)};
- const ::neurun::graph::operand::Index kh_index{node.param().kh_index};
- const ::neurun::graph::operand::Index kw_index{node.param().kw_index};
+ const auto kh_index{node.param().kh_index};
+ const auto kw_index{node.param().kw_index};
- const ::neurun::graph::operand::Index vstride_index{node.param().vstride_index};
- const ::neurun::graph::operand::Index hstride_index{node.param().hstride_index};
+ const auto vstride_index{node.param().vstride_index};
+ const auto hstride_index{node.param().hstride_index};
- const ::neurun::graph::operand::Index padding_index{node.param().padding_index};
- const ::neurun::graph::operand::Index activation_index{node.param().activation_index};
+ const auto padding_index{node.param().padding_index};
+ const auto activation_index{node.param().activation_index};
const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>();
const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>();
@@ -260,8 +247,8 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node
// Construct operation parameters
struct Param
{
- int ofm_index;
- int ifm_index;
+ model::operand::Index ofm_index;
+ model::operand::Index ifm_index;
uint32_t kw;
uint32_t kh;
@@ -269,16 +256,16 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node
::neurun::kernel::cpu::Shape ofm_shape;
::neurun::kernel::cpu::Shape ifm_shape;
- ::internal::Padding padding;
- ::internal::Stride stride;
+ util::Padding padding;
+ util::Stride stride;
FuseCode activation;
};
Param param;
- param.ofm_index = ofm_index.asInt();
- param.ifm_index = ifm_index.asInt();
+ param.ofm_index = ofm_index;
+ param.ifm_index = ifm_index;
param.kh = kh;
param.kw = kw;
@@ -291,31 +278,17 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node
param.padding =
(padding_type == ANEURALNETWORKS_PADDING_SAME)
- ? ::internal::same_padding(_ctx.at(ifm_index).shape().asFeature(),
- _ctx.at(ofm_index).shape().asFeature(), param.stride, kw, kh)
- : ::internal::valid_padding();
+ ? util::same_padding(_ctx.at(ifm_index).shape().asFeature(),
+ _ctx.at(ofm_index).shape().asFeature(), param.stride, kw, kh)
+ : util::valid_padding();
param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
- VERBOSE(AvgPool2D) << "IFM_H: " << _ctx.at(ifm_index).shape().asFeature().H << std::endl;
- VERBOSE(AvgPool2D) << "IFM_W: " << _ctx.at(ifm_index).shape().asFeature().W << std::endl;
- VERBOSE(AvgPool2D) << "OFM_H: " << _ctx.at(ofm_index).shape().asFeature().H << std::endl;
- VERBOSE(AvgPool2D) << "OFM_W: " << _ctx.at(ofm_index).shape().asFeature().W << std::endl;
- VERBOSE(AvgPool2D) << "KER_H: " << kh << std::endl;
- VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl;
- VERBOSE(AvgPool2D) << "STRIDE_H: " << vstride << std::endl;
- VERBOSE(AvgPool2D) << "STRIDE_W: " << hstride << std::endl;
- VERBOSE(AvgPool2D) << "PAD: " << ::nnfw::support::nnapi::to_string(padding_type) << std::endl;
- VERBOSE(AvgPool2D) << "PAD(T): " << param.padding.top << std::endl;
- VERBOSE(AvgPool2D) << "PAD(B): " << param.padding.bottom << std::endl;
- VERBOSE(AvgPool2D) << "PAD(L): " << param.padding.left << std::endl;
- VERBOSE(AvgPool2D) << "PAD(R): " << param.padding.right << std::endl;
-
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto ofm_alloc = tensors->at(::neurun::graph::operand::Index{param.ofm_index}).get();
- auto ifm_alloc = tensors->at(::neurun::graph::operand::Index{param.ifm_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto ofm_alloc = tensors->at(param.ofm_index).get();
+ auto ifm_alloc = tensors->at(param.ifm_index).get();
std::unique_ptr<::neurun::kernel::cpu::AvgPoolLayer> fn{
new ::neurun::kernel::cpu::AvgPoolLayer};
@@ -326,20 +299,18 @@ Stage StageGenerator::generate(const graph::operation::AvgPool2D::Implicit::Node
param.ofm_shape);
builder.append(std::move(fn));
- };
+ });
}
-Stage StageGenerator::generate(const graph::operation::Concat::Node &node)
+void StageGenerator::visit(const model::operation::ConcatNode &node)
{
- VERBOSE(Concat) << "generate CPU Concat" << std::endl;
-
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index axis_index{node.param().axis_index};
+ const auto ofm_index{node.getOutputs().at(0)};
+ const auto axis_index{node.param().axis_index};
struct Param
{
- int32_t output_index;
- std::vector<int32_t> input_indexes;
+ model::operand::Index output_index;
+ std::vector<model::operand::Index> input_indexes;
int32_t axis;
@@ -349,10 +320,10 @@ Stage StageGenerator::generate(const graph::operation::Concat::Node &node)
Param param;
- param.output_index = ofm_index.asInt();
+ param.output_index = ofm_index;
for (const auto &e : node.getInputs())
{
- param.input_indexes.emplace_back(e.asInt());
+ param.input_indexes.emplace_back(e);
}
param.axis = _ctx.at(axis_index).asScalar<int32_t>();
@@ -365,14 +336,13 @@ Stage StageGenerator::generate(const graph::operation::Concat::Node &node)
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto output_alloc = tensors->at(param.output_index).get();
std::vector<const uint8_t *> input_buffers;
for (auto ifm_ind : param.input_indexes)
{
- input_buffers.emplace_back(
- tensors->at(::neurun::graph::operand::Index{ifm_ind}).get()->buffer());
+ input_buffers.emplace_back(tensors->at(ifm_ind).get()->buffer());
}
std::unique_ptr<::neurun::kernel::cpu::ConcatLayer> fn{new ::neurun::kernel::cpu::ConcatLayer};
@@ -381,26 +351,26 @@ Stage StageGenerator::generate(const graph::operation::Concat::Node &node)
param.ofm_shape);
builder.append(std::move(fn));
- };
+ });
}
-Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &node)
+void StageGenerator::visit(const model::operation::FullyConnectedNode &node)
{
- VERBOSE(FullyConnected) << "generate CPU FullyConnected" << std::endl;
+ using model::operation::FullyConnectedNode;
- const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
- const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)};
- const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)};
- const ::neurun::graph::operand::Index activation_index{node.param().activation_index};
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(FullyConnectedNode::Input::INPUT)};
+ const auto weight_index{node.getInputs().at(FullyConnectedNode::Input::WEIGHT)};
+ const auto bias_index{node.getInputs().at(FullyConnectedNode::Input::BIAS)};
+ const auto activation_index{node.param().activation_index};
// Construct operation parameters
struct Param
{
- int output_index;
- int input_index;
- int weight_index;
- int bias_index;
+ model::operand::Index output_index;
+ model::operand::Index input_index;
+ model::operand::Index weight_index;
+ model::operand::Index bias_index;
::neurun::kernel::cpu::Shape ofm_shape;
::neurun::kernel::cpu::Shape ifm_shape;
@@ -412,10 +382,10 @@ Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &nod
Param param;
- param.output_index = output_index.asInt();
- param.input_index = input_index.asInt();
- param.weight_index = weight_index.asInt();
- param.bias_index = bias_index.asInt();
+ param.output_index = output_index;
+ param.input_index = input_index;
+ param.weight_index = weight_index;
+ param.bias_index = bias_index;
param.ofm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(output_index));
param.ifm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(input_index));
@@ -426,11 +396,11 @@ Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &nod
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get();
- auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get();
- auto weight_alloc = tensors->at(::neurun::graph::operand::Index{param.weight_index}).get();
- auto bias_alloc = tensors->at(::neurun::graph::operand::Index{param.bias_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto output_alloc = tensors->at(param.output_index).get();
+ auto input_alloc = tensors->at(param.input_index).get();
+ auto weight_alloc = tensors->at(param.weight_index).get();
+ auto bias_alloc = tensors->at(param.bias_index).get();
std::unique_ptr<::neurun::kernel::cpu::FullyConnectedLayer> fn{
new ::neurun::kernel::cpu::FullyConnectedLayer};
@@ -440,18 +410,18 @@ Stage StageGenerator::generate(const graph::operation::FullyConnected::Node &nod
output_alloc->buffer(), param.ofm_shape);
builder.append(std::move(fn));
- };
+ });
}
-Stage StageGenerator::generate(const graph::operation::Reshape::Node &node)
+void StageGenerator::visit(const model::operation::ReshapeNode &node)
{
- const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(model::operation::ReshapeNode::Input::INPUT)};
struct Param
{
- int output_index;
- int input_index;
+ model::operand::Index output_index;
+ model::operand::Index input_index;
::neurun::kernel::cpu::Shape ofm_shape;
::neurun::kernel::cpu::Shape ifm_shape;
@@ -459,17 +429,17 @@ Stage StageGenerator::generate(const graph::operation::Reshape::Node &node)
Param param;
- param.output_index = output_index.asInt();
- param.input_index = input_index.asInt();
+ param.output_index = output_index;
+ param.input_index = input_index;
param.ofm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(output_index));
param.ifm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(input_index));
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get();
- auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto output_alloc = tensors->at(param.output_index).get();
+ auto input_alloc = tensors->at(param.input_index).get();
std::unique_ptr<::neurun::kernel::cpu::ReshapeLayer> fn{
new ::neurun::kernel::cpu::ReshapeLayer};
@@ -477,21 +447,19 @@ Stage StageGenerator::generate(const graph::operation::Reshape::Node &node)
fn->configure(input_alloc->buffer(), param.ifm_shape, output_alloc->buffer(), param.ofm_shape);
builder.append(std::move(fn));
- };
+ });
}
-Stage StageGenerator::generate(const graph::operation::Softmax::Node &node)
+void StageGenerator::visit(const model::operation::SoftmaxNode &node)
{
- VERBOSE(Softmax) << "generate CPU Softmax" << std::endl;
-
- const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
- const ::neurun::graph::operand::Index scale_index{node.param().scale_index};
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(model::operation::SoftmaxNode::Input::INPUT)};
+ const auto scale_index{node.param().scale_index};
struct Param
{
- int output_index;
- int input_index;
+ model::operand::Index output_index;
+ model::operand::Index input_index;
::neurun::kernel::cpu::Shape ofm_shape;
::neurun::kernel::cpu::Shape ifm_shape;
@@ -501,8 +469,8 @@ Stage StageGenerator::generate(const graph::operation::Softmax::Node &node)
Param param;
- param.output_index = output_index.asInt();
- param.input_index = input_index.asInt();
+ param.output_index = output_index;
+ param.input_index = input_index;
param.ofm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(output_index));
param.ifm_shape = ::neurun::kernel::cpu::getShape(_ctx.at(input_index));
@@ -511,9 +479,9 @@ Stage StageGenerator::generate(const graph::operation::Softmax::Node &node)
auto tensors = _tensor_builder;
- return [tensors, param](IExecutionBuilder &builder) {
- auto output_alloc = tensors->at(::neurun::graph::operand::Index{param.output_index}).get();
- auto input_alloc = tensors->at(::neurun::graph::operand::Index{param.input_index}).get();
+ returnStage([tensors, param](IExecutionBuilder &builder) {
+ auto output_alloc = tensors->at(param.output_index).get();
+ auto input_alloc = tensors->at(param.input_index).get();
std::unique_ptr<::neurun::kernel::cpu::SoftMaxLayer> fn{
new ::neurun::kernel::cpu::SoftMaxLayer};
@@ -522,15 +490,58 @@ Stage StageGenerator::generate(const graph::operation::Softmax::Node &node)
param.ofm_shape);
builder.append(std::move(fn));
- };
+ });
}
-Stage StageGenerator::generate(const graph::operation::NOP::Node & /* node */)
+void StageGenerator::visit(const model::operation::PermuteNode &node)
{
- // DO NOTHING
- return nullptr;
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ using PermuteType = model::operation::PermuteNode::Type;
+
+ struct Param
+ {
+ model::operand::Index output_index;
+ model::operand::Index input_index;
+
+ model::operand::Shape shape;
+
+ PermuteType type{PermuteType::COPY};
+ };
+
+ Param param;
+
+ param.output_index = output_index;
+ param.input_index = input_index;
+
+ param.shape = _ctx.at(output_index).shape();
+ param.type = node.param().type;
+
+ // assert(param.shape == _ctx.at(input_index));
+
+ const auto &input_li = _ctx.at(input_index).lower_info();
+ const auto &output_li = _ctx.at(output_index).lower_info();
+ const auto input_backend = input_li->def_backends().getOnlyElement();
+ const auto output_backend = output_li->def_backends().getOnlyElement();
+
+ const auto input_tensors = input_backend->tensor_builder();
+ const auto output_tensors = output_backend->tensor_builder();
+
+ returnStage([input_tensors, output_tensors, param](IExecutionBuilder &builder) {
+ auto output_object = output_tensors->wrapTensor(param.output_index);
+ auto input_object = input_tensors->wrapTensor(param.input_index);
+
+ auto fn = nnfw::cpp14::make_unique<::neurun::kernel::cpu::PermuteLayer>();
+
+ fn->configure(input_object, output_object, param.shape, param.type);
+
+ builder.append(std::move(fn));
+ });
}
+void StageGenerator::visit(const model::operation::AddNode &) { throw std::runtime_error("NYI"); }
+
} // namespace neurun
} // namespace backend
} // namespace cpu
diff --git a/runtimes/neurun/src/backend/cpu/StageGenerator.h b/runtimes/neurun/src/backend/cpu/StageGenerator.h
index acdd2c8b2..6a0e387da 100644
--- a/runtimes/neurun/src/backend/cpu/StageGenerator.h
+++ b/runtimes/neurun/src/backend/cpu/StageGenerator.h
@@ -17,9 +17,9 @@
#ifndef __NEURUN_BACKEND_CPU_STAGE_GENERATOR_H__
#define __NEURUN_BACKEND_CPU_STAGE_GENERATOR_H__
-#include "backend/IStageGenerator.h"
+#include "backend/interface/IStageGenerator.h"
-#include "graph/operand/Set.h"
+#include "model/operand/Set.h"
#include "backend/cpu/operand/Tensor.h"
#include "TensorBuilder.h"
@@ -33,22 +33,18 @@ namespace cpu
class StageGenerator : public IStageGenerator
{
public:
- StageGenerator(const neurun::graph::operand::Set &ctx,
+ StageGenerator(const neurun::model::operand::Set &ctx,
const std::shared_ptr<TensorBuilder> &tensor_builder);
virtual std::shared_ptr<ITensorBuilder> tensor_builder() override { return _tensor_builder; }
- virtual Stage generate(const graph::operation::Conv2D::Implicit::Node &node) override;
- virtual Stage generate(const graph::operation::MaxPool2D::Implicit::Node &node) override;
- virtual Stage generate(const graph::operation::AvgPool2D::Implicit::Node &node) override;
- virtual Stage generate(const graph::operation::Concat::Node &node) override;
- virtual Stage generate(const graph::operation::FullyConnected::Node &node) override;
- virtual Stage generate(const graph::operation::Reshape::Node &node) override;
- virtual Stage generate(const graph::operation::Softmax::Node &node) override;
- virtual Stage generate(const graph::operation::NOP::Node &node) override;
+#define OP(InternalName, IsNnApi, NnApiName) \
+ virtual void visit(const model::operation::InternalName &) override;
+#include "model/operation/Op.lst"
+#undef OP
private:
- const neurun::graph::operand::Set &_ctx;
+ const neurun::model::operand::Set &_ctx;
std::shared_ptr<TensorBuilder> _tensor_builder;
};
diff --git a/runtimes/neurun/src/backend/cpu/TensorBuilder.cc b/runtimes/neurun/src/backend/cpu/TensorBuilder.cc
index 1b972a830..9c39b9c00 100644
--- a/runtimes/neurun/src/backend/cpu/TensorBuilder.cc
+++ b/runtimes/neurun/src/backend/cpu/TensorBuilder.cc
@@ -19,6 +19,7 @@
#include <cassert>
#include "operand/Object.h"
+#include "util/logging.h"
namespace neurun
{
@@ -27,43 +28,93 @@ namespace backend
namespace cpu
{
-TensorBuilder::TensorBuilder()
+TensorBuilder::TensorBuilder() : _mem_planner(std::make_shared<FirstFitPlanner>())
{
// DO NOTHING
}
-void TensorBuilder::mark(const ::neurun::graph::operand::Index &ind)
+void TensorBuilder::registerTensorInfo(const model::operand::Index &ind,
+ const compiler::TensorInfo &info)
{
- assert(_tensors.size() == 0);
+ _tensor_info_map.insert({ind, info});
+}
+
+void TensorBuilder::registerSubTensorInfo(const model::operand::Index &,
+ const compiler::SubTensorInfo &)
+{
+ // Not supported yet
+ assert(false);
+}
+
+void TensorBuilder::notifyFirstUse(const model::operand::Index &ind)
+{
+ assert(_tensor_info_map.find(ind) != _tensor_info_map.end());
+ const auto &info = _tensor_info_map.at(ind);
- _inds.insert(ind);
+ const auto size = info.total_size();
+ _mem_planner->claim(ind, size);
}
-void TensorBuilder::prepare(codegen::Plan &plan,
- const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx)
+void TensorBuilder::notifyLastUse(const model::operand::Index &ind) { _mem_planner->release(ind); }
+
+void TensorBuilder::prepare(void)
{
assert(_tensors.size() == 0);
- for (auto ind_int : _inds)
+ _mem_alloc = std::make_shared<Allocator>(_mem_planner->capacity());
+ assert(_mem_alloc->base());
+
+ for (auto &mem_plan : _mem_planner->memory_plans())
{
- ::neurun::graph::operand::Index ind{ind_int};
- auto tensor = std::make_shared<operand::Tensor>(tensor_info_ctx.at(ind.asInt()));
- // TODO Fix allocation here. When Tensor object is created the memory for tensor is also
- // allocated, and this must be fixed.
- plan.operands().set(ind, std::make_shared<operand::Object>(tensor));
+ auto ind = mem_plan.first;
+ auto mem_blk = mem_plan.second;
+ const auto &info = _tensor_info_map[ind];
+
+ uint8_t *buffer = _mem_alloc->base() + mem_blk.offset;
+ auto tensor = std::make_shared<operand::Tensor>(info);
+ tensor->setBuffer(buffer);
_tensors[ind] = tensor;
+
+ VERBOSE(CPU_TENSORBUILDER) << "TENSOR(#" << ind.value() << "): " << static_cast<void *>(buffer)
+ << std::endl;
+
+ // If we do not make tensor here currently, stages would cause segment fault
}
}
void TensorBuilder::allocate(void)
{
- assert(_inds.size() == _tensors.size());
-
// NOTE For now nothing to do. Allocation is done in prepare stage, which is wrong
- // See also: comment in `prepare()`
}
-std::shared_ptr<operand::Tensor> TensorBuilder::at(const ::neurun::graph::operand::Index &ind)
+std::shared_ptr<::neurun::backend::operand::ITensor>
+TensorBuilder::tensorAt(const model::operand::Index &ind)
+{
+ return _tensors.at(ind);
+}
+
+std::shared_ptr<backend::operand::IObject>
+TensorBuilder::wrapTensor(const model::operand::Index &ind)
+{
+ if (_objects.find(ind) != _objects.end())
+ {
+ return _objects.at(ind);
+ }
+ else
+ {
+ return _objects[ind] = std::make_shared<operand::Object>(_tensors.at(ind));
+ }
+}
+
+void TensorBuilder::iterate(const IterateFunction &fn)
+{
+ for (auto it : _tensors)
+ {
+ fn(it.first);
+ }
+}
+
+std::shared_ptr<operand::Tensor> TensorBuilder::at(const ::neurun::model::operand::Index &ind)
{
return _tensors.at(ind);
}
diff --git a/runtimes/neurun/src/backend/cpu/TensorBuilder.h b/runtimes/neurun/src/backend/cpu/TensorBuilder.h
index f61a930fe..2715d57f0 100644
--- a/runtimes/neurun/src/backend/cpu/TensorBuilder.h
+++ b/runtimes/neurun/src/backend/cpu/TensorBuilder.h
@@ -18,11 +18,12 @@
#define __NEURUN_BACKEND_CPU_TENSOR_BUILDER_H__
#include <unordered_map>
-#include <unordered_set>
-#include "backend/ITensorBuilder.h"
+#include "backend/interface/ITensorBuilder.h"
#include "backend/cpu/operand/Tensor.h"
-#include "graph/operand/Index.h"
+#include "backend/cpu/operand/Object.h"
+#include "model/operand/Index.h"
+#include "MemoryPlanner.h"
namespace neurun
{
@@ -31,23 +32,47 @@ namespace backend
namespace cpu
{
-class Plan;
-
class TensorBuilder : public ITensorBuilder
{
public:
TensorBuilder();
- virtual void mark(const ::neurun::graph::operand::Index &ind) override;
- virtual void prepare(codegen::Plan &plan,
- const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx) override;
+ /**
+ * @brief Register tensor information to allocate on CPU backend
+ * @param[in] ind Operand index
+ * @param[in] info Tensor information
+ */
+ virtual void registerTensorInfo(const model::operand::Index &ind,
+ const compiler::TensorInfo &info) override;
+ /**
+ * @brief Register subtensor information to allocate on CPU backend
+ * @param[in] ind Operand index
+ * @param[in] info Tensor information
+ */
+ virtual void registerSubTensorInfo(const model::operand::Index &ind,
+ const compiler::SubTensorInfo &info) override;
+
+ virtual void notifyFirstUse(const model::operand::Index &) override;
+ virtual void notifyLastUse(const model::operand::Index &) override;
+
+ virtual void prepare(void) override;
virtual void allocate(void) override;
- std::shared_ptr<operand::Tensor> at(const ::neurun::graph::operand::Index &ind);
+ virtual std::shared_ptr<::neurun::backend::operand::ITensor>
+ tensorAt(const model::operand::Index &ind) override;
+ virtual std::shared_ptr<backend::operand::IObject>
+ wrapTensor(const model::operand::Index &ind) override;
+ virtual void iterate(const IterateFunction &fn) override;
+
+ std::shared_ptr<operand::Tensor> at(const ::neurun::model::operand::Index &ind);
private:
- std::unordered_set<graph::operand::Index> _inds;
- std::unordered_map<graph::operand::Index, std::shared_ptr<operand::Tensor>> _tensors;
+ std::unordered_map<model::operand::Index, compiler::TensorInfo> _tensor_info_map;
+ std::unordered_map<model::operand::Index, std::shared_ptr<operand::Tensor>> _tensors;
+ std::unordered_map<model::operand::Index, std::shared_ptr<operand::Object>> _objects;
+ std::unordered_map<model::operand::Index, Block> _tensor_mem_map;
+ std::shared_ptr<IMemoryPlanner> _mem_planner;
+ std::shared_ptr<Allocator> _mem_alloc;
};
} // namespace cpu
diff --git a/runtimes/neurun/src/backend/cpu/operand/Object.cc b/runtimes/neurun/src/backend/cpu/operand/Object.cc
index 52b63fba7..011747a8c 100644
--- a/runtimes/neurun/src/backend/cpu/operand/Object.cc
+++ b/runtimes/neurun/src/backend/cpu/operand/Object.cc
@@ -25,7 +25,8 @@ namespace cpu
namespace operand
{
-void Object::access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const
+void Object::access(
+ const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const
{
fn(*_tensor);
}
diff --git a/runtimes/neurun/src/backend/cpu/operand/Object.h b/runtimes/neurun/src/backend/cpu/operand/Object.h
index 08f63f3dc..5ef7c4fbf 100644
--- a/runtimes/neurun/src/backend/cpu/operand/Object.h
+++ b/runtimes/neurun/src/backend/cpu/operand/Object.h
@@ -18,9 +18,9 @@
#define __NEURUN_BACKEND_CPU_OPERAND_OBJECT_H__
#include <memory>
-#include <arm_compute/core/ITensor.h>
+#include "backend/interface/operand/ITensor.h"
-#include "backend/IObject.h"
+#include "backend/interface/operand/IObject.h"
namespace neurun
{
@@ -37,19 +37,20 @@ public:
Object() = default;
public:
- Object(const std::shared_ptr<::arm_compute::ITensor> &tensor) : _tensor{tensor}
+ Object(const std::shared_ptr<::neurun::backend::operand::ITensor> &tensor) : _tensor{tensor}
{
// DO NOTHING
}
public:
- ::arm_compute::ITensor *ptr(void) const override { return _tensor.get(); }
+ ::neurun::backend::operand::ITensor *ptr(void) const override { return _tensor.get(); }
private:
- std::shared_ptr<::arm_compute::ITensor> _tensor;
+ std::shared_ptr<::neurun::backend::operand::ITensor> _tensor;
public:
- void access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const override;
+ void
+ access(const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const override;
};
} // namespace operand
diff --git a/runtimes/neurun/src/backend/cpu/operand/Tensor.cc b/runtimes/neurun/src/backend/cpu/operand/Tensor.cc
index 0e4f34aac..a5251292e 100644
--- a/runtimes/neurun/src/backend/cpu/operand/Tensor.cc
+++ b/runtimes/neurun/src/backend/cpu/operand/Tensor.cc
@@ -16,6 +16,8 @@
#include "Tensor.h"
+#define NO_USE(a) (void)(a)
+
namespace neurun
{
namespace backend
@@ -25,7 +27,11 @@ namespace cpu
namespace operand
{
-// NO IMPLEMENTATION YET
+size_t Tensor::calcOffset(const neurun::util::feature::Coordinate4D &coords)
+{
+ NO_USE(coords);
+ throw std::runtime_error("offset_element_in_bytes is not supported for cpu::Tensor now.");
+}
} // namespace operand
} // namespace cpu
diff --git a/runtimes/neurun/src/backend/cpu/operand/Tensor.h b/runtimes/neurun/src/backend/cpu/operand/Tensor.h
index 83a99acf2..7500f890f 100644
--- a/runtimes/neurun/src/backend/cpu/operand/Tensor.h
+++ b/runtimes/neurun/src/backend/cpu/operand/Tensor.h
@@ -17,8 +17,8 @@
#ifndef __NEURUN_BACKEND_CPU_OPERAND_TENSOR_H__
#define __NEURUN_BACKEND_CPU_OPERAND_TENSOR_H__
-#include <arm_compute/core/ITensor.h>
-#include <arm_compute/core/TensorInfo.h>
+#include "backend/interface/operand/ITensor.h"
+#include "compiler/TensorInfo.h"
namespace neurun
{
@@ -29,38 +29,40 @@ namespace cpu
namespace operand
{
-class Tensor : public ::arm_compute::ITensor
+class Tensor : public ::neurun::backend::operand::ITensor
{
public:
- Tensor() = default;
+ Tensor() = delete;
- Tensor(::arm_compute::TensorInfo info) : _info(info)
- {
- // TODO Do not allocate buffer here. This tensor is just an abstract Tensor object for cpu.
- uint32_t size = _info.total_size(); // NOTE This size may not be accurate
- _buffer = new uint8_t[size]; // NOTE The allocated buffer is never deallocated.
- }
-
- Tensor(uint8_t *buffer) : _buffer(buffer)
+public:
+ Tensor(const compiler::TensorInfo &info) : _info(info)
{
// DO NOTHING
}
public:
void setBuffer(uint8_t *buffer) { _buffer = buffer; }
+ ::neurun::model::operand::DataType data_type() const { return _info.typeInfo().type(); }
public:
- ::arm_compute::TensorInfo *info() const override
- {
- return const_cast<::arm_compute::TensorInfo *>(&_info);
- }
-
- ::arm_compute::TensorInfo *info() override { return &_info; }
-
uint8_t *buffer() const override { 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().dims().size(); }
+ size_t total_size() const override { return _info.total_size(); }
+ size_t calcOffset(const neurun::util::feature::Coordinate4D &coords) override;
private:
- ::arm_compute::TensorInfo _info;
+ compiler::TensorInfo _info;
uint8_t *_buffer = nullptr;
};
diff --git a/runtimes/neurun/src/backend/IBackendConfig.h b/runtimes/neurun/src/backend/interface/IConfig.h
index a6c7ce517..82789d0ff 100644
--- a/runtimes/neurun/src/backend/IBackendConfig.h
+++ b/runtimes/neurun/src/backend/interface/IConfig.h
@@ -14,8 +14,10 @@
* limitations under the License.
*/
-#ifndef __INTERNAL_IBACKEND_CONFIG_H__
-#define __INTERNAL_IBACKEND_CONFIG_H__
+#ifndef __NEURUN_BACKEND_ICONFIG_H__
+#define __NEURUN_BACKEND_ICONFIG_H__
+
+#include <string>
#include "graph/operand/Layout.h"
@@ -24,16 +26,19 @@ namespace neurun
namespace backend
{
-struct IBackendConfig
+struct IConfig
{
- virtual ~IBackendConfig() = default;
+ virtual ~IConfig() = default;
+ virtual std::string id() = 0;
virtual void initialize() = 0;
// NOTE Assume backend has only one type of operand layout
virtual graph::operand::Layout getOperandLayout() = 0;
+ // Support subtensor allocation
+ virtual bool SupportSubTensorAlloc() = 0;
};
} // namespace backend
} // namespace neurun
-#endif // __INTERNAL_IBACKEND_CONFIG_H__
+#endif // __NEURUN_BACKEND_ICONFIG_H__
diff --git a/runtimes/neurun/src/backend/interface/IStageGenerator.h b/runtimes/neurun/src/backend/interface/IStageGenerator.h
new file mode 100644
index 000000000..878a50e3f
--- /dev/null
+++ b/runtimes/neurun/src/backend/interface/IStageGenerator.h
@@ -0,0 +1,72 @@
+/*
+ * 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 __NEURUN_BACKEND_ISTAGE_GENERATOR_H__
+#define __NEURUN_BACKEND_ISTAGE_GENERATOR_H__
+
+#include <memory>
+#include <functional>
+
+#include "exec/interface/IFunction.h"
+
+#include "backend/interface/ITensorBuilder.h"
+#include "model/operation/NodeVisitor.h"
+
+struct IExecutionBuilder
+{
+ virtual ~IExecutionBuilder() = default;
+
+ virtual void append(std::unique_ptr<::neurun::exec::IFunction> &&f) = 0;
+};
+
+using Stage = std::function<void(IExecutionBuilder &)>;
+
+namespace neurun
+{
+namespace backend
+{
+
+class IStageGenerator : model::operation::NodeVisitor
+{
+public:
+ virtual ~IStageGenerator() = default;
+
+ virtual std::shared_ptr<ITensorBuilder> tensor_builder() = 0;
+
+protected:
+#define OP(InternalName, IsNnApi, NnApiName) \
+ virtual void visit(const model::operation::InternalName &) override {}
+#include "model/operation/Op.lst"
+#undef OP
+
+protected:
+ void returnStage(const Stage &stage) { _return = stage; }
+
+public:
+ Stage generate(const model::operation::Node &node)
+ {
+ node.accept(std::move(*this));
+ return _return;
+ }
+
+private:
+ Stage _return = nullptr;
+};
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ISTAGE_GENERATOR_H__
diff --git a/runtimes/neurun/src/backend/interface/ITensorBuilder.h b/runtimes/neurun/src/backend/interface/ITensorBuilder.h
new file mode 100644
index 000000000..354a270e6
--- /dev/null
+++ b/runtimes/neurun/src/backend/interface/ITensorBuilder.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.
+ */
+
+#ifndef __NEURUN_BACKEND_ITENSOR_BUILDER_H__
+#define __NEURUN_BACKEND_ITENSOR_BUILDER_H__
+
+#include <map>
+
+#include "model/operand/Index.h"
+#include "operand/IObject.h"
+#include "compiler/SubTensorInfo.h"
+#include "compiler/TensorInfo.h"
+#include "backend/interface/operand/ITensor.h"
+
+namespace neurun
+{
+namespace backend
+{
+
+struct ITensorBuilder
+{
+ using IterateFunction = std::function<void(const model::operand::Index &)>;
+
+ virtual ~ITensorBuilder(void) = default;
+
+ // TODO Merge registerTensorInfo and registerSubTensorInfo using abstraction by internal class
+ /**
+ * @brief Register tensor information to allocate on backend
+ */
+ virtual void registerTensorInfo(const model::operand::Index &, const compiler::TensorInfo &) = 0;
+ /**
+ * @brief Register subtensor information to allocate on backend
+ */
+ virtual void registerSubTensorInfo(const model::operand::Index &,
+ const compiler::SubTensorInfo &) = 0;
+
+ virtual void notifyFirstUse(const model::operand::Index &) = 0;
+ virtual void notifyLastUse(const model::operand::Index &) = 0;
+
+ virtual void prepare(void) = 0;
+ virtual void allocate(void) = 0;
+
+ virtual std::shared_ptr<::neurun::backend::operand::ITensor>
+ tensorAt(const model::operand::Index &ind) = 0;
+ virtual std::shared_ptr<backend::operand::IObject>
+ wrapTensor(const model::operand::Index &ind) = 0;
+ virtual void iterate(const IterateFunction &fn) = 0;
+};
+
+} // namespace backend
+} // namespace neurun
+
+#include <set>
+#include <memory>
+
+namespace neurun
+{
+namespace backend
+{
+
+using TensorBuilderSet = std::set<std::shared_ptr<backend::ITensorBuilder>>;
+
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_ITENSOR_BUILDER_H__
diff --git a/runtimes/neurun/src/backend/IObject.h b/runtimes/neurun/src/backend/interface/operand/IObject.h
index f7d511095..44b33b080 100644
--- a/runtimes/neurun/src/backend/IObject.h
+++ b/runtimes/neurun/src/backend/interface/operand/IObject.h
@@ -19,7 +19,7 @@
#include <functional>
-#include <arm_compute/core/ITensor.h>
+#include "ITensor.h"
namespace neurun
{
@@ -31,8 +31,9 @@ namespace operand
struct IObject
{
virtual ~IObject() = default;
- virtual ::arm_compute::ITensor *ptr(void) const = 0;
- virtual void access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const = 0;
+ virtual ::neurun::backend::operand::ITensor *ptr(void) const = 0;
+ virtual void
+ access(const std::function<void(::neurun::backend::operand::ITensor &tensor)> &fn) const = 0;
};
} // namespace operand
diff --git a/runtimes/neurun/src/backend/interface/operand/ITensor.h b/runtimes/neurun/src/backend/interface/operand/ITensor.h
new file mode 100644
index 000000000..8bc3ff465
--- /dev/null
+++ b/runtimes/neurun/src/backend/interface/operand/ITensor.h
@@ -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.
+ */
+
+#ifndef __NEURUN_BACKEND_OPERAND_I_TENSOR_H__
+#define __NEURUN_BACKEND_OPERAND_I_TENSOR_H__
+
+#include <cstring>
+#include <cstdint>
+
+#include "util/feature/Coordinate4D.h"
+
+namespace neurun
+{
+namespace backend
+{
+namespace operand
+{
+
+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 neurun::util::feature::Coordinate4D &coords) = 0;
+};
+
+} // namespace operand
+} // namespace backend
+} // namespace neurun
+
+#endif // __NEURUN_BACKEND_OPERAND_I_TENSOR_H__
diff --git a/runtimes/neurun/src/codegen/IPlanBuilder.h b/runtimes/neurun/src/codegen/IPlanBuilder.h
deleted file mode 100644
index 197681432..000000000
--- a/runtimes/neurun/src/codegen/IPlanBuilder.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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 __NEURUN_CODEGEN_I_PLAN_BUILDER_H__
-#define __NEURUN_CODEGEN_I_PLAN_BUILDER_H__
-
-#include "arm_compute/core/TensorInfo.h"
-#include "backend/IStageGenerator.h"
-#include "backend/IInitializerGenerator.h"
-
-namespace neurun
-{
-namespace codegen
-{
-
-struct IPlanBuilder
-{
- virtual ~IPlanBuilder() = default;
-
- virtual void addShapeConstr(const ::neurun::graph::operand::Index &ind,
- const ::arm_compute::TensorInfo &info) = 0;
- virtual void addInitializer(const ::neurun::graph::operand::Index &ind,
- const Initializer &initializer) = 0;
- virtual void addStage(const Stage &) = 0;
-};
-
-} // namespace codegen
-} // namespace neurun
-
-#endif // __NEURUN_CODEGEN_I_PLAN_BUILDER_H__
diff --git a/runtimes/neurun/src/codegen/PlanBuilder.h b/runtimes/neurun/src/codegen/PlanBuilder.h
deleted file mode 100644
index 4323143b3..000000000
--- a/runtimes/neurun/src/codegen/PlanBuilder.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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 __NEURUN_CODEGEN_PLAN_BUILDER_H__
-#define __NEURUN_CODEGEN_PLAN_BUILDER_H__
-
-#include "IPlanBuilder.h"
-#include "codegen/Plan.h"
-#include "backend/IStageGenerator.h"
-#include "backend/ITensorBuilder.h"
-
-namespace neurun
-{
-namespace codegen
-{
-
-class ExecutionBuilder final : public IExecutionBuilder
-{
-public:
- ExecutionBuilder(codegen::Plan &plan) : _plan{plan}
- {
- // DO NOTHING
- }
-
-public:
- void append(std::unique_ptr<::arm_compute::IFunction> &&f) override
- {
- _plan.operations().append(std::move(f));
- }
-
-private:
- codegen::Plan &_plan;
-};
-
-class PlanBuilder final : public IPlanBuilder
-{
-public:
- PlanBuilder(codegen::Plan &plan) : _plan{plan}
- {
- // DO NOTHING
- }
-
-public:
- void addShapeConstr(const ::neurun::graph::operand::Index &ind,
- const ::arm_compute::TensorInfo &info) override;
-
-public:
- void addInitializer(const ::neurun::graph::operand::Index &ind,
- const Initializer &initializer) override;
-
-public:
- void addStage(const Stage &stage) override;
-
-public:
- // TODO Remove the argument `tensor_builders`
- void finalize(const backend::TensorBuilderSet &tensor_builders);
-
-public:
- const std::map<int, ::arm_compute::TensorInfo> &tensor_info_ctx() { return _tensor_info_ctx; }
-
-private:
- codegen::Plan &_plan;
-
-private:
- std::map<int, ::arm_compute::TensorInfo> _tensor_info_ctx;
- std::map<int, Initializer> _initializer_ctx;
- std::vector<Stage> _stages;
-};
-
-} // namepsace codegen
-} // namespace neurun
-
-#endif // __NEURUN_CODEGEN_PLAN_BUILDER_H__
diff --git a/runtimes/neurun/src/codegen/Planner.cc b/runtimes/neurun/src/codegen/Planner.cc
deleted file mode 100644
index 1add3acf5..000000000
--- a/runtimes/neurun/src/codegen/Planner.cc
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * 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 "Planner.h"
-
-#include <typeinfo>
-
-#include "internal/Convert.h"
-#include "graph/operand/Set.h"
-#include "codegen/IPlanBuilder.h"
-#include "graph/operation/LowerInfo.h"
-
-#include "logging.h"
-
-namespace neurun
-{
-namespace codegen
-{
-
-void Planner::visit(const graph::operation::Conv2D::Implicit::Node &node)
-{
- const auto ofm_index = node.getOutputs().at(0);
-
- const auto ifm_index = node.getInputs().at(0);
- const auto ker_index = node.getInputs().at(1);
- const auto bias_index = node.getInputs().at(2);
-
- const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
- const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
- const auto ker_shape = _ctx.at(ker_index).shape().asKernel();
- const auto bias_size = _ctx.at(bias_index).shape().asVector();
-
- // Set Shape Constraints
- _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape));
- _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape));
- _builder.addShapeConstr(ker_index, ::internal::asTensorInfo(ker_shape));
- _builder.addShapeConstr(bias_index, ::internal::asTensorInfo(bias_size));
-
- // backend
- auto backend = node.lower_info()->backend();
-
- // Generate Initializers
- auto init_gen = backend.initializer_gen();
- _builder.addInitializer(ker_index, init_gen->generateWeight(node));
- _builder.addInitializer(bias_index, init_gen->generateBias(node));
-
- // Generate Stage
- auto stage_gen = backend.stage_gen();
- _builder.addStage(stage_gen->generate(node));
-}
-
-void Planner::visit(const graph::operation::MaxPool2D::Implicit::Node &node)
-{
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
-
- const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
- const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
-
- // Set Shape Constraints
- _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape));
- _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape));
-
- // backend
- auto backend = node.lower_info()->backend();
-
- // Generate Stage
- auto stage_gen = backend.stage_gen();
- _builder.addStage(stage_gen->generate(node));
-}
-
-void Planner::visit(const graph::operation::AvgPool2D::Implicit::Node &node)
-{
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index ifm_index{node.getInputs().at(0)};
-
- const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
- const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
-
- // Set Shape Constraints
- _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape));
- _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape));
-
- // backend
- auto backend = node.lower_info()->backend();
-
- // Generate Stage
- auto stage_gen = backend.stage_gen();
- _builder.addStage(stage_gen->generate(node));
-}
-
-void Planner::visit(const graph::operation::Concat::Node &node)
-{
- const ::neurun::graph::operand::Index ofm_index{node.getOutputs().at(0)};
-
- // NOTE This implementation assumes that input and output are a feature
- // TODO Remove this assumption
- const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
-
- // NOTE This implementation assumes concat over feature depth
- // TODO Remove this assumption
- assert(_ctx.at(::neurun::graph::operand::Index{node.param().axis_index}).asScalar<int32_t>() ==
- 3);
-
- // Set Shape Constraints (for output)
- _builder.addShapeConstr(ofm_index, ::internal::asTensorInfo(ofm_shape));
-
- // Set Shape Constraints (for input)
- for (const auto &index : node.getInputs())
- {
- const ::neurun::graph::operand::Index ifm_index{index};
- const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
- _builder.addShapeConstr(ifm_index, ::internal::asTensorInfo(ifm_shape));
- }
-
- // backend
- auto backend = node.lower_info()->backend();
-
- // Generate Stage
- auto stage_gen = backend.stage_gen();
- _builder.addStage(stage_gen->generate(node));
-}
-
-void Planner::visit(const graph::operation::FullyConnected::Node &node)
-{
- VERBOSE(FullyConnected) << "Configure FULLY_CONNECTED operation" << std::endl;
-
- const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)};
-
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
- const ::neurun::graph::operand::Index weight_index{node.getInputs().at(1)};
- const ::neurun::graph::operand::Index bias_index{node.getInputs().at(2)};
-
- const ::neurun::graph::operand::Index activation_index{node.param().activation_index};
-
- assert(_ctx.at(output_index).shape().rank() == 2);
- const auto output_size = _ctx.at(output_index).shape().dim(1);
-
- // NOTE We assume that input is a feature map
- // TODO Remove this restriction!
- const auto ifm_shape = _ctx.at(input_index).shape().asFeature();
-
- assert(_ctx.at(weight_index).shape().rank() == 2);
- const auto num_output = _ctx.at(weight_index).shape().dim(0);
- const auto input_size = _ctx.at(weight_index).shape().dim(1);
- assert(ifm_shape.C * ifm_shape.H * ifm_shape.W == input_size);
-
- const auto bias_size = _ctx.at(bias_index).shape().asVector();
-
- // Set Shape Constraints
- _builder.addShapeConstr(output_index, ::internal::asTensorInfo(output_size));
- _builder.addShapeConstr(input_index, ::internal::asTensorInfo(ifm_shape));
- _builder.addShapeConstr(weight_index,
- ::internal::asTensorInfo(num_output /*H*/, input_size /*W*/));
- _builder.addShapeConstr(bias_index, ::internal::asTensorInfo(bias_size));
-
- // backend
- auto backend = node.lower_info()->backend();
-
- // Generate Initializers
- auto init_gen = backend.initializer_gen();
- _builder.addInitializer(weight_index, init_gen->generateWeight(node));
- _builder.addInitializer(bias_index, init_gen->generateBias(node));
-
- // Generate Stage
- auto stage_gen = backend.stage_gen();
- _builder.addStage(stage_gen->generate(node));
-}
-
-void Planner::visit(const graph::operation::Reshape::Node &node)
-{
- const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
-
- // NOTE The content of a tensor specified by shape_index should be aligned with
- // output tensor shape
- // TODO Check consistency of ouput shape
-
- // 'Feature Map' to 'Vector' reshape
- assert(_ctx.at(input_index).shape().rank() == 4);
- assert(_ctx.at(output_index).shape().rank() == 2);
- assert(_ctx.at(output_index).shape().dim(0) == 1);
-
- const auto ifm_shape = _ctx.at(input_index).shape().asFeature();
- const auto out_size = _ctx.at(output_index).shape().dim(1);
-
- // NOTE Vector element ordering issue arises when H or W is not 1
- assert(ifm_shape.H == 1);
- assert(ifm_shape.W == 1);
- assert((ifm_shape.C * ifm_shape.H * ifm_shape.W) == out_size);
-
- _builder.addShapeConstr(output_index, ::internal::asTensorInfo(out_size));
- _builder.addShapeConstr(input_index, ::internal::asTensorInfo(ifm_shape));
-
- // backend
- auto backend = node.lower_info()->backend();
-
- // Generate Stage
- auto stage_gen = backend.stage_gen();
- _builder.addStage(stage_gen->generate(node));
-}
-
-void Planner::visit(const graph::operation::Softmax::Node &node)
-{
- VERBOSE(Softmax) << "Configure SOFTMAX operation" << std::endl;
-
- const ::neurun::graph::operand::Index output_index{node.getOutputs().at(0)};
- const ::neurun::graph::operand::Index input_index{node.getInputs().at(0)};
-
- assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank());
-
- // TODO Support 'feature map' input
- assert(_ctx.at(input_index).shape().rank() == 2);
- assert(_ctx.at(input_index).shape().dim(0) == 1);
- assert(_ctx.at(input_index).shape().dim(0) == _ctx.at(output_index).shape().dim(0));
- assert(_ctx.at(input_index).shape().dim(1) == _ctx.at(output_index).shape().dim(1));
-
- const uint32_t len = _ctx.at(output_index).shape().dim(1);
-
- _builder.addShapeConstr(output_index, ::internal::asTensorInfo(len));
- _builder.addShapeConstr(input_index, ::internal::asTensorInfo(len));
-
- // backend
- auto backend = node.lower_info()->backend();
-
- // Generate Stage
- auto stage_gen = backend.stage_gen();
- _builder.addStage(stage_gen->generate(node));
-}
-
-void Planner::visit(const graph::operation::NOP::Node & /* node */)
-{
- // DO NOTHING
- // TODO : It's just for graph manipulation test now, it should be added tensor copy stage later.
-}
-
-void Planner::visit(const graph::operation::Permute::Node & /* node */) { throw "NYI"; }
-
-} // namespace codegen
-} // namespace neurun
diff --git a/runtimes/neurun/src/codegen/Planner.h b/runtimes/neurun/src/codegen/Planner.h
deleted file mode 100644
index d725567b5..000000000
--- a/runtimes/neurun/src/codegen/Planner.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 __NEURUN_CODEGEN_PLANNER_H__
-#define __NEURUN_CODEGEN_PLANNER_H__
-
-#include "graph/operation/NodeVisitor.h"
-
-namespace neurun
-{
-namespace graph
-{
-namespace operand
-{
-class Set;
-} // namespace operand
-} // namespace graph
-} // namespace neurun
-
-namespace neurun
-{
-namespace codegen
-{
-
-class IPlanBuilder;
-
-class Planner : public graph::operation::NodeVisitor
-{
-public:
- Planner(const neurun::graph::operand::Set &ctx, neurun::codegen::IPlanBuilder &builder)
- : _ctx{ctx}, _builder{builder}
- {
- }
-
-public:
- virtual void visit(const graph::operation::Conv2D::Implicit::Node &) override;
- virtual void visit(const graph::operation::MaxPool2D::Implicit::Node &) override;
- virtual void visit(const graph::operation::AvgPool2D::Implicit::Node &) override;
- virtual void visit(const graph::operation::Concat::Node &) override;
- virtual void visit(const graph::operation::Reshape::Node &) override;
- virtual void visit(const graph::operation::FullyConnected::Node &) override;
- virtual void visit(const graph::operation::Softmax::Node &) override;
- virtual void visit(const graph::operation::NOP::Node &) override;
- virtual void visit(const graph::operation::Permute::Node &) override;
-
-private:
- const neurun::graph::operand::Set &_ctx;
- neurun::codegen::IPlanBuilder &_builder;
-};
-
-} // namespace codegen
-} // namespace neurun
-
-#endif // __NEURUN_CODEGEN_PLANNER_H__
diff --git a/runtimes/neurun/src/codegen/BackendResolver.cc b/runtimes/neurun/src/compiler/BackendResolver.cc
index 4037a2813..6c1f32603 100644
--- a/runtimes/neurun/src/codegen/BackendResolver.cc
+++ b/runtimes/neurun/src/compiler/BackendResolver.cc
@@ -18,10 +18,10 @@
namespace neurun
{
-namespace codegen
+namespace compiler
{
// NOT IMPLEMENTED
-} // namespace codegen
+} // namespace compiler
} // namespace neurun
diff --git a/runtimes/neurun/src/codegen/BackendResolver.h b/runtimes/neurun/src/compiler/BackendResolver.h
index 02f22b278..4742b2d94 100644
--- a/runtimes/neurun/src/codegen/BackendResolver.h
+++ b/runtimes/neurun/src/compiler/BackendResolver.h
@@ -14,69 +14,75 @@
* limitations under the License.
*/
-#ifndef __NEURUN_CODEGEN_BACKEND_RESOLVER_H__
-#define __NEURUN_CODEGEN_BACKEND_RESOLVER_H__
+#ifndef __NEURUN_COMPILER_BACKEND_RESOLVER_H__
+#define __NEURUN_COMPILER_BACKEND_RESOLVER_H__
#include <set>
#include <unordered_map>
#include <typeindex>
-#include "logging.h"
-#include "util/EnvVar.h"
+#include "util/logging.h"
+#include "util/config/ConfigManager.h"
#include "backend/BackendManager.h"
-#include "backend/IInitializerGenerator.h"
-#include "backend/IStageGenerator.h"
+#include "backend/interface/IStageGenerator.h"
namespace neurun
{
-namespace codegen
+namespace compiler
{
class BackendResolver
{
public:
- BackendResolver(const neurun::graph::operand::Set &operands)
+ BackendResolver(const neurun::model::operand::Set &operands)
{
_backend_manager = std::make_shared<backend::BackendManager>(operands);
- const auto &backend_all_str =
- ::nnfw::util::EnvVar{std::string("OP_BACKEND_ALLOPS")}.asString("none");
+ const auto backend_all_str =
+ config::ConfigManager::instance().get<std::string>("OP_BACKEND_ALLOPS");
if (backend_all_str.compare("none") != 0)
{
VERBOSE(BackendResolver) << "Use backend for all ops: " << backend_all_str << std::endl;
-#define OP(InternalName, NnApiName) \
- { \
- auto backend = _backend_manager->get(backend_all_str); \
- _gen_map[typeid(graph::operation::InternalName::Node)] = backend; \
+#define OP(InternalName, IsNnApi, NnApiName) \
+ if (IsNnApi) \
+ { \
+ auto backend = _backend_manager->get(backend_all_str); \
+ _gen_map[typeid(model::operation::InternalName)] = backend; \
}
-#include "graph/operation/Op.lst"
+#include "model/operation/Op.lst"
#undef OP
}
else
{
-#define OP(InternalName, NnApiName) \
+#define OP(InternalName, IsNnApi, NnApiName) \
+ if (IsNnApi) \
{ \
const auto &backend_str = \
- ::nnfw::util::EnvVar{std::string("OP_BACKEND_") + #NnApiName}.asString("acl_cl"); \
+ config::ConfigManager::instance().get<std::string>("OP_BACKEND_" #NnApiName); \
auto backend = _backend_manager->get(backend_str); \
VERBOSE(BackendResolver) << "backend for " << #NnApiName << ": " << backend_str << std::endl; \
- _gen_map[typeid(graph::operation::InternalName::Node)] = backend; \
+ _gen_map[typeid(model::operation::InternalName)] = backend; \
}
-#include "graph/operation/Op.lst"
+#include "model/operation/Op.lst"
#undef OP
}
}
public:
- const backend::Backend &getBackend(const std::type_index &type) { return _gen_map[type]; }
+ const backend::Backend *getBackend(const std::type_index &type) { return _gen_map[type]; }
+ const backend::Backend *getDefaultBackend() const
+ {
+ backend::Backend *default_backend = _backend_manager->get("cpu");
+ return default_backend;
+ }
private:
- std::unordered_map<std::type_index, backend::Backend> _gen_map;
+ std::unordered_map<std::type_index, backend::Backend *> _gen_map;
std::shared_ptr<backend::BackendManager> _backend_manager;
};
-} // namespace codegen
+} // namespace compiler
} // namespace neurun
-#endif // __NEURUN_CODEGEN_BACKEND_RESOLVER_H__
+#endif // __NEURUN_COMPILER_BACKEND_RESOLVER_H__
diff --git a/runtimes/neurun/src/compiler/Compiler.cc b/runtimes/neurun/src/compiler/Compiler.cc
new file mode 100644
index 000000000..92ec69afb
--- /dev/null
+++ b/runtimes/neurun/src/compiler/Compiler.cc
@@ -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.
+ */
+
+#include "Compiler.h"
+
+#include "OperationValidator.h"
+#include "SubTensorAnalyzer.h"
+#include "PlanBuilder.h"
+#include "ConstantInitializer.h"
+
+#include "graph/dumper/Dumper.h"
+#include "graph/operation/LowerInfo.h"
+#include "dumper/dot/DotDumper.h"
+#include "linear/Linear.h"
+
+namespace neurun
+{
+
+namespace compiler
+{
+
+void Compiler::compile(void)
+{
+ auto &plan = this->plan();
+ auto &graph = plan.model();
+ const auto &operands = graph.operands();
+
+ // Disable compile phase
+ // When ready to use interpreter backend, remove this config and use backend setting
+ const auto env_disable_compile = config::ConfigManager::instance().get<bool>("DISABLE_COMPILE");
+ if (env_disable_compile)
+ {
+ plan.state(State::NOT_COMPILED);
+ return;
+ }
+
+ /***************************************************
+ * Backend independent analysis & optimization phase
+ ***************************************************/
+
+ /*************************************************************
+ * Backend independent analysis & optimization phase finished
+ *************************************************************/
+
+ // dump graph to .dot
+ neurun::dumper::dot::DotDumper dot_dumper(graph);
+ dot_dumper.dumpIfNeeded("before_lower");
+
+ // Lower: decide backend
+ graph.lower();
+ plan.state(State::LOWERED);
+
+ dot_dumper.dumpIfNeeded("after_lower");
+
+ auto linear = graph.linearize();
+ plan.state(State::LINEARIZED);
+
+ // Dump ops
+ linear->accept(neurun::graph::dumper::Dumper{});
+
+ linear->accept(OperationValidator{operands});
+
+ /*************************************************
+ * Backend dependent analysis & optimization phase
+ *************************************************/
+
+ // SubTensorInfo should be generated after lower, before stage generation and finalize
+ // because SubTensorAnalyzer assume that insert permutation is already finished
+ // lower: decide backend and insert permutation
+ // stage generation: prepare codegen to optimization
+ // finalize: generate tensor using subtensor info, then execute stage
+ // Generated SubTensorInfo is in operand(Object)
+ // for easy pass SubTensorInfo to plan builder and tensor builder
+ linear->accept(SubTensorAnalyzer{graph.operands()});
+
+ /**********************************************************
+ * Backend dependent analysis & optimization phase finished
+ **********************************************************/
+
+ /***********************
+ * Code generation phase
+ ***********************/
+
+ PlanBuilder plan_builder{plan};
+
+ // Plan building
+ linear->iterate([&](const linear::Element &element) {
+ auto backend = element.lower_info->backend();
+
+ // Generate Stage
+ auto stage_gen = backend->stage_gen();
+ plan_builder.addStage(stage_gen->generate(*element.node));
+ });
+
+ auto tensor_builders = linear->planTensors();
+
+ // TODO Add optimization passes
+ plan_builder.finalize(tensor_builders);
+
+ ConstantInitializer{graph, plan}();
+
+ /********************************
+ * Code generation phase finished
+ ********************************/
+
+ plan.state(State::COMPILED);
+}
+
+} // namespace compiler
+
+} // namespace neurun
diff --git a/runtimes/neurun/src/compiler/Compiler.h b/runtimes/neurun/src/compiler/Compiler.h
new file mode 100644
index 000000000..d8f620a10
--- /dev/null
+++ b/runtimes/neurun/src/compiler/Compiler.h
@@ -0,0 +1,73 @@
+/*
+ * 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 __NEURUN_COMPILER_COMPILE_H_
+#define __NEURUN_COMPILER_COMPILE_H_
+
+#include "graph/Graph.h"
+#include "Plan.h"
+
+namespace neurun
+{
+
+namespace compiler
+{
+
+/**
+ * @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::Graph> &model) : _plan{new Plan{model}}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return plan
+ * @return Plan
+ */
+ Plan &plan(void) { return *_plan; }
+ /**
+ * @brief Run compilation
+ */
+ void compile(void);
+ /**
+ * @brief Pass plan reference
+ * @param[out] plan Plan reference to return
+ */
+ void release(std::shared_ptr<const Plan> &plan) { plan = _plan; }
+
+private:
+ std::shared_ptr<Plan> _plan;
+};
+
+} // namespace compiler
+
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_COMPILE_H_
diff --git a/runtimes/neurun/src/compiler/ConstantInitializer.cc b/runtimes/neurun/src/compiler/ConstantInitializer.cc
new file mode 100644
index 000000000..d6d58e273
--- /dev/null
+++ b/runtimes/neurun/src/compiler/ConstantInitializer.cc
@@ -0,0 +1,188 @@
+/*
+ * 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 "ConstantInitializer.h"
+
+#include "backend/interface/operand/IObject.h"
+#include "backend/interface/IConfig.h"
+#include "backend/BackendManager.h"
+#include "model/operation/FullyConnectedNode.h"
+#include "util/feature/nhwc/Reader.h"
+#include "util/feature/nhwc/View.h"
+#include "util/feature/nchw/View.h"
+#include "misc/feature/IndexIterator.h"
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+ConstantInitializer::ConstantInitializer(const graph::Graph &graph, Plan &plan)
+ : _graph{graph}, _plan{plan}
+{
+}
+
+void ConstantInitializer::operator()()
+{
+ // Fill operand data
+ _plan.operands().iterate([&](int ind, neurun::backend::operand::IObject &obj) {
+ neurun::model::operand::Index index(ind);
+ const auto &model_obj = _graph.operands().at(index);
+
+ // For only CONSTANTS
+ if (model_obj.getUsage() != neurun::model::operand::OperandUsage::CONSTANT)
+ return;
+
+ // Only float32 is supported
+ auto type = model_obj.typeInfo().type();
+ if (type != ::neurun::model::operand::DataType::TENSOR_FLOAT32)
+ throw std::runtime_error{"Unsupported data type. Only TENSOR_FLOAT32 is supported."};
+
+ VERBOSE(FillOperandData) << "Fill data for operand " << ind << std::endl;
+
+ auto layout =
+ model_obj.lower_info()->def_backends().getOnlyElement()->config()->getOperandLayout();
+ const auto shape = model_obj.shape();
+ auto base = reinterpret_cast<const float *>(model_obj.data().base());
+ auto size = model_obj.data().size();
+
+ obj.access([&](::neurun::backend::operand::ITensor &tensor) {
+ switch (shape.rank())
+ {
+ case 1:
+ {
+ auto vec_size = shape.asVector();
+ for (int32_t n = 0; n < vec_size; ++n)
+ {
+ const float *from = reinterpret_cast<const float *>(base) + n;
+ const auto value = *from;
+
+ float *into = reinterpret_cast<float *>(tensor.buffer()) + n;
+
+ *into = value;
+ }
+ break;
+ }
+ case 2:
+ {
+ // NOTE This is a WORKAROUND which supports FullyConnected weight only
+ // For FullyConnected, we must know the IFM shape to deduce 2D weight shape from 4D
+ // IFM.
+ // This is because of NHWC/NCHW layout, the order of mapping will be different.
+ // TODO Support general case - explicitly insert Reshape op for IFM as 2D
+
+ // Find corresponding FullyConnected IFM
+ auto operation_index = _graph.operands().at(index).getUses().list().front();
+ auto operation = &_graph.operations().at(operation_index);
+ auto fc_operation =
+ dynamic_cast<const neurun::model::operation::FullyConnectedNode *>(operation);
+
+ if (fc_operation == nullptr)
+ break;
+
+ auto ifm_index = fc_operation->getInputs().at(
+ neurun::model::operation::FullyConnectedNode::Input::INPUT);
+ const auto &ifm = _graph.operands().at(ifm_index);
+ const auto ifm_shape = ifm.shape().asFeature();
+ const auto num_output = shape.dim(0);
+
+ const ::nnfw::misc::feature::Shape ker_shape{num_output, ifm_shape.C, ifm_shape.H,
+ ifm_shape.W};
+ const util::feature::nhwc::Reader<float> from{ker_shape, base, size};
+
+ if (layout == neurun::graph::operand::Layout::NHWC)
+ {
+ ::nnfw::misc::feature::iterate(ker_shape)
+ << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(nth, ch, row, col);
+
+ uint32_t offset = 0;
+
+ // NNAPI uses NHWC ordering
+ offset += nth * ifm_shape.H * ifm_shape.W * ifm_shape.C;
+ offset += row * ifm_shape.W * ifm_shape.C;
+ offset += col * ifm_shape.C;
+ offset += ch;
+
+ float *into = reinterpret_cast<float *>(tensor.buffer()) + offset;
+
+ *into = value;
+ };
+ }
+ else
+ {
+ assert(layout == neurun::graph::operand::Layout::NCHW);
+
+ ::nnfw::misc::feature::iterate(ker_shape)
+ << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(nth, ch, row, col);
+
+ uint32_t offset = 0;
+
+ // 'NCHW' ordering
+ offset += nth * ifm_shape.C * ifm_shape.H * ifm_shape.W;
+ offset += ch * ifm_shape.H * ifm_shape.W;
+ offset += row * ifm_shape.W;
+ offset += col;
+
+ float *into = reinterpret_cast<float *>(tensor.buffer()) + offset;
+
+ *into = value;
+ };
+ }
+
+ break;
+ }
+ case 4:
+ {
+ auto ker_shape = shape.asFeature();
+ auto from = util::feature::nhwc::Reader<float>{ker_shape, base, size};
+
+ if (layout == neurun::graph::operand::Layout::NHWC)
+ {
+ auto into = util::feature::nhwc::View<float>{
+ ker_shape, reinterpret_cast<float *>(tensor.buffer()), size};
+
+ ::nnfw::misc::feature::iterate(ker_shape)
+ << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(nth, ch, row, col);
+ into.at(nth, ch, row, col) = value;
+ };
+ }
+ else
+ {
+ assert(layout == neurun::graph::operand::Layout::NCHW);
+
+ auto into = util::feature::nchw::View<float>{&tensor};
+
+ ::nnfw::misc::feature::iterate(ker_shape)
+ << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(nth, ch, row, col);
+ into.at(nth, ch, row, col) = value;
+ };
+ }
+ break;
+ }
+ default:
+ throw std::runtime_error{"Not yet supported"};
+ }
+ });
+ });
+}
+
+} // namespace codegen
+} // namespace neurun
diff --git a/runtimes/neurun/src/compiler/ConstantInitializer.h b/runtimes/neurun/src/compiler/ConstantInitializer.h
new file mode 100644
index 000000000..7d9231908
--- /dev/null
+++ b/runtimes/neurun/src/compiler/ConstantInitializer.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 __NEURUN_COMPILER_CONSTANT_INITIALIZER_H__
+#define __NEURUN_COMPILER_CONSTANT_INITIALIZER_H__
+
+#include "graph/Graph.h"
+#include "Plan.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+class ConstantInitializer
+{
+public:
+ ConstantInitializer(const graph::Graph &graph, Plan &plan);
+
+ void operator()();
+
+private:
+ const graph::Graph &_graph;
+ Plan &_plan;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_CONSTANT_INITIALIZER_H__
diff --git a/runtimes/neurun/src/compiler/OperationValidator.cc b/runtimes/neurun/src/compiler/OperationValidator.cc
new file mode 100644
index 000000000..0110eccb8
--- /dev/null
+++ b/runtimes/neurun/src/compiler/OperationValidator.cc
@@ -0,0 +1,121 @@
+/*
+ * 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 <typeinfo>
+
+#include "model/operand/Set.h"
+#include "graph/operation/LowerInfo.h"
+
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+void OperationValidator::visit(const model::operation::Conv2DNode &)
+{
+ // DO NOTHING
+}
+
+void OperationValidator::visit(const model::operation::MaxPool2DNode &)
+{
+ // DO NOTHING
+}
+
+void OperationValidator::visit(const model::operation::AvgPool2DNode &)
+{
+ // DO NOTHING
+}
+
+void OperationValidator::visit(const model::operation::ConcatNode &node)
+{
+ (void)node; // NOTE To prevent from unused variable warning
+
+ // NOTE This implementation assumes concat over feature depth
+ // TODO Remove this assumption
+ assert(_ctx.at(::neurun::model::operand::Index{node.param().axis_index}).asScalar<int32_t>() ==
+ 3);
+}
+
+void OperationValidator::visit(const model::operation::FullyConnectedNode &)
+{
+ // DO NOTHING
+}
+
+void OperationValidator::visit(const model::operation::ReshapeNode &node)
+{
+ (void)node; // NOTE To prevent from unused variable warning
+
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ // NOTE The content of a tensor specified by shape_index should be aligned with
+ // output tensor shape
+ // TODO Check consistency of ouput shape
+
+ // 'Feature Map' to 'Vector' reshape
+ assert(_ctx.at(input_index).shape().rank() == 4);
+ assert(_ctx.at(output_index).shape().rank() == 2);
+ assert(_ctx.at(output_index).shape().dim(0) == 1);
+
+ // NOTE Vector element ordering issue arises when H or W is not 1
+ assert(_ctx.at(input_index).shape().dim(1) == 1); // H
+ assert(_ctx.at(input_index).shape().dim(2) == 1); // W
+ // input(4D)'s C * H * W == output(2D)'s W
+ assert((_ctx.at(input_index).shape().dim(3) * _ctx.at(input_index).shape().dim(1) *
+ _ctx.at(input_index).shape().dim(2)) == _ctx.at(output_index).shape().dim(1));
+}
+
+void OperationValidator::visit(const model::operation::SoftmaxNode &node)
+{
+ (void)node; // NOTE To prevent from unused variable warning
+
+ VERBOSE(Softmax) << "Configure SOFTMAX operation" << std::endl;
+
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank());
+
+ // TODO Support 'feature map' input
+ assert(_ctx.at(input_index).shape().rank() == 2);
+ assert(_ctx.at(input_index).shape().dim(0) == 1);
+ assert(_ctx.at(input_index).shape().dim(0) == _ctx.at(output_index).shape().dim(0));
+ assert(_ctx.at(input_index).shape().dim(1) == _ctx.at(output_index).shape().dim(1));
+}
+
+void OperationValidator::visit(const model::operation::PermuteNode &node)
+{
+ (void)node; // NOTE To prevent from unused variable warning
+
+ VERBOSE(Permute) << "Configure Permute operation" << std::endl;
+
+ const auto output_index{node.getOutputs().at(0)};
+ const auto input_index{node.getInputs().at(0)};
+
+ assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank());
+}
+
+void OperationValidator::visit(const model::operation::AddNode &)
+{
+ // DO NOTHING
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtimes/neurun/src/compiler/OperationValidator.h b/runtimes/neurun/src/compiler/OperationValidator.h
new file mode 100644
index 000000000..f4ed533ed
--- /dev/null
+++ b/runtimes/neurun/src/compiler/OperationValidator.h
@@ -0,0 +1,56 @@
+/*
+ * 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 __NEURUN_COMPILER_OPERATION_VALIDATOR_H__
+#define __NEURUN_COMPILER_OPERATION_VALIDATOR_H__
+
+#include "model/operation/NodeVisitor.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operand
+{
+class Set;
+} // namespace operand
+} // namespace graph
+} // namespace neurun
+
+namespace neurun
+{
+namespace compiler
+{
+
+class OperationValidator : public model::operation::NodeVisitor
+{
+public:
+ OperationValidator(const neurun::model::operand::Set &ctx) : _ctx{ctx} {}
+
+public:
+#define OP(InternalName, IsNnApi, NnApiName) \
+ virtual void visit(const model::operation::InternalName &) override;
+#include "model/operation/Op.lst"
+#undef OP
+
+private:
+ const neurun::model::operand::Set &_ctx;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_OPERATION_VALIDATOR_H__
diff --git a/runtimes/neurun/src/codegen/Plan.cc b/runtimes/neurun/src/compiler/Plan.cc
index b7637b189..b7637b189 100644
--- a/runtimes/neurun/src/codegen/Plan.cc
+++ b/runtimes/neurun/src/compiler/Plan.cc
diff --git a/runtimes/neurun/src/codegen/Plan.h b/runtimes/neurun/src/compiler/Plan.h
index 47624ed35..f2a526e0e 100644
--- a/runtimes/neurun/src/codegen/Plan.h
+++ b/runtimes/neurun/src/compiler/Plan.h
@@ -18,18 +18,27 @@
#define __NEURUN_CODEGEN_PLAN_H__
#include "graph/Graph.h"
-#include "codegen/operand/Context.h"
-#include "codegen/operation/Sequence.h"
+#include "compiler/operand/Context.h"
+#include "compiler/operation/Sequence.h"
namespace neurun
{
-namespace codegen
+namespace compiler
{
+enum class State
+{
+ NONE, // Initial state
+ LOWERED, // Backend is decided
+ LINEARIZED, // Everything is moved to Linear object so this Graph object is no longer effective
+ COMPILED, // Success compilation
+ NOT_COMPILED // Not compiled by environment or graph status
+};
+
class Plan
{
public:
- Plan(const std::shared_ptr<neurun::graph::Graph> &model) : _model(model)
+ Plan(const std::shared_ptr<neurun::graph::Graph> &model) : _model(model), _state(State::NONE)
{
// DO NOTHING
}
@@ -38,6 +47,9 @@ public:
neurun::graph::Graph &model(void) { return *_model; }
const neurun::graph::Graph &model(void) const { return *_model; }
+ void state(State state) { _state = state; }
+ State state(void) const { return _state; }
+
public:
operand::Context &operands(void) { return _operands; }
const operand::Context &operands(void) const { return _operands; }
@@ -50,9 +62,10 @@ private:
std::shared_ptr<neurun::graph::Graph> _model;
operand::Context _operands;
operation::Sequence _ops;
+ State _state;
};
-} // namespace codegen
+} // namespace compiler
} // namespace neurun
#endif // __NEURUN_CODEGEN_PLAN_H__
diff --git a/runtimes/neurun/src/codegen/PlanBuilder.cc b/runtimes/neurun/src/compiler/PlanBuilder.cc
index 5d4d6f9c9..8ef3fedbf 100644
--- a/runtimes/neurun/src/codegen/PlanBuilder.cc
+++ b/runtimes/neurun/src/compiler/PlanBuilder.cc
@@ -16,31 +16,29 @@
#include "PlanBuilder.h"
+#include "backend/interface/operand/IObject.h"
+
namespace neurun
{
-namespace codegen
-{
-
-void PlanBuilder::addShapeConstr(const ::neurun::graph::operand::Index &ind,
- const ::arm_compute::TensorInfo &info)
+namespace compiler
{
- _tensor_info_ctx[ind.asInt()] = info;
-}
-
-void PlanBuilder::addInitializer(const ::neurun::graph::operand::Index &ind,
- const Initializer &initializer)
-{
- _initializer_ctx[ind.asInt()] = initializer;
-}
void PlanBuilder::addStage(const Stage &stage) { _stages.emplace_back(stage); }
void PlanBuilder::finalize(const backend::TensorBuilderSet &tensor_builders)
{
+ auto &operands = _plan.operands();
+
// Prepare tensors
for (auto &tensor_builder : tensor_builders)
{
- tensor_builder->prepare(_plan, _tensor_info_ctx);
+ tensor_builder->prepare();
+
+ // Wrap tensors as Object and store them to plan
+ tensor_builder->iterate([&](const model::operand::Index &index) {
+ auto object = tensor_builder->wrapTensor(index);
+ operands.set(index, object);
+ });
}
// Process Stage
@@ -51,25 +49,12 @@ void PlanBuilder::finalize(const backend::TensorBuilderSet &tensor_builders)
stage(execution_builder);
}
- // TODO Add code for CPU/ACL tensor allocation
// Allocate Tensor Memory for cl_tensors
for (auto &tensor_builder : tensor_builders)
{
tensor_builder->allocate();
}
-
- // Fill weight/bias
- for (auto it = _initializer_ctx.begin(); it != _initializer_ctx.end(); ++it)
- {
- const ::neurun::graph::operand::Index operand_index{it->first};
- auto objects = _plan.operands().at(operand_index);
-
- for (auto object : objects)
- {
- object->access(it->second);
- }
- }
}
-} // namepsace codegen
+} // namepsace compiler
} // namespace neurun
diff --git a/runtimes/neurun/src/compiler/PlanBuilder.h b/runtimes/neurun/src/compiler/PlanBuilder.h
new file mode 100644
index 000000000..3231906d2
--- /dev/null
+++ b/runtimes/neurun/src/compiler/PlanBuilder.h
@@ -0,0 +1,72 @@
+/*
+ * 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 __NEURUN_COMPILER_PLAN_BUILDER_H__
+#define __NEURUN_COMPILER_PLAN_BUILDER_H__
+
+#include "Plan.h"
+#include "backend/interface/IStageGenerator.h"
+#include "backend/interface/ITensorBuilder.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+class ExecutionBuilder final : public IExecutionBuilder
+{
+public:
+ ExecutionBuilder(Plan &plan) : _plan{plan}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void append(std::unique_ptr<::neurun::exec::IFunction> &&f) override
+ {
+ _plan.operations().append(std::move(f));
+ }
+
+private:
+ Plan &_plan;
+};
+
+class PlanBuilder
+{
+public:
+ PlanBuilder(Plan &plan) : _plan{plan}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void addStage(const Stage &stage);
+
+public:
+ // TODO Remove the argument `tensor_builders`
+ void finalize(const backend::TensorBuilderSet &tensor_builders);
+
+private:
+ Plan &_plan;
+
+private:
+ std::vector<Stage> _stages;
+};
+
+} // namepsace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_PLAN_BUILDER_H__
diff --git a/runtimes/neurun/src/compiler/SubTensorAnalyzer.cc b/runtimes/neurun/src/compiler/SubTensorAnalyzer.cc
new file mode 100644
index 000000000..0851b7991
--- /dev/null
+++ b/runtimes/neurun/src/compiler/SubTensorAnalyzer.cc
@@ -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.
+ */
+
+#include "SubTensorAnalyzer.h"
+
+#include <typeinfo>
+
+#include "cpp14/memory.h"
+#include "model/operand/Set.h"
+#include "graph/operation/LowerInfo.h"
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+void SubTensorAnalyzer::visit(const model::operation::ConcatNode &node)
+{
+ // If operator is concat (or other operators related with subsumption), fill subsumption info
+ // TODO: if one tensor is subset of many parents or model input
+ // Solution 1. Handle 1st parent only, ignore others (need to invert for other childrun)
+ // Solution 2. Insert copy operation for other parents
+ auto axis_index = node.param().axis_index;
+
+ // To prepare concat elimination, axis should be constant
+ if (_ctx.at(axis_index).getUsage() != model::operand::OperandUsage::CONSTANT)
+ {
+ VERBOSE(SUBTENSOR) << "Cannot handle non-constant axis" << std::endl;
+ return;
+ }
+
+ // NOTE This implementation assumes concat over feature depth
+ // TODO Remove this assumption
+ int32_t axis = _ctx.at(axis_index).asScalar<int32_t>();
+ if (axis != 3)
+ {
+ VERBOSE(SUBTENSOR) << "Cannot handle axis is not channel" << std::endl;
+ return;
+ }
+
+ auto &output_index = node.getOutputs().at(0);
+ auto &inputs = node.getInputs();
+
+ int32_t axis_point = 0;
+ for (auto &input_index : inputs)
+ {
+ auto input_shape_4D = _ctx.at(input_index).lower_info()->shape();
+ std::vector<int32_t> offset = {0, 0, 0, 0};
+ offset[axis] = axis_point;
+ neurun::util::feature::Coordinate4D coordinate_info(offset[0], offset[1], offset[2], offset[3]);
+ std::unique_ptr<graph::operand::ParentInfo> parentInfo =
+ nnfw::cpp14::make_unique<graph::operand::ParentInfo>(output_index, coordinate_info);
+
+ // NOTD Not support multiple parent tensor yet
+ assert(_ctx.at(input_index).parent_info() == nullptr);
+ _ctx.at(input_index).parent_info(std::move(parentInfo));
+
+ // NOTE Only support when axis is 3(channel)
+ axis_point += input_shape_4D.c();
+ }
+}
+
+} // namespace compiler
+} // namespace neurun
diff --git a/runtimes/neurun/src/compiler/SubTensorAnalyzer.h b/runtimes/neurun/src/compiler/SubTensorAnalyzer.h
new file mode 100644
index 000000000..ddfd10263
--- /dev/null
+++ b/runtimes/neurun/src/compiler/SubTensorAnalyzer.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.
+ */
+
+/**
+ * @file SubTensorAnalyzer.h
+ * @brief This file contains SubTensorAnalyzer to analyze tensor subsumption
+ * using operation visitor
+ */
+
+#ifndef __NEURUN_COMPILER_SUBTENSOR_ANALYZER_H__
+#define __NEURUN_COMPILER_SUBTENSOR_ANALYZER_H__
+
+#include "model/operation/NodeVisitor.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operand
+{
+class Set;
+} // namespace operation
+} // namespace graph
+} // namespace neurun
+
+namespace neurun
+{
+namespace compiler
+{
+
+/**
+ * @brief Class to analyze tensor subsumption
+ */
+class SubTensorAnalyzer : public model::operation::NodeVisitor
+{
+public:
+ /**
+ * @brief Construct a new SubTensorAnalyzer object
+ * @param[in] ctx Graph operand set
+ */
+ SubTensorAnalyzer(neurun::model::operand::Set &ctx) : _ctx{ctx} {}
+
+public:
+ virtual void visit(const model::operation::ConcatNode &) override;
+
+private:
+ neurun::model::operand::Set &_ctx;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_SUBTENSOR_ANALYZER_H__
diff --git a/runtimes/neurun/src/compiler/SubTensorInfo.h b/runtimes/neurun/src/compiler/SubTensorInfo.h
new file mode 100644
index 000000000..c0fb857d0
--- /dev/null
+++ b/runtimes/neurun/src/compiler/SubTensorInfo.h
@@ -0,0 +1,84 @@
+/*
+ * 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 SubTensorInfo.h
+ * @brief This file contains SubTensorInfo to represent subsumption between tensors
+ * for backend tensor allocation
+ */
+#ifndef __NEURUN_COMPILER_SUBTENSOR_INFO_H__
+#define __NEURUN_COMPILER_SUBTENSOR_INFO_H__
+
+#include "model/operand/Object.h"
+#include "util/feature/Coordinate4D.h"
+
+namespace neurun
+{
+namespace compiler
+{
+
+/**
+ * @brief Class to represent information of subtensor
+ */
+class SubTensorInfo
+{
+public:
+ SubTensorInfo() = delete;
+
+ /**
+ * @brief Construct a new SubTensorInfo object
+ * @param[in] obj SubTensor object
+ */
+ SubTensorInfo(const model::operand::Object &obj)
+ : _parent{obj.parent_info()->parent()}, _shape{obj.shape()}, _type{obj.typeInfo()},
+ _offset{obj.parent_info()->offset()}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return parent tensor index
+ * @return Parent tensor index
+ */
+ const model::operand::Index parent(void) const { return _parent; }
+ /**
+ * @brief Return tensor shape
+ * @return Tensor shape
+ */
+ const model::operand::Shape shape(void) const { return _shape; }
+ /**
+ * @brief Return tensor type
+ * @return Tensor type
+ */
+ const model::operand::TypeInfo type(void) const { return _type; }
+ /**
+ * @brief Return tensor's offset in parent tensor
+ * @return Tensor offset
+ */
+ const neurun::util::feature::Coordinate4D offset(void) const { return _offset; }
+
+private:
+ const model::operand::Index _parent;
+ const model::operand::Shape _shape;
+ const model::operand::TypeInfo _type;
+ const neurun::util::feature::Coordinate4D _offset;
+};
+
+} // compiler
+} // neurun
+
+#endif // __NEURUN_COMPILER_SUBTENSOR_INFO_H__
diff --git a/runtimes/neurun/src/compiler/TensorInfo.h b/runtimes/neurun/src/compiler/TensorInfo.h
new file mode 100644
index 000000000..787c433e5
--- /dev/null
+++ b/runtimes/neurun/src/compiler/TensorInfo.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 __NEURUN_COMPILER_TENSOR_INFO_H__
+#define __NEURUN_COMPILER_TENSOR_INFO_H__
+
+#include "model/operand/Shape.h"
+#include "model/operand/TypeInfo.h"
+
+#include <numeric>
+
+namespace neurun
+{
+namespace compiler
+{
+
+class TensorInfo
+{
+public:
+ TensorInfo() = default;
+
+public:
+ TensorInfo(const ::neurun::model::operand::Shape &shape,
+ const ::neurun::model::operand::TypeInfo &typeInfo)
+ : _shape(shape), _typeInfo(typeInfo)
+ {
+ // DO NOTHING
+ }
+
+public:
+ const ::neurun::model::operand::Shape &shape() const { return _shape; }
+ const ::neurun::model::operand::TypeInfo &typeInfo() const { return _typeInfo; }
+ size_t total_size() const
+ {
+ const auto &dims = _shape.dims();
+ return std::accumulate(dims.begin(), dims.end(), 4, std::multiplies<size_t>());
+ }
+
+private:
+ ::neurun::model::operand::Shape _shape;
+ ::neurun::model::operand::TypeInfo _typeInfo;
+};
+
+} // namespace compiler
+} // namespace neurun
+
+#endif // __NEURUN_COMPILER_TENSOR_INFO_H__
diff --git a/runtimes/neurun/src/codegen/operand/Context.cc b/runtimes/neurun/src/compiler/operand/Context.cc
index 7e5cdeccf..3fa529995 100644
--- a/runtimes/neurun/src/codegen/operand/Context.cc
+++ b/runtimes/neurun/src/compiler/operand/Context.cc
@@ -16,20 +16,32 @@
#include "Context.h"
+#include <cassert>
+
namespace neurun
{
-namespace codegen
+namespace compiler
{
namespace operand
{
-Context &Context::set(const graph::operand::Index &id,
+Context &Context::set(const model::operand::Index &id,
const std::shared_ptr<backend::operand::IObject> &object)
{
- _objects[id.value()].emplace_back(object);
+ // Only one object for an id
+ assert(_objects.find(id.value()) == _objects.end());
+ _objects[id.value()] = object;
return (*this);
}
+void Context::iterate(const std::function<void(int, backend::operand::IObject &)> &fn)
+{
+ for (auto &e : _objects)
+ {
+ fn(e.first, *e.second);
+ }
+}
+
} // namespace operand
-} // namespace codegen
+} // namespace compiler
} // namespace neurun
diff --git a/runtimes/neurun/src/codegen/operand/Context.h b/runtimes/neurun/src/compiler/operand/Context.h
index 386c253c6..bc558404e 100644
--- a/runtimes/neurun/src/codegen/operand/Context.h
+++ b/runtimes/neurun/src/compiler/operand/Context.h
@@ -14,17 +14,18 @@
* limitations under the License.
*/
-#ifndef __NEURUN_CODEGEN_OPERAND_CONTEXT_H__
-#define __NEURUN_CODEGEN_OPERAND_CONTEXT_H__
+#ifndef __NEURUN_COMPILER_OPERAND_CONTEXT_H__
+#define __NEURUN_COMPILER_OPERAND_CONTEXT_H__
-#include "backend/IObject.h"
-#include "graph/operand/Index.h"
+#include "backend/interface/operand/IObject.h"
+#include "model/operand/Index.h"
#include <map>
+#include <memory>
namespace neurun
{
-namespace codegen
+namespace compiler
{
namespace operand
{
@@ -32,33 +33,34 @@ namespace operand
class Context
{
public:
- Context &set(const graph::operand::Index &ind,
+ Context &set(const model::operand::Index &ind,
const std::shared_ptr<backend::operand::IObject> &object);
public:
- bool exist(const ::neurun::graph::operand::Index &ind) const
+ bool exist(const ::neurun::model::operand::Index &ind) const
{
return _objects.find(ind.asInt()) != _objects.end();
}
public:
- const std::vector<std::shared_ptr<backend::operand::IObject>> &
- at(const graph::operand::Index &ind) const
+ std::shared_ptr<backend::operand::IObject> at(const model::operand::Index &ind) const
{
return _objects.at(ind.asInt());
}
- std::vector<std::shared_ptr<backend::operand::IObject>> &at(const graph::operand::Index &ind)
+ std::shared_ptr<backend::operand::IObject> &at(const model::operand::Index &ind)
{
return _objects.at(ind.asInt());
}
+ void iterate(const std::function<void(int, backend::operand::IObject &)> &fn);
+
private:
- std::map<int, std::vector<std::shared_ptr<backend::operand::IObject>>> _objects;
+ std::map<int, std::shared_ptr<backend::operand::IObject>> _objects;
};
} // namespace operand
-} // namespace codegen
+} // namespace compiler
} // namespace neurun
-#endif // __NEURUN_CODEGEN_OPERAND_CONTEXT_H__
+#endif // __NEURUN_COMPILER_OPERAND_CONTEXT_H__
diff --git a/runtimes/neurun/src/codegen/operation/Sequence.cc b/runtimes/neurun/src/compiler/operation/Sequence.cc
index 908e84a5c..3160e04b6 100644
--- a/runtimes/neurun/src/codegen/operation/Sequence.cc
+++ b/runtimes/neurun/src/compiler/operation/Sequence.cc
@@ -18,7 +18,7 @@
namespace neurun
{
-namespace codegen
+namespace compiler
{
namespace operation
{
@@ -26,5 +26,5 @@ namespace operation
// NO IMPLEMENTATION YET
} // namespace operation
-} // namespace codegen
+} // namespace compiler
} // namespace neurun
diff --git a/runtimes/neurun/src/codegen/operation/Sequence.h b/runtimes/neurun/src/compiler/operation/Sequence.h
index 83403feae..d69cfcfe3 100644
--- a/runtimes/neurun/src/codegen/operation/Sequence.h
+++ b/runtimes/neurun/src/compiler/operation/Sequence.h
@@ -14,17 +14,16 @@
* limitations under the License.
*/
-#ifndef __NEURUN_CODEGEN_OPERATION_SEQUENCE_H__
-#define __NEURUN_CODEGEN_OPERATION_SEQUENCE_H__
-
+#ifndef __NEURUN_COMPILER_OPERATION_SEQUENCE_H__
+#define __NEURUN_COMPILER_OPERATION_SEQUENCE_H__
#include <stdint.h>
-#include <arm_compute/runtime/IFunction.h>
+#include "exec/interface/IFunction.h"
#include <memory>
#include <vector>
namespace neurun
{
-namespace codegen
+namespace compiler
{
namespace operation
{
@@ -35,21 +34,21 @@ public:
uint32_t size(void) const { return _functions.size(); }
public:
- Sequence &append(std::unique_ptr<::arm_compute::IFunction> &&func)
+ Sequence &append(std::unique_ptr<::neurun::exec::IFunction> &&func)
{
_functions.emplace_back(std::move(func));
return (*this);
}
public:
- ::arm_compute::IFunction &at(uint32_t n) const { return *(_functions.at(n)); }
+ ::neurun::exec::IFunction &at(uint32_t n) const { return *(_functions.at(n)); }
private:
- std::vector<std::unique_ptr<::arm_compute::IFunction>> _functions;
+ std::vector<std::unique_ptr<::neurun::exec::IFunction>> _functions;
};
} // namespace operation
-} // namespace codegen
+} // namespace compiler
} // namespace neurun
-#endif // __NEURUN_CODEGEN_OPERATION_SEQUENCE_H__
+#endif // __NEURUN_COMPILER_OPERATION_SEQUENCE_H__
diff --git a/runtimes/neurun/src/dumper/dot/DotBuilder.cc b/runtimes/neurun/src/dumper/dot/DotBuilder.cc
new file mode 100644
index 000000000..d694323b4
--- /dev/null
+++ b/runtimes/neurun/src/dumper/dot/DotBuilder.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 "DotBuilder.h"
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+// NodeAttr
+NodeAttr &NodeAttr::addAttr(const std::string &name, const std::string &attr)
+{
+ _attrs.emplace_back(name, attr);
+
+ return *this;
+}
+
+void NodeAttr::finish()
+{
+ _attr_stream << "[";
+ for (auto attr : _attrs)
+ {
+ _attr_stream << attr.first << "="
+ << "\"" << attr.second << "\" ";
+ }
+ _attr_stream << "];\n";
+}
+
+// DotDumper
+DotBuilder::DotBuilder() {}
+
+void DotBuilder::update(const IDotInfo &node_info)
+{
+ addNode(node_info);
+ for (auto child : node_info.children())
+ {
+ addEdge(node_info, *child);
+ }
+}
+
+void DotBuilder::writeDot(std::ostream &os)
+{
+ os << "digraph D {\n"
+ << _dot.str() << "\n"
+ << "}\n";
+}
+
+void DotBuilder::addNode(const IDotInfo &dotinfo)
+{
+ NodeAttr attr;
+ attr.addAttr("shape", dotinfo.dot_shape())
+ .addAttr("label", dotinfo.label())
+ .addAttr("style", "filled")
+ .addAttr("colorscheme", dotinfo.bg_color_scheme())
+ .addAttr("fillcolor", dotinfo.bg_color());
+
+ attr.finish();
+
+ _dot << dotinfo.index_str() << attr.attr_stream();
+}
+
+void DotBuilder::addEdge(const IDotInfo &dotinfo1, const IDotInfo &dotinfo2)
+{
+ _dot << dotinfo1.index_str() << " -> " << dotinfo2.index_str() << ";\n";
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
diff --git a/runtimes/neurun/src/dumper/dot/DotBuilder.h b/runtimes/neurun/src/dumper/dot/DotBuilder.h
new file mode 100644
index 000000000..783e92b80
--- /dev/null
+++ b/runtimes/neurun/src/dumper/dot/DotBuilder.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.
+ */
+
+#ifndef __NEURUN_DUMPER_DOT_DOT_BUILDER_H__
+#define __NEURUN_DUMPER_DOT_DOT_BUILDER_H__
+
+#include <sstream>
+
+#include "model/operation/Index.h"
+#include "model/operand/Index.h"
+
+#include "model/operation/Node.h"
+#include "model/operand/Object.h"
+
+#include "DotNodeInfo.h"
+#include "DotOperandInfo.h"
+
+using Node = neurun::model::operation::Node;
+using Object = neurun::model::operand::Object;
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+class NodeAttr
+{
+public:
+ NodeAttr() = default;
+
+public:
+ void finish();
+ NodeAttr &addAttr(const std::string &name, const std::string &attr);
+
+public:
+ std::stringbuf *attr_stream() { return _attr_stream.rdbuf(); }
+
+private:
+ std::vector<std::pair<std::string, std::string>> _attrs;
+ std::stringstream _attr_stream;
+};
+
+class DotBuilder
+{
+public:
+ DotBuilder();
+
+public:
+ void update(const IDotInfo &dotinfo);
+
+ void writeDot(std::ostream &os);
+
+private:
+ void addNode(const IDotInfo &dotinfo);
+ void addEdge(const IDotInfo &dotinfo1, const IDotInfo &dotinfo2);
+
+ std::stringstream _dot;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
+
+#endif // __NEURUN_DUMPER_DOT_DOT_BUILDER_H__
diff --git a/runtimes/neurun/src/dumper/dot/DotDumper.cc b/runtimes/neurun/src/dumper/dot/DotDumper.cc
new file mode 100644
index 000000000..1e53ece19
--- /dev/null
+++ b/runtimes/neurun/src/dumper/dot/DotDumper.cc
@@ -0,0 +1,115 @@
+/*
+ * 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 <fstream>
+
+#include "DotDumper.h"
+#include "DotBuilder.h"
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+using namespace neurun::graph;
+
+void DotDumper::dumpIfNeeded(const std::string &tag)
+{
+ if (_option == OPTIONS::DUMP_OFF)
+ {
+ return;
+ }
+ neurun::dumper::dot::DotBuilder dot_builder;
+
+ auto &operations = _graph.operations();
+ auto &operands = _graph.operands();
+
+ operations.iterate([&](const model::operation::Index &index, const model::operation::Node &node) {
+ neurun::dumper::dot::DotNodeInfo node_info(_graph, index, node);
+
+ for (auto output : node.getOutputs())
+ {
+ using neurun::dumper::dot::DotOperandInfo;
+ auto child = std::make_shared<DotOperandInfo>(output, operands.at(output),
+ DotOperandInfo::Type::MODEL_OUTPUT);
+ node_info.appendChild(child);
+ }
+
+ dot_builder.update(node_info);
+ });
+
+ operands.iterate([&](const model::operand::Index &index, const model::operand::Object &object) {
+ bool showing_cond = false;
+ auto usage = object.getUsage();
+ if (_option == OPTIONS::SHOW_CONSTANTS)
+ {
+ showing_cond = object.usageIsDefined();
+ }
+ else
+ {
+ showing_cond = (usage == model::operand::OperandUsage::MODEL_INPUT) ||
+ (usage == model::operand::OperandUsage::OPERATION_OUTPUT);
+ }
+ if (usage != model::operand::OperandUsage::OPERATION_OUTPUT)
+ {
+ showing_cond = showing_cond && (object.getUses().size() > 0);
+ }
+ if (showing_cond)
+ {
+ auto type = [&]() {
+ using neurun::dumper::dot::DotOperandInfo;
+ if (_graph.getInputs().contains(index))
+ return DotOperandInfo::Type::MODEL_INPUT;
+ if (_graph.getOutputs().contains(index))
+ return DotOperandInfo::Type::MODEL_OUTPUT;
+ return DotOperandInfo::Type::INTERNAL;
+ }();
+
+ neurun::dumper::dot::DotOperandInfo operand_info(index, object, type);
+
+ for (auto operation_index : object.getUses().list())
+ {
+ auto &node = operations.at(operation_index);
+ auto child =
+ std::make_shared<neurun::dumper::dot::DotNodeInfo>(_graph, operation_index, node);
+ operand_info.appendChild(child);
+ }
+
+ dot_builder.update(operand_info);
+ }
+ });
+
+ // 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 neurun
diff --git a/runtimes/neurun/src/dumper/dot/DotDumper.h b/runtimes/neurun/src/dumper/dot/DotDumper.h
new file mode 100644
index 000000000..0c0a9b8df
--- /dev/null
+++ b/runtimes/neurun/src/dumper/dot/DotDumper.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.
+ */
+
+#include "graph/Graph.h"
+#include "util/config/ConfigManager.h"
+
+#ifndef __NEURUN_DUMPER_DOT_DOT_DUMPER_H__
+#define __NEURUN_DUMPER_DOT_DOT_DUMPER_H__
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+enum OPTIONS
+{
+ DUMP_OFF = 0, // Don't dump
+ DEFAULT = 1, // Show default dot graph
+ SHOW_CONSTANTS // Show dot graph with input constants
+};
+
+class DotDumper
+{
+public:
+ DotDumper(const neurun::graph::Graph &graph) : _graph(graph)
+ {
+ _option = config::ConfigManager::instance().get<int>("GRAPH_DOT_DUMP");
+ }
+
+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 dumpIfNeeded(const std::string &tag);
+
+private:
+ const neurun::graph::Graph &_graph;
+ uint32_t _option;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
+
+#endif // __NEURUN_DUMPER_DOT_DOT_DUMPER_H__
diff --git a/runtimes/neurun/src/dumper/dot/DotNodeInfo.cc b/runtimes/neurun/src/dumper/dot/DotNodeInfo.cc
new file mode 100644
index 000000000..aefe12e2a
--- /dev/null
+++ b/runtimes/neurun/src/dumper/dot/DotNodeInfo.cc
@@ -0,0 +1,108 @@
+/*
+ * 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 <sstream>
+
+#include "DotNodeInfo.h"
+#include "graph/Graph.h"
+#include "graph/operation/LowerInfo.h"
+#include "backend/interface/IConfig.h"
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+const std::string DotNodeInfo::NODE_SHAPE = "rect";
+const std::string DotNodeInfo::BG_COLOR_SCHEME = "pastel18";
+// RED BLUE ORANGE YELLOW GREEN PUPLE CYAN PINK
+const std::string DotNodeInfo::BG_COLORS[8] = {"1", "2", "5", "6", "3", "4", "7", "8"};
+
+DotNodeInfo::DotNodeInfo(const neurun::graph::Graph &graph,
+ const neurun::model::operation::Index &index,
+ const neurun::model::operation::Node &node)
+ : _index(index), _node(node), _lower_info(graph.getLowerInfo(index))
+{
+ addBackendLabel();
+}
+
+std::string DotNodeInfo::index_str() const
+{
+ std::stringstream ss;
+ ss << "node" << _index.value();
+
+ return ss.str();
+}
+
+std::string DotNodeInfo::label() const
+{
+ std::stringstream ss;
+ ss << _index.value() << " : " << _node.getName() << std::endl;
+ for (auto label : _labels)
+ {
+ ss << label << std::endl;
+ }
+
+ return ss.str();
+}
+
+std::string DotNodeInfo::dot_shape() const { return NODE_SHAPE; }
+
+std::string DotNodeInfo::bg_color_scheme() const { return BG_COLOR_SCHEME; }
+
+std::string DotNodeInfo::bg_color() const
+{
+ if (!_lower_info)
+ return DEFAULT_BG_COLOR;
+ assert(_lower_info != nullptr);
+ const auto &backend = _lower_info->backend();
+ assert(backend != nullptr);
+
+ std::string backend_id = backend->config()->id();
+ // TODO : This is just workaround it can be made more efficient.
+ if (backend_id == "acl_cl")
+ {
+ return BG_COLORS[RED];
+ }
+ else if (backend_id == "cpu")
+ {
+ return BG_COLORS[BLUE];
+ }
+ else
+ {
+ return DEFAULT_BG_COLOR;
+ }
+}
+
+void DotNodeInfo::addBackendLabel()
+{
+ if (!_lower_info)
+ return;
+
+ std::string label;
+ const auto &backend = _lower_info->backend();
+ assert(backend != nullptr);
+
+ label += "[Backend] : ";
+ label += backend->config()->id();
+ _labels.emplace_back(label);
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
diff --git a/runtimes/neurun/src/dumper/dot/DotNodeInfo.h b/runtimes/neurun/src/dumper/dot/DotNodeInfo.h
new file mode 100644
index 000000000..656a05af6
--- /dev/null
+++ b/runtimes/neurun/src/dumper/dot/DotNodeInfo.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 __NEURUN_DUMPER_DOT_DOT_NODE_INFO_H__
+#define __NEURUN_DUMPER_DOT_DOT_NODE_INFO_H__
+
+#include "IDotInfo.h"
+#include "model/operation/Node.h"
+#include "model/operation/Index.h"
+
+namespace neurun
+{
+namespace graph
+{
+class Graph;
+} // namespace graph
+} // namespace neurun
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+class DotNodeInfo : public IDotInfo
+{
+public:
+ static const std::string NODE_SHAPE;
+ static const std::string BG_COLOR_SCHEME;
+ static const std::string BG_COLORS[8];
+
+public:
+ DotNodeInfo(const neurun::graph::Graph &graph, const neurun::model::operation::Index &index,
+ const neurun::model::operation::Node &node);
+
+public:
+ virtual std::string index_str() const override;
+ virtual std::string label() const override;
+ virtual std::string dot_shape() const override;
+ virtual std::string bg_color_scheme() const override;
+ virtual std::string bg_color() const override;
+
+private:
+ void addBackendLabel();
+
+private:
+ neurun::model::operation::Index _index;
+ const neurun::model::operation::Node &_node;
+ const neurun::graph::operation::LowerInfo *_lower_info;
+ std::vector<std::string> _labels;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
+
+#endif // __NEURUN_DUMPER_DOT_DOT_NODE_INFO_H__
diff --git a/runtimes/neurun/src/dumper/dot/DotOperandInfo.cc b/runtimes/neurun/src/dumper/dot/DotOperandInfo.cc
new file mode 100644
index 000000000..8f5905020
--- /dev/null
+++ b/runtimes/neurun/src/dumper/dot/DotOperandInfo.cc
@@ -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.
+ */
+
+#include <sstream>
+
+#include "DotOperandInfo.h"
+#include "graph/operand/LowerInfo.h"
+#include "backend/interface/IConfig.h"
+#include "backend/BackendManager.h"
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+const std::string DotOperandInfo::INPUT_SHAPE = "doublecircle";
+const std::string DotOperandInfo::OUTPUT_SHAPE = "doublecircle";
+const std::string DotOperandInfo::OPERAND_SHAPE = "ellipse";
+const std::string DotOperandInfo::BG_COLOR_SCHEME = "set38";
+// RED BLUE ORANGE YELLOW GREEN PUPLE CYAN PINK
+const std::string DotOperandInfo::BG_COLORS[8] = {"4", "5", "6", "2", "7", "3", "1", "8"};
+
+DotOperandInfo::DotOperandInfo(const neurun::model::operand::Index &index,
+ const neurun::model::operand::Object &object, Type type)
+ : _index(index), _object(object), _type(type)
+{
+ const auto &lower_info = object.lower_info();
+ if (lower_info)
+ {
+ addBackendLabel();
+ }
+}
+
+std::string DotOperandInfo::index_str() const
+{
+ std::stringstream ss;
+ ss << "obj" << _index.value();
+
+ return ss.str();
+}
+
+std::string DotOperandInfo::label() const
+{
+ std::stringstream ss;
+ ss << _index.value() << std::endl;
+ for (auto label : _labels)
+ {
+ ss << label << std::endl;
+ }
+
+ return ss.str();
+}
+
+std::string DotOperandInfo::dot_shape() const
+{
+ 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;
+ }
+}
+
+std::string DotOperandInfo::bg_color_scheme() const { return BG_COLOR_SCHEME; }
+
+std::string DotOperandInfo::bg_color() const
+{
+ const auto &lower_info = _object.lower_info();
+ if (!lower_info)
+ return DEFAULT_BG_COLOR;
+ assert(lower_info != nullptr);
+ const auto &def_backends = lower_info->def_backends();
+ assert(def_backends.size() == 1);
+
+ std::string backend_id = def_backends.getOnlyElement()->config()->id();
+ // TODO : This is just workaround it can be made more efficient.
+ if (backend_id == "acl_cl")
+ {
+ return BG_COLORS[RED];
+ }
+ else if (backend_id == "cpu")
+ {
+ return BG_COLORS[BLUE];
+ }
+ else
+ {
+ return DEFAULT_BG_COLOR;
+ }
+}
+
+void DotOperandInfo::addBackendLabel()
+{
+ std::string label;
+ const auto &lower_info = _object.lower_info();
+ assert(lower_info != nullptr);
+ const auto &def_backends = lower_info->def_backends();
+ assert(def_backends.size() == 1);
+
+ label += "[";
+ label += def_backends.getOnlyElement()->config()->id();
+ label += "]";
+ _labels.emplace_back(label);
+}
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
diff --git a/runtimes/neurun/src/dumper/dot/DotOperandInfo.h b/runtimes/neurun/src/dumper/dot/DotOperandInfo.h
new file mode 100644
index 000000000..c54da444d
--- /dev/null
+++ b/runtimes/neurun/src/dumper/dot/DotOperandInfo.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 __NEURUN_DUMPER_DOT_DOT_OPERAND_INFO_H__
+#define __NEURUN_DUMPER_DOT_DOT_OPERAND_INFO_H__
+
+#include <vector>
+
+#include "IDotInfo.h"
+#include "model/operand/Object.h"
+#include "model/operand/Index.h"
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+class DotOperandInfo : public IDotInfo
+{
+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;
+ static const std::string BG_COLORS[8];
+
+public:
+ DotOperandInfo(const neurun::model::operand::Index &index,
+ const neurun::model::operand::Object &object, Type type);
+
+public:
+ virtual std::string index_str() const override;
+ virtual std::string label() const override;
+ virtual std::string dot_shape() const override;
+ virtual std::string bg_color_scheme() const override;
+ virtual std::string bg_color() const override;
+
+private:
+ void addBackendLabel();
+
+private:
+ const neurun::model::operand::Index &_index;
+ const neurun::model::operand::Object &_object;
+ Type _type;
+
+ std::vector<std::string> _labels;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
+
+#endif // __NEURUN_DUMPER_DOT_DOT_OPERAND_INFO_H__
diff --git a/runtimes/neurun/src/dumper/dot/IDotInfo.h b/runtimes/neurun/src/dumper/dot/IDotInfo.h
new file mode 100644
index 000000000..d507e724a
--- /dev/null
+++ b/runtimes/neurun/src/dumper/dot/IDotInfo.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 __NEURUN_DUMPER_DOT_IDOTINFO_H__
+#define __NEURUN_DUMPER_DOT_IDOTINFO_H__
+
+#include <string>
+#include <memory>
+#include <vector>
+
+namespace neurun
+{
+namespace dumper
+{
+namespace dot
+{
+
+#define DEFAULT_BG_COLOR_SCHEME "x11"
+#define DEFAULT_BG_COLOR "white"
+
+enum BGCOLORS : int
+{
+ RED,
+ BLUE,
+ ORANGE,
+ YELLOW,
+ GREEN,
+ PUPLE,
+ CYAN,
+ PINK
+};
+
+struct IDotInfo
+{
+ virtual ~IDotInfo() = default;
+
+ virtual std::string index_str() const = 0;
+ virtual std::string label() const = 0;
+ virtual std::string dot_shape() const = 0;
+ virtual std::string bg_color_scheme() const { return DEFAULT_BG_COLOR_SCHEME; }
+ virtual std::string bg_color() const { return DEFAULT_BG_COLOR; }
+
+ void appendChild(std::shared_ptr<IDotInfo> dotinfo) { _children.emplace_back(dotinfo); }
+ const std::vector<std::shared_ptr<IDotInfo>> &children() const { return _children; }
+
+private:
+ std::vector<std::shared_ptr<IDotInfo>> _children;
+};
+
+} // namespace dot
+} // namespace dumper
+} // namespace neurun
+
+#endif // __NEURUN_DUMPER_DOT_IDOTINFO_H__
diff --git a/runtimes/neurun/src/exec/Sink.h b/runtimes/neurun/src/exec/Sink.h
index a96f08320..fe23e8ac3 100644
--- a/runtimes/neurun/src/exec/Sink.h
+++ b/runtimes/neurun/src/exec/Sink.h
@@ -19,105 +19,119 @@
#include <cassert>
-#include <arm_compute/core/ITensor.h>
-
-#include <util/feature/Shape.h>
-#include <util/feature/IndexIterator.h>
-
-#include "backend/cpu/operand/Tensor.h" // TODO Remove this dependency to backend
-#include "internal/nnapi/feature/View.h"
-#include "internal/nnapi/feature/Reader.h"
+#include "cpp14/memory.h"
+#include "util/feature/nhwc/View.h"
+#include "util/feature/nchw/View.h"
+#include <misc/feature/IndexIterator.h>
namespace neurun
{
namespace exec
{
-struct Sink
+struct ISink
{
- virtual ~Sink() = default;
+ virtual ~ISink() = default;
- virtual void pull(::arm_compute::ITensor &tensor) const = 0;
+ virtual void pull(::neurun::backend::operand::ITensor &tensor) const = 0;
};
-//
-// VectorSink
-//
-class VectorSink final : public Sink
+template <typename T> class Sink final : public ISink
{
public:
- VectorSink(const int32_t vlen, uint8_t *base, const size_t size) : _vlen{vlen}, _base{base}
- {
- (void)size; // Workaround for unused variable in release mode
- assert(size >= _vlen * sizeof(float));
- }
+ Sink(T *base, const size_t size) : _base{base}, _size{size} {}
public:
- void pull(::arm_compute::ITensor &tensor) const override
+ void pull(::neurun::backend::operand::ITensor &tensor) const override
{
- float *base = reinterpret_cast<float *>(_base);
-
- for (int32_t n = 0; n < _vlen; ++n)
- {
- auto from = reinterpret_cast<float *>(tensor.ptr_to_element(::arm_compute::Coordinates{n}));
- auto into = base + n;
-
- *into = *from;
- }
+ memcpy(_base, tensor.buffer(), _size);
}
private:
- const int32_t _vlen;
- uint8_t *const _base;
+ T *const _base;
+ const size_t _size;
};
-//
-// FeatureSink
-//
-class FeatureSink final : public Sink
+class PermutateSink final : public ISink
{
public:
- FeatureSink(const nnfw::util::feature::Shape &shape, uint8_t *base, const size_t size)
- : _shape{shape}, _base{base}, _size{size}
+ PermutateSink(void *output_buffer, const size_t &output_size, const model::operand::Shape &shape)
+ : _output_buffer{(uint8_t *)output_buffer}, _output_size{output_size}, _shape{shape}
{
- // DO NOTHING
}
public:
- void pull(::arm_compute::ITensor &tensor) const override
+ void pull(neurun::backend::operand::ITensor &tensor) const override
{
- // TODO: This is just workaround codes, It needs to refactor.
- if (typeid(tensor) == typeid(neurun::backend::cpu::operand::Tensor))
- {
- const ::internal::nnapi::feature::Reader<float> from{_shape, tensor.buffer(), _size};
- ::internal::nnapi::feature::View<float> into{_shape, _base, _size};
-
- ::nnfw::util::feature::iterate(_shape)
- << [&](uint32_t bat, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(bat, ch, row, col);
- into.at(bat, ch, row, col) = value;
- };
- }
- else if (typeid(tensor) == typeid(::arm_compute::CLTensor))
+ // do NCHW_TO_NHWC permutation
+ auto input_buffer = tensor.buffer();
+ auto rank = _shape.rank();
+
+ switch (rank)
{
- const ::internal::arm_compute::feature::View<float> from{&tensor};
- ::internal::nnapi::feature::View<float> into{_shape, _base, _size};
-
- ::nnfw::util::feature::iterate(_shape)
- << [&](uint32_t bat, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(bat, ch, row, col);
- into.at(bat, ch, row, col) = value;
- };
+ case 0:
+ case 1:
+ {
+ memcpy(_output_buffer, input_buffer, _output_size);
+ break;
+ }
+ case 2:
+ {
+ auto matrix_shape = _shape.asMatrix();
+
+ for (auto h = 0; h < matrix_shape.H; ++h)
+ {
+ neurun::util::feature::Coordinate4D coord{0, h, 0, 0};
+ memcpy(_output_buffer + h * matrix_shape.W, input_buffer + tensor.calcOffset(coord),
+ matrix_shape.W * sizeof(float));
+ }
+ break;
+ }
+ case 3:
+ {
+ const int32_t depth = _shape.dim(0);
+ const int32_t height = _shape.dim(1);
+ const int32_t width = _shape.dim(2);
+
+ for (auto c = 0; c < depth; ++c)
+ {
+ for (auto h = 0; h < height; ++h)
+ {
+ neurun::util::feature::Coordinate4D coord{0, h, 0, c};
+ memcpy(_output_buffer + c * height * width + h * width,
+ input_buffer + tensor.calcOffset(coord), width * sizeof(float));
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ auto feature = _shape.asFeature();
+
+ const util::feature::nchw::View<float> from{&tensor};
+ util::feature::nhwc::View<float> into{feature, reinterpret_cast<float *>(_output_buffer),
+ _output_size};
+
+ ::nnfw::misc::feature::iterate(feature)
+ << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(batch, ch, row, col);
+ into.at(batch, ch, row, col) = value;
+ };
+ break;
+ }
+ default:
+ throw "NYI";
+ break;
}
}
private:
- const nnfw::util::feature::Shape _shape;
- uint8_t *const _base;
- const size_t _size;
+ uint8_t *_output_buffer;
+ const size_t _output_size;
+ const model::operand::Shape _shape;
};
} // namespace exec
} // namespace neurun
-#endif // __INTERNAL_SINK_H__
+#endif // __NEURUN_EXEC_SINK_H__
diff --git a/runtimes/neurun/src/exec/Source.h b/runtimes/neurun/src/exec/Source.h
index e7c2e80c4..169f8b386 100644
--- a/runtimes/neurun/src/exec/Source.h
+++ b/runtimes/neurun/src/exec/Source.h
@@ -19,105 +19,118 @@
#include <cassert>
-#include <arm_compute/runtime/CL/CLTensor.h>
-
-#include <util/feature/Shape.h>
-#include <util/feature/IndexIterator.h>
-
-#include "backend/cpu/operand/Tensor.h" // TODO Remove this dependency to backend
-#include "internal/nnapi/feature/Reader.h"
-#include "internal/nnapi/feature/View.h"
-
-#include "backend/acl_cl/feature/View.h"
+#include "cpp14/memory.h"
+#include "util/feature/nchw/View.h"
+#include "util/feature/nhwc/Reader.h"
+#include "util/feature/Coordinate4D.h"
+#include <misc/feature/IndexIterator.h>
namespace neurun
{
namespace exec
{
-struct Source
+struct ISource
{
- virtual ~Source() = default;
+ virtual ~ISource() = default;
- virtual void push(::arm_compute::ITensor &tensor) const = 0;
+ virtual void push(::neurun::backend::operand::ITensor &tensor) const = 0;
};
-//
-// VectorSource
-//
-class VectorSource final : public Source
+template <typename T> class Source final : public ISource
{
public:
- VectorSource(const int32_t vlen, const uint8_t *base, const size_t size)
- : _vlen{vlen}, _base{base}
- {
- (void)size; // Workaround for unused variable in release mode
- assert(size >= _vlen * sizeof(float));
- }
+ Source(const T *base, const size_t size) : _base{base}, _size{size} {}
public:
- void push(::arm_compute::ITensor &tensor) const override
+ void push(::neurun::backend::operand::ITensor &tensor) const override
{
- auto base = reinterpret_cast<const float *>(_base);
-
- for (int32_t n = 0; n < _vlen; ++n)
- {
- auto from = base + n;
- auto into = reinterpret_cast<float *>(tensor.ptr_to_element(::arm_compute::Coordinates{n}));
-
- *into = *from;
- }
+ memcpy(tensor.buffer(), _base, _size);
}
private:
- const int32_t _vlen;
- const uint8_t *const _base;
+ const T *const _base;
+ const size_t _size;
};
-//
-// FeatureSource
-//
-class FeatureSource final : public Source
+class PermutateSource final : public ISource
{
public:
- FeatureSource(const nnfw::util::feature::Shape &shape, const uint8_t *base, const size_t size)
- : _shape{shape}, _base{base}, _size{size}
+ PermutateSource(const void *input_buffer, const size_t &input_size,
+ const model::operand::Shape &shape)
+ : _input_buffer{(uint8_t *)input_buffer}, _input_size{input_size}, _shape{shape}
{
- // DO NOTHING
}
public:
- void push(::arm_compute::ITensor &tensor) const override
+ void push(neurun::backend::operand::ITensor &tensor) const override
{
- // TODO: This is just workaround codes, It needs to refactor.
- if (typeid(tensor) == typeid(neurun::backend::cpu::operand::Tensor))
- {
- const ::internal::nnapi::feature::Reader<float> from{_shape, _base, _size};
- ::internal::nnapi::feature::View<float> into{_shape, tensor.buffer(), _size};
-
- ::nnfw::util::feature::iterate(_shape)
- << [&](uint32_t bat, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(bat, ch, row, col);
- into.at(bat, ch, row, col) = value;
- };
- }
- else if (typeid(tensor) == typeid(::arm_compute::CLTensor))
+ // do NHWC_TO_NCHW permutation
+ auto output_buffer = tensor.buffer();
+ auto rank = _shape.rank();
+
+ switch (rank)
{
- const ::internal::nnapi::feature::Reader<float> from{_shape, _base, _size};
- ::internal::arm_compute::feature::View<float> into{&tensor};
-
- ::nnfw::util::feature::iterate(_shape)
- << [&](uint32_t bat, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(bat, ch, row, col);
- into.at(bat, ch, row, col) = value;
- };
+ case 0:
+ case 1:
+ {
+ memcpy(output_buffer, _input_buffer, _input_size);
+ break;
+ }
+ case 2:
+ {
+ auto matrix_shape = _shape.asMatrix();
+
+ for (auto h = 0; h < matrix_shape.H; ++h)
+ {
+ neurun::util::feature::Coordinate4D coord{0, h, 0, 0};
+ memcpy(output_buffer + tensor.calcOffset(coord), _input_buffer + h * matrix_shape.W,
+ matrix_shape.W * sizeof(float));
+ }
+ break;
+ }
+ case 3:
+ {
+ const int32_t depth = _shape.dim(0);
+ const int32_t height = _shape.dim(1);
+ const int32_t width = _shape.dim(2);
+
+ for (auto c = 0; c < depth; ++c)
+ {
+ for (auto h = 0; h < height; ++h)
+ {
+ neurun::util::feature::Coordinate4D coord{0, h, 0, c};
+ memcpy(output_buffer + tensor.calcOffset(coord),
+ _input_buffer + c * height * width + h * width, width * sizeof(float));
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ auto feature = _shape.asFeature();
+
+ const util::feature::nhwc::Reader<float> from{
+ feature, reinterpret_cast<const float *>(_input_buffer), _input_size};
+ util::feature::nchw::View<float> into{&tensor};
+
+ ::nnfw::misc::feature::iterate(feature)
+ << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(batch, ch, row, col);
+ into.at(batch, ch, row, col) = value;
+ };
+ break;
+ }
+ default:
+ throw "NYI";
+ break;
}
}
private:
- const nnfw::util::feature::Shape _shape;
- const uint8_t *const _base;
- const size_t _size;
+ const uint8_t *_input_buffer;
+ const size_t _input_size;
+ const model::operand::Shape _shape;
};
} // namespace exec
diff --git a/runtimes/neurun/src/exec/interface/IFunction.h b/runtimes/neurun/src/exec/interface/IFunction.h
new file mode 100644
index 000000000..b7a721d1d
--- /dev/null
+++ b/runtimes/neurun/src/exec/interface/IFunction.h
@@ -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.
+ */
+
+#ifndef __NEURUN_EXEC_I_FUNCTION_H__
+#define __NEURUN_EXEC_I_FUNCTION_H__
+
+namespace neurun
+{
+namespace exec
+{
+
+class IFunction
+{
+public:
+ virtual ~IFunction() = default;
+ virtual void run() = 0;
+ virtual void prepare() {}
+};
+
+} // namespace exec
+} // namespace neurun
+
+#endif // __NEURUN_EXEC_I_FUNCTION_H__
diff --git a/runtimes/neurun/src/frontend/compilation.cc b/runtimes/neurun/src/frontend/compilation.cc
index a135edac5..9b0719f46 100644
--- a/runtimes/neurun/src/frontend/compilation.cc
+++ b/runtimes/neurun/src/frontend/compilation.cc
@@ -32,6 +32,11 @@ int ANeuralNetworksCompilation_create(ANeuralNetworksModel *model,
return ANEURALNETWORKS_UNEXPECTED_NULL;
}
+ if (!model->isFinished())
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
std::shared_ptr<neurun::graph::Graph> internal;
model->release(internal);
diff --git a/runtimes/neurun/src/frontend/execution.cc b/runtimes/neurun/src/frontend/execution.cc
index ff34921b7..5f1729b30 100644
--- a/runtimes/neurun/src/frontend/execution.cc
+++ b/runtimes/neurun/src/frontend/execution.cc
@@ -22,7 +22,122 @@
#include "frontend/wrapper/execution.h"
#include "frontend/wrapper/event.h"
-#include "graph/operand/Index.h"
+#include "model/operand/DataType.h"
+#include "model/operand/Index.h"
+#include "graph/operand/Layout.h"
+#include "backend/BackendManager.h"
+#include "backend/interface/IConfig.h"
+#include "compiler/BackendResolver.h"
+#include "compiler/TensorInfo.h"
+#include "backend/interface/operand/ITensor.h"
+
+inline void source(ANeuralNetworksExecution *execution,
+ const ::neurun::model::operand::DataType &type, int32_t index,
+ const void *buffer, size_t length)
+{
+ const auto &operands = execution->plan().model().operands();
+ neurun::model::operand::IO::Index input_index{index};
+
+ const auto operand_index = execution->plan().model().getInputs().at(input_index);
+ auto operand = &operands.at(operand_index);
+ auto operand_li = operand->lower_info();
+ const auto output_backend = operand_li->def_backends().getOnlyElement();
+ const auto output_layout = output_backend->config()->getOperandLayout();
+ auto input_layout = execution->plan()
+ .model()
+ .backend_resolver()
+ ->getDefaultBackend()
+ ->config()
+ ->getOperandLayout();
+ if (input_layout == neurun::graph::operand::Layout::NHWC &&
+ output_layout == neurun::graph::operand::Layout::NCHW)
+ {
+ const auto tensor_info = neurun::compiler::TensorInfo(operand->shape(), operand->typeInfo());
+
+ execution->source<::neurun::exec::PermutateSource>(index, buffer, tensor_info.total_size(),
+ operand->shape());
+ return;
+ }
+ using ::neurun::model::operand::DataType;
+ switch (type)
+ {
+ case DataType::SCALAR_FLOAT32:
+ case DataType::TENSOR_FLOAT32:
+ execution->source<::neurun::exec::Source<float>>(
+ index, reinterpret_cast<const float *>(buffer), length);
+ break;
+ case DataType::SCALAR_INT32:
+ case DataType::TENSOR_INT32:
+ execution->source<::neurun::exec::Source<int32_t>>(
+ index, reinterpret_cast<const int32_t *>(buffer), length);
+ break;
+ case DataType::SCALAR_UINT32:
+ execution->source<::neurun::exec::Source<uint32_t>>(
+ index, reinterpret_cast<const uint32_t *>(buffer), length);
+ break;
+ case DataType::TENSOR_QUANT8_ASYMM:
+ execution->source<::neurun::exec::Source<uint8_t>>(
+ index, reinterpret_cast<const uint8_t *>(buffer), length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+inline void sink(ANeuralNetworksExecution *execution,
+ const ::neurun::model::operand::DataType &type, int32_t index, void *buffer,
+ size_t length)
+{
+ const auto &operands = execution->plan().model().operands();
+ neurun::model::operand::IO::Index input_index{index};
+
+ const auto operand_index = execution->plan().model().getOutputs().at(input_index);
+ auto operand = &operands.at(operand_index);
+ auto operand_li = operand->lower_info();
+ const auto input_backend = operand_li->def_backends().getOnlyElement();
+ const auto input_layout = input_backend->config()->getOperandLayout();
+ auto output_layout = execution->plan()
+ .model()
+ .backend_resolver()
+ ->getDefaultBackend()
+ ->config()
+ ->getOperandLayout();
+ if (input_layout == neurun::graph::operand::Layout::NCHW &&
+ output_layout == neurun::graph::operand::Layout::NHWC)
+ {
+ const auto tensor_info = neurun::compiler::TensorInfo(operand->shape(), operand->typeInfo());
+
+ execution->sink<::neurun::exec::PermutateSink>(index, buffer, tensor_info.total_size(),
+ operand->shape());
+ return;
+ }
+ using ::neurun::model::operand::DataType;
+ switch (type)
+ {
+ case DataType::SCALAR_FLOAT32:
+ case DataType::TENSOR_FLOAT32:
+ execution->sink<::neurun::exec::Sink<float>>(index, reinterpret_cast<float *>(buffer),
+ length);
+ break;
+ case DataType::SCALAR_INT32:
+ case DataType::TENSOR_INT32:
+ execution->sink<::neurun::exec::Sink<int32_t>>(index, reinterpret_cast<int32_t *>(buffer),
+ length);
+ break;
+ case DataType::SCALAR_UINT32:
+ execution->sink<::neurun::exec::Sink<uint32_t>>(index, reinterpret_cast<uint32_t *>(buffer),
+ length);
+ break;
+ case DataType::TENSOR_QUANT8_ASYMM:
+ execution->sink<::neurun::exec::Sink<uint8_t>>(index, reinterpret_cast<uint8_t *>(buffer),
+ length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
//
// NNAPI Implementation
@@ -35,7 +150,13 @@ int ANeuralNetworksExecution_create(ANeuralNetworksCompilation *compilation,
return ANEURALNETWORKS_UNEXPECTED_NULL;
}
- std::shared_ptr<const neurun::codegen::Plan> plan;
+ // Can handle compiled state only
+ if (compilation->plan().state() != neurun::compiler::State::COMPILED)
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ std::shared_ptr<const neurun::compiler::Plan> plan;
compilation->publish(plan);
@@ -61,36 +182,23 @@ int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution *execution, int32
return ANEURALNETWORKS_UNEXPECTED_NULL;
}
+ // TODO Handle optional input
+ if (buffer == nullptr)
+ {
+ throw std::runtime_error("Not supported optional input, yet");
+ }
+
const auto &operands = execution->plan().model().operands();
// TODO Check type conflicts
- // NOTE The current implemenation assumes that every input is a feature map.
- // TODO Remove this assumption
- neurun::graph::operand::IO::Index input_index{index};
+ neurun::model::operand::IO::Index input_index{index};
const auto operand_index = execution->plan().model().getInputs().at(input_index);
+ const auto data_type = operands.at(operand_index).typeInfo().type();
+ const auto operand_shape = operands.at(operand_index).shape();
- if (operands.at(operand_index).shape().rank() == 2)
- {
- assert(operands.at(operand_index).shape().dim(0) == 1);
-
- const auto len = operands.at(operand_index).shape().dim(1);
-
- execution->source<neurun::exec::VectorSource>(
- index, len, reinterpret_cast<const uint8_t *>(buffer), length);
- }
- else if (operands.at(operand_index).shape().rank() == 4)
- {
- const auto &operand_shape = operands.at(operand_index).shape().asFeature();
-
- execution->source<neurun::exec::FeatureSource>(
- index, operand_shape, reinterpret_cast<const uint8_t *>(buffer), length);
- }
- else
- {
- throw std::runtime_error{"Not supported, yet"};
- }
+ source(execution, data_type, index, buffer, length);
return ANEURALNETWORKS_NO_ERROR;
}
@@ -108,36 +216,23 @@ int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution *execution, int3
return ANEURALNETWORKS_UNEXPECTED_NULL;
}
+ // Handle optional output
+ if (buffer == nullptr)
+ {
+ return ANEURALNETWORKS_NO_ERROR;
+ }
+
const auto &operands = execution->plan().model().operands();
// TODO Check type conflicts
- // NOTE The current implemenation assumes that every output is a feature map.
- // TODO Remove this assumption
- neurun::graph::operand::IO::Index output_index{index};
+ neurun::model::operand::IO::Index output_index{index};
const auto operand_index = execution->plan().model().getOutputs().at(output_index);
+ const auto data_type = operands.at(operand_index).typeInfo().type();
+ const auto operand_shape = operands.at(operand_index).shape();
- if (operands.at(operand_index).shape().rank() == 2)
- {
- assert(operands.at(operand_index).shape().dim(0) == 1);
-
- const auto len = operands.at(operand_index).shape().dim(1);
-
- execution->sink<neurun::exec::VectorSink>(index, len, reinterpret_cast<uint8_t *>(buffer),
- length);
- }
- else if (operands.at(operand_index).shape().rank() == 4)
- {
- const auto &operand_shape = operands.at(operand_index).shape().asFeature();
-
- execution->sink<neurun::exec::FeatureSink>(index, operand_shape,
- reinterpret_cast<uint8_t *>(buffer), length);
- }
- else
- {
- throw std::runtime_error{"Not supported, yet"};
- }
+ sink(execution, data_type, index, buffer, length);
return ANEURALNETWORKS_NO_ERROR;
}
@@ -163,17 +258,16 @@ int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution,
// Set input(s)
for (uint32_t n = 0; n < model.getInputs().size(); ++n)
{
- auto setter = [&](::arm_compute::ITensor &tensor) { execution->source(n).push(tensor); };
+ auto setter = [&](::neurun::backend::operand::ITensor &tensor) {
+ execution->source(n).push(tensor);
+ };
- neurun::graph::operand::IO::Index input_index{n};
+ neurun::model::operand::IO::Index input_index{n};
- ::neurun::graph::operand::Index index{model.getInputs().at(input_index)};
- auto objects = plan.operands().at(index);
+ ::neurun::model::operand::Index index{model.getInputs().at(input_index)};
+ auto object = plan.operands().at(index);
- for (auto object : objects)
- {
- object->access(setter);
- }
+ object->access(setter);
}
const auto &operations = execution->plan().operations();
@@ -186,17 +280,16 @@ int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution,
// Get output(s)
for (uint32_t n = 0; n < model.getOutputs().size(); ++n)
{
- auto getter = [&](::arm_compute::ITensor &tensor) { execution->sink(n).pull(tensor); };
+ auto getter = [&](::neurun::backend::operand::ITensor &tensor) {
+ execution->sink(n).pull(tensor);
+ };
- neurun::graph::operand::IO::Index output_index{n};
+ neurun::model::operand::IO::Index output_index{n};
- ::neurun::graph::operand::Index index{model.getOutputs().at(output_index)};
- auto objects = plan.operands().at(index);
+ ::neurun::model::operand::Index index{model.getOutputs().at(output_index)};
+ auto object = plan.operands().at(index);
- for (auto object : objects)
- {
- object->access(getter);
- }
+ object->access(getter);
}
return ANEURALNETWORKS_NO_ERROR;
diff --git a/runtimes/neurun/src/frontend/memory.cc b/runtimes/neurun/src/frontend/memory.cc
index cc891feef..b2f6ab2d0 100644
--- a/runtimes/neurun/src/frontend/memory.cc
+++ b/runtimes/neurun/src/frontend/memory.cc
@@ -19,7 +19,7 @@
#include <new>
#include <memory>
-#include "nnfw/std/memory.h"
+#include "cpp14/memory.h"
#include "frontend/wrapper/memory.h"
int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset,
@@ -32,7 +32,7 @@ int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t
// Use unique pointer to avoid memory leak
std::unique_ptr<ANeuralNetworksMemory> memory_ptr =
- nnfw::make_unique<ANeuralNetworksMemory>(size, protect, fd, offset);
+ nnfw::cpp14::make_unique<ANeuralNetworksMemory>(size, protect, fd, offset);
if (memory_ptr == nullptr)
{
return ANEURALNETWORKS_OUT_OF_MEMORY;
diff --git a/runtimes/neurun/src/frontend/model.cc b/runtimes/neurun/src/frontend/model.cc
index 28a9b2515..3aa2aa2ff 100644
--- a/runtimes/neurun/src/frontend/model.cc
+++ b/runtimes/neurun/src/frontend/model.cc
@@ -21,18 +21,12 @@
#include <stdexcept>
#include <new>
-#include "nnfw/std/memory.h"
+#include "cpp14/memory.h"
#include "graph/Graph.h"
#include "frontend/wrapper/model.h"
#include "frontend/wrapper/memory.h"
-#include "graph/operation/AvgPool2D.h"
-#include "graph/operation/Concat.h"
-#include "graph/operation/Conv2D.h"
-#include "graph/operation/FullyConnected.h"
-#include "graph/operation/MaxPool2D.h"
-#include "graph/operation/Reshape.h"
-#include "graph/operation/Softmax.h"
+#include "model/operation/Node.Include.h"
int ANeuralNetworksModel_create(ANeuralNetworksModel **model)
{
@@ -94,8 +88,8 @@ int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model,
return ANEURALNETWORKS_BAD_DATA;
}
- ::neurun::graph::operand::Shape shape(type->dimensionCount);
- ::neurun::graph::operand::TypeInfo typeInfo((OperandCode)(type->type), type->scale,
+ ::neurun::model::operand::Shape shape(type->dimensionCount);
+ ::neurun::model::operand::TypeInfo typeInfo((OperandCode)(type->type), type->scale,
type->zeroPoint);
for (uint32_t axis = 0; axis < type->dimensionCount; ++axis)
@@ -115,6 +109,8 @@ int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model,
int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index,
const void *buffer, size_t length)
{
+ const bool isOptional = ((buffer == nullptr) && (length == 0));
+
if ((model == nullptr) || ((buffer == nullptr) && (length != 0)))
{
return ANEURALNETWORKS_UNEXPECTED_NULL;
@@ -130,7 +126,7 @@ int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t in
{
return ANEURALNETWORKS_BAD_DATA;
}
- const neurun::graph::operand::Index ind{static_cast<uint32_t>(index)};
+ const neurun::model::operand::Index ind{static_cast<uint32_t>(index)};
if (!model->deref().operands().exist(ind))
{
@@ -138,7 +134,7 @@ int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t in
}
auto &obj = model->deref().operands().at(ind);
- if (obj.operandSize() != length)
+ if ((obj.operandSize() != length) && !isOptional)
{
return ANEURALNETWORKS_BAD_DATA;
}
@@ -147,10 +143,30 @@ int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t in
return ANEURALNETWORKS_BAD_DATA;
}
- using ::neurun::graph::operand::CachedData;
+ using ::neurun::model::operand::CachedData;
+ using ::neurun::model::operand::ExternalData;
- model->deref().setOperandValue(
- ind, nnfw::make_unique<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length));
+ // Remain operands.at(ind).data()->base() as nullptr for optional operand
+ // This will be filled when model finished
+ if (isOptional)
+ {
+ model->setOptionalOperand(ind);
+ }
+
+ // 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
+ if (length <= ANEURALNETWORKS_MAX_SIZE_OF_IMMEDIATELY_COPIED_VALUES)
+ {
+ model->deref().setOperandValue(ind, nnfw::cpp14::make_unique<CachedData>(
+ reinterpret_cast<const uint8_t *>(buffer), length));
+ }
+ else
+ {
+ model->deref().setOperandValue(ind, nnfw::cpp14::make_unique<ExternalData>(
+ reinterpret_cast<const uint8_t *>(buffer), length));
+ }
return ANEURALNETWORKS_NO_ERROR;
}
@@ -174,7 +190,7 @@ int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model,
{
return ANEURALNETWORKS_BAD_DATA;
}
- const neurun::graph::operand::Index ind{static_cast<uint32_t>(index)};
+ const neurun::model::operand::Index ind{static_cast<uint32_t>(index)};
if (!model->deref().operands().exist(ind))
{
@@ -191,10 +207,10 @@ int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model,
return ANEURALNETWORKS_BAD_DATA;
}
- using ::neurun::graph::operand::ExternalData;
+ using ::neurun::model::operand::ExternalData;
model->deref().setOperandValue(
- ind, nnfw::make_unique<ExternalData>(
+ ind, nnfw::cpp14::make_unique<ExternalData>(
reinterpret_cast<const uint8_t *>(memory->base() + offset), length));
return ANEURALNETWORKS_NO_ERROR;
@@ -210,6 +226,13 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
return ANEURALNETWORKS_UNEXPECTED_NULL;
}
+ const ANeuralNetworksOperationType FIRST_OPERATION = ANEURALNETWORKS_ADD;
+ const ANeuralNetworksOperationType LAST_OPERATION = ANEURALNETWORKS_TRANSPOSE;
+ if ((type < FIRST_OPERATION) || (type > LAST_OPERATION))
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
if (model->isFinished())
{
return ANEURALNETWORKS_BAD_STATE;
@@ -217,7 +240,7 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
for (uint32_t i = 0; i < outputCount; i++)
{
- const ::neurun::graph::operand::Index ind{outputs[i]};
+ const ::neurun::model::operand::Index ind{outputs[i]};
auto &obj = model->deref().operands().at(ind);
if (!obj.setAsOperationOutput())
@@ -229,108 +252,115 @@ int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
auto &graph = model->deref();
auto node_param =
- neurun::graph::operation::Node::InitParam{inputCount, inputs, outputCount, outputs};
+ neurun::model::operation::Node::InitParam{inputCount, inputs, outputCount, outputs};
- switch (type)
+ try
{
- case ANEURALNETWORKS_CONV_2D:
+ switch (type)
{
- // 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(inputCount == 7 || inputCount == 10);
- assert(outputCount == 1);
-
- if (inputCount == 7)
+ case ANEURALNETWORKS_CONV_2D:
{
- using GraphNode = neurun::graph::operation::Conv2D::Implicit::Node;
-
- graph.addOperation(nnfw::make_unique<GraphNode>(node_param));
+ // 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(inputCount == 7 || inputCount == 10);
+ assert(outputCount == 1);
+
+ if (inputCount == 7)
+ {
+ using GraphNode = neurun::model::operation::Conv2DNode;
+
+ graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param));
+ }
+ else
+ {
+ throw std::runtime_error{"Explicit padding in Conv2D is not supported, yet"};
+ }
+
+ break;
}
- else
+ case ANEURALNETWORKS_MAX_POOL_2D:
{
- throw std::runtime_error{"Explicit padding in Conv2D is not supported, yet"};
+ // 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(inputCount == 7 || inputCount == 10);
+ assert(outputCount == 1);
+
+ if (inputCount == 7)
+ {
+ using GraphNode = neurun::model::operation::MaxPool2DNode;
+
+ graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param));
+ }
+ else
+ {
+ throw std::runtime_error{"Explicit padding in MaxPool2D is not supported, yet"};
+ }
+
+ break;
}
-
- break;
- }
- case ANEURALNETWORKS_MAX_POOL_2D:
- {
- // 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(inputCount == 7 || inputCount == 10);
- assert(outputCount == 1);
-
- if (inputCount == 7)
+ case ANEURALNETWORKS_AVERAGE_POOL_2D:
{
- using GraphNode = neurun::graph::operation::MaxPool2D::Implicit::Node;
-
- graph.addOperation(nnfw::make_unique<GraphNode>(node_param));
+ // 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(inputCount == 7 || inputCount == 10);
+ assert(outputCount == 1);
+
+ if (inputCount == 7)
+ {
+ using GraphNode = neurun::model::operation::AvgPool2DNode;
+
+ graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param));
+ }
+ else
+ {
+ throw std::runtime_error{"Explicit padding in AvgPool2D is not supported, yet"};
+ }
+
+ break;
}
- else
+ case ANEURALNETWORKS_CONCATENATION:
{
- throw std::runtime_error{"Explicit padding in MaxPool2D is not supported, yet"};
- }
-
- break;
- }
- case ANEURALNETWORKS_AVERAGE_POOL_2D:
- {
- // 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(inputCount == 7 || inputCount == 10);
- assert(outputCount == 1);
+ using GraphNode = neurun::model::operation::ConcatNode;
- if (inputCount == 7)
- {
- using GraphNode = neurun::graph::operation::AvgPool2D::Implicit::Node;
+ graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param));
- graph.addOperation(nnfw::make_unique<GraphNode>(node_param));
+ break;
}
- else
+ case ANEURALNETWORKS_RESHAPE:
{
- throw std::runtime_error{"Explicit padding in AvgPool2D is not supported, yet"};
- }
-
- break;
- }
- case ANEURALNETWORKS_CONCATENATION:
- {
- using GraphNode = neurun::graph::operation::Concat::Node;
+ using GraphNode = neurun::model::operation::ReshapeNode;
- graph.addOperation(nnfw::make_unique<GraphNode>(node_param));
+ graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param));
- break;
- }
- case ANEURALNETWORKS_RESHAPE:
- {
- using GraphNode = neurun::graph::operation::Reshape::Node;
-
- graph.addOperation(nnfw::make_unique<GraphNode>(node_param));
-
- break;
- }
- case ANEURALNETWORKS_FULLY_CONNECTED:
- {
- using GraphNode = neurun::graph::operation::FullyConnected::Node;
+ break;
+ }
+ case ANEURALNETWORKS_FULLY_CONNECTED:
+ {
+ using GraphNode = neurun::model::operation::FullyConnectedNode;
- graph.addOperation(nnfw::make_unique<GraphNode>(node_param));
+ graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param));
- break;
- }
- case ANEURALNETWORKS_SOFTMAX:
- {
- using GraphNode = neurun::graph::operation::Softmax::Node;
+ break;
+ }
+ case ANEURALNETWORKS_SOFTMAX:
+ {
+ using GraphNode = neurun::model::operation::SoftmaxNode;
- graph.addOperation(nnfw::make_unique<GraphNode>(node_param));
+ graph.addOperation(nnfw::cpp14::make_unique<GraphNode>(node_param));
- break;
- }
- default:
- throw std::runtime_error{"Not supported operation"};
- };
+ break;
+ }
+ default:
+ throw std::runtime_error{"Not supported operation"};
+ };
+ }
+ catch (const std::exception &e)
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
return ANEURALNETWORKS_NO_ERROR;
}
@@ -350,9 +380,16 @@ int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model,
return ANEURALNETWORKS_BAD_STATE;
}
+ const ANeuralNetworksOperationTypeEx FIRST_OPERATION = ANEURALNETWORKS_GATHER_EX;
+ const ANeuralNetworksOperationTypeEx LAST_OPERATION = ANEURALNETWORKS_PRELU_EX;
+ if ((type < FIRST_OPERATION) || (type > LAST_OPERATION))
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
for (uint32_t i = 0; i < outputCount; i++)
{
- const ::neurun::graph::operand::Index ind{outputs[i]};
+ const ::neurun::model::operand::Index ind{outputs[i]};
auto &obj = model->deref().operands().at(ind);
if (!obj.setAsOperationOutput())
@@ -367,11 +404,20 @@ int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model,
return ANEURALNETWORKS_BAD_DATA;
}
- switch (type)
+ try
{
- default:
- throw std::runtime_error{"Not supported operation"};
+ switch (type)
+ {
+ default:
+ throw std::runtime_error{"Not supported operation"};
+ }
}
+ catch (const std::exception &e)
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
}
int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount,
@@ -388,7 +434,7 @@ int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, u
return ANEURALNETWORKS_BAD_STATE;
}
- // NOTE ::neurun::graph::operand::Index uses int as its underlying type as various NNAPI
+ // NOTE ::neurun::model::operand::Index uses int as its underlying type as various NNAPI
// functions such as ANeuralNetworksModel_setOperandValue use int to represent operand index
//
// ANeuralNetworksModel_identifyInputsAndOutputs, however, uses uint32_t to represent operand
@@ -397,7 +443,7 @@ int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, u
// Below, static_cast<int>(...) is introduced to eliminate compiler warning.
for (uint32_t n = 0; n < inputCount; ++n)
{
- const neurun::graph::operand::Index ind{static_cast<uint32_t>(inputs[n])};
+ const neurun::model::operand::Index ind{static_cast<uint32_t>(inputs[n])};
model->deref().addInput(ind);
auto &obj = model->deref().operands().at(ind);
@@ -409,7 +455,7 @@ int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, u
for (uint32_t n = 0; n < outputCount; ++n)
{
- const neurun::graph::operand::Index ind{static_cast<uint32_t>(outputs[n])};
+ const neurun::model::operand::Index ind{static_cast<uint32_t>(outputs[n])};
model->deref().addOutput(ind);
auto &obj = model->deref().operands().at(ind);
diff --git a/runtimes/neurun/src/frontend/wrapper/compilation.cc b/runtimes/neurun/src/frontend/wrapper/compilation.cc
index 4ff33faa5..e4aa99f7a 100644
--- a/runtimes/neurun/src/frontend/wrapper/compilation.cc
+++ b/runtimes/neurun/src/frontend/wrapper/compilation.cc
@@ -14,53 +14,18 @@
* limitations under the License.
*/
-#include <NeuralNetworks.h>
-
-#include <algorithm>
-
-#include <arm_compute/core/CL/ICLTensor.h>
-
-#include <arm_compute/runtime/IFunction.h>
-#include <arm_compute/runtime/CL/CLScheduler.h>
-
-#include "internal/Convert.h"
-#include "backend/acl_cl/kernel/View.h"
-#include "backend/acl_cl/TensorBuilder.h"
-#include "internal/nnapi/kernel/Reader.h"
-#include "internal/Padding.h"
-#include "backend/IInitializerGenerator.h"
-#include "backend/IStageGenerator.h"
-
#include "compilation.h"
-#include "model.h"
-#include "logging.h"
-
-#include "graph/dumper/Dumper.h"
-#include "codegen/IPlanBuilder.h"
-#include "codegen/Planner.h"
-#include "codegen/PlanBuilder.h"
-
-#include "linear/Linear.h"
int ANeuralNetworksCompilation::finish()
{
- auto &plan = this->plan();
- const auto &operands = plan.model().operands();
-
- plan.model().lower();
- auto linear = plan.model().linearize();
-
- // Dump ops
- linear->accept(neurun::graph::dumper::Dumper{});
-
- neurun::codegen::PlanBuilder plan_builder{plan};
-
- auto tensor_builders = linear->markTensors();
-
- linear->accept(neurun::codegen::Planner{operands, plan_builder});
-
- // TODO Add optimization passes
- plan_builder.finalize(tensor_builders);
+ try
+ {
+ _compiler->compile();
+ }
+ catch (const std::exception &e)
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
return ANEURALNETWORKS_NO_ERROR;
}
diff --git a/runtimes/neurun/src/frontend/wrapper/compilation.h b/runtimes/neurun/src/frontend/wrapper/compilation.h
index 20d5a3d98..d4ba32ea5 100644
--- a/runtimes/neurun/src/frontend/wrapper/compilation.h
+++ b/runtimes/neurun/src/frontend/wrapper/compilation.h
@@ -17,27 +17,27 @@
#ifndef __COMPILATION_H__
#define __COMPILATION_H__
-#include "codegen/Plan.h"
+#include "compiler/Compiler.h"
#include "graph/Graph.h"
struct ANeuralNetworksCompilation
{
public:
ANeuralNetworksCompilation(const std::shared_ptr<neurun::graph::Graph> &model)
- : _plan{new neurun::codegen::Plan{model}}
+ : _compiler{new neurun::compiler::Compiler{model}}
{
// DO NOTHING
}
public:
- neurun::codegen::Plan &plan(void) { return *_plan; }
+ neurun::compiler::Plan &plan(void) { return _compiler->plan(); }
public:
- void publish(std::shared_ptr<const neurun::codegen::Plan> &plan) { plan = _plan; }
+ void publish(std::shared_ptr<const neurun::compiler::Plan> &plan) { _compiler->release(plan); }
int finish();
private:
- std::shared_ptr<neurun::codegen::Plan> _plan;
+ std::shared_ptr<neurun::compiler::Compiler> _compiler;
};
#endif
diff --git a/runtimes/neurun/src/frontend/wrapper/execution.h b/runtimes/neurun/src/frontend/wrapper/execution.h
index 374201eb2..b68a7b967 100644
--- a/runtimes/neurun/src/frontend/wrapper/execution.h
+++ b/runtimes/neurun/src/frontend/wrapper/execution.h
@@ -17,28 +17,28 @@
#ifndef __EXECUTION_H__
#define __EXECUTION_H__
-#include "codegen/Plan.h"
+#include "compiler/Plan.h"
#include "exec/Source.h"
#include "exec/Sink.h"
struct ANeuralNetworksExecution
{
public:
- ANeuralNetworksExecution(const std::shared_ptr<const neurun::codegen::Plan> &plan) : _plan{plan}
+ ANeuralNetworksExecution(const std::shared_ptr<const neurun::compiler::Plan> &plan) : _plan{plan}
{
_sources.resize(_plan->model().getInputs().size());
_sinks.resize(_plan->model().getOutputs().size());
}
public:
- const neurun::codegen::Plan &plan(void) const { return *_plan; }
+ const neurun::compiler::Plan &plan(void) const { return *_plan; }
private:
- std::shared_ptr<const neurun::codegen::Plan> _plan;
+ std::shared_ptr<const neurun::compiler::Plan> _plan;
public:
// TODO Use InputIndex instead of int
- void source(int n, std::unique_ptr<neurun::exec::Source> &&source)
+ void source(int n, std::unique_ptr<neurun::exec::ISource> &&source)
{
_sources.at(n) = std::move(source);
}
@@ -48,22 +48,22 @@ public:
}
public:
- const neurun::exec::Source &source(int n) const { return *(_sources.at(n)); }
+ const neurun::exec::ISource &source(int n) const { return *(_sources.at(n)); }
public:
// TODO Use OutputIndex instead of int
- void sink(int n, std::unique_ptr<neurun::exec::Sink> &&sink) { _sinks.at(n) = std::move(sink); }
+ void sink(int n, std::unique_ptr<neurun::exec::ISink> &&sink) { _sinks.at(n) = std::move(sink); }
template <typename T, typename... Args> void sink(int n, Args &&... args)
{
sink(n, std::unique_ptr<T>{new T{std::forward<Args>(args)...}});
}
public:
- const neurun::exec::Sink &sink(int n) const { return *(_sinks.at(n)); }
+ const neurun::exec::ISink &sink(int n) const { return *(_sinks.at(n)); }
private:
- std::vector<std::unique_ptr<neurun::exec::Source>> _sources;
- std::vector<std::unique_ptr<neurun::exec::Sink>> _sinks;
+ std::vector<std::unique_ptr<neurun::exec::ISource>> _sources;
+ std::vector<std::unique_ptr<neurun::exec::ISink>> _sinks;
};
#endif
diff --git a/runtimes/neurun/src/frontend/wrapper/model.cc b/runtimes/neurun/src/frontend/wrapper/model.cc
index c7ccbc60a..a7a9275fc 100644
--- a/runtimes/neurun/src/frontend/wrapper/model.cc
+++ b/runtimes/neurun/src/frontend/wrapper/model.cc
@@ -21,7 +21,8 @@
//
// ANeuralNetworksModel
//
-ANeuralNetworksModel::ANeuralNetworksModel() : _model{new neurun::graph::Graph}
+ANeuralNetworksModel::ANeuralNetworksModel()
+ : _model{new neurun::graph::Graph}, _optional_operands{}
{
// DO NOTHING
}
@@ -34,7 +35,24 @@ ResultCode ANeuralNetworksModel::finish()
return ANEURALNETWORKS_BAD_STATE;
}
+ fillOptionalOperand();
+
_model->finishBuilding();
return ANEURALNETWORKS_NO_ERROR;
}
+
+void ANeuralNetworksModel::fillOptionalOperand(void)
+{
+ _model->operations().iterate(
+ [&](const ::neurun::model::operation::Index &, ::neurun::model::operation::Node &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/runtimes/neurun/src/frontend/wrapper/model.h b/runtimes/neurun/src/frontend/wrapper/model.h
index 3c7b027dc..2386a648d 100644
--- a/runtimes/neurun/src/frontend/wrapper/model.h
+++ b/runtimes/neurun/src/frontend/wrapper/model.h
@@ -30,12 +30,18 @@ public:
neurun::graph::Graph &deref(void) { return *_model; }
ResultCode finish();
bool isFinished() { return !_model->isBuildingPhase(); }
-
-public:
void release(std::shared_ptr<neurun::graph::Graph> &model) { model = _model; }
+ void setOptionalOperand(const neurun::model::operand::Index idx)
+ {
+ _optional_operands.insert(idx);
+ }
+
+private:
+ void fillOptionalOperand(void);
private:
std::shared_ptr<neurun::graph::Graph> _model;
+ std::unordered_set<neurun::model::operand::Index> _optional_operands;
};
#endif // __MODEL_H__
diff --git a/runtimes/neurun/src/graph/Graph.cc b/runtimes/neurun/src/graph/Graph.cc
index 07194ff7e..832e2b887 100644
--- a/runtimes/neurun/src/graph/Graph.cc
+++ b/runtimes/neurun/src/graph/Graph.cc
@@ -19,116 +19,62 @@
#include <algorithm>
#include <bitset>
-#include "logging.h"
-#include "verifier/IVerifier.h"
-#include "nnfw/std/memory.h"
+#include "util/logging.h"
+#include "verifier/Verifier.h"
+#include "cpp14/memory.h"
#include "linear/Linear.h"
#include "operation/LowerInfo.h"
#include "operand/LowerInfo.h"
#include "operand/Shape4DConvert.h"
-#include "codegen/BackendResolver.h"
-#include "backend/IBackendConfig.h"
+#include "compiler/BackendResolver.h"
+#include "backend/interface/IConfig.h"
+#include "pass/PermutationInsertionPass.h"
+#include "pass/PermutationEliminationPass.h"
namespace neurun
{
namespace graph
{
-operand::Index Graph::addOperand(const operand::Shape &shape, const operand::TypeInfo &type)
-{
- return _operands.append(shape, type);
-}
+Graph::Graph(void) = default;
-operation::Index Graph::addOperation(std::unique_ptr<operation::Node> &&node)
+Graph::~Graph(void) = default;
+
+model::operand::Index Graph::addOperand(const model::operand::Shape &shape,
+ const model::operand::TypeInfo &type)
{
- assert(_phase == Phase::BUILDING);
- return _operations.append(std::move(node));
+ return _model->operands.append(shape, type);
}
-// TODO : If operand's use-def information is introduced,
-// Following API and implements would be refactored.
-/**
- * @brief Insert operation into between an operand and next operation.
- *
- * @param prev_operand_index is an previous operand index of insertion.
- * @param next_operation_index is an next operation index of insertion.
- * @param node is an operation::Node to insert.
- *
- * @return operation::Index
- */
-operation::Index Graph::insertOperation(const operand::Index &prev_operand_index,
- const operation::Index &next_operation_index,
- std::unique_ptr<operation::Node> &&node)
+model::operation::Index Graph::addOperation(std::unique_ptr<model::operation::Node> &&node)
{
- assert(_phase != Phase::BUILDING);
- auto &next_operation = _operations.at(next_operation_index);
- auto next_input_indexes = next_operation.getInputs();
-
- assert(next_input_indexes.contains(prev_operand_index));
- assert(node->getInputs().size() == 0); // node to be inserted must not have any inputs
-
- node->setInputs({prev_operand_index});
-
- // For multi input operation (ex. concat)
- operand::IndexSet index_set;
- auto cur_output_indexes = node->getOutputs();
- assert(cur_output_indexes.size() == 1); // Assume output of inserted node size always 1
- auto cur_output_index = cur_output_indexes.at(operand::IO::Index{0});
- // TODO : If the API for setting input one by one is introduced, it would be changed to simple.
- for (auto next_input_index : next_input_indexes)
- {
- if (prev_operand_index == next_input_index)
- {
- index_set.append(cur_output_index);
- }
- else
- {
- index_set.append(next_input_index);
- }
- }
-
- next_operation.setInputs(index_set);
-
- operation::Index node_index = _operations.append(std::move(node));
-
- // Update Use/Def info
- {
- _operands.at(prev_operand_index).removeUse(next_operation_index);
- _operands.at(cur_output_index).appendUse(next_operation_index);
-
- _operands.at(prev_operand_index).appendUse(node_index);
-
- auto node_output_indexes = _operations.at(node_index).getOutputs();
- assert(node_output_indexes.size() == 1);
- auto node_output_index = node_output_indexes.at(operand::IO::Index{0});
- _operands.at(node_output_index).appendDef(node_index);
- }
-
- return node_index;
+ assert(isBuildingPhase());
+ return _model->operations.append(std::move(node));
}
-void Graph::setOperandValue(const operand::Index &ind, std::unique_ptr<operand::Data> &&data)
+void Graph::setOperandValue(const model::operand::Index &ind,
+ std::unique_ptr<model::operand::Data> &&data)
{
- assert(_phase == Phase::BUILDING);
- assert(_operands.exist(ind));
- _operands.at(ind).data(std::move(data));
+ assert(isBuildingPhase());
+ assert(_model->operands.exist(ind));
+ _model->operands.at(ind).data(std::move(data));
}
-void Graph::addInput(const operand::Index &ind)
+void Graph::addInput(const model::operand::Index &ind)
{
- assert(_phase == Phase::BUILDING);
- _inputs.append(ind);
+ assert(isBuildingPhase());
+ _model->inputs.append(ind);
}
-void Graph::addOutput(const operand::Index &ind)
+void Graph::addOutput(const model::operand::Index &ind)
{
- assert(_phase == Phase::BUILDING);
- _outputs.append(ind);
+ assert(isBuildingPhase());
+ _model->outputs.append(ind);
}
void Graph::finishBuilding(void)
{
- assert(_phase == Phase::BUILDING);
+ assert(isBuildingPhase());
_phase = Phase::MODEL;
// Initialize operand use-def
@@ -136,8 +82,8 @@ void Graph::finishBuilding(void)
// Call graph verifications for the MODEL phase
{
- verifier::DAGChecker dag_checker;
- dag_checker.verify(*this);
+ assert(verifier::DAGChecker().verify(*this));
+ assert(verifier::EdgeConsistencyChecker().verify(*this));
}
}
@@ -148,106 +94,174 @@ void Graph::lower(void)
// Lower
{
// operand::LowerInfo holder
- std::unordered_map<operand::Index, std::unique_ptr<operand::LowerInfo>> operands_lower_info;
+ std::unordered_map<model::operand::Index, std::unique_ptr<operand::LowerInfo>>
+ operands_lower_info;
- _operands.iterate([&](const operand::Index &index, const operand::Object &object) {
+ _model->operands.iterate([&](const model::operand::Index &index,
+ const model::operand::Object &object) {
operands_lower_info[index] =
- nnfw::make_unique<operand::LowerInfo>(operand::asShape4D(object.shape()));
+ nnfw::cpp14::make_unique<operand::LowerInfo>(graph::operand::asShape4D(object.shape()));
});
- auto _backend_resolver = codegen::BackendResolver(_operands);
+ _backend_resolver = nnfw::cpp14::make_unique<compiler::BackendResolver>(_model->operands);
+
+ _model->operations.iterate(
+ [&](const model::operation::Index &index, model::operation::Node &node) {
+ auto backend = _backend_resolver->getBackend(typeid(node));
+
+ // Operation LowerInfo
+ setLowerInfo(index, nnfw::cpp14::make_unique<graph::operation::LowerInfo>(backend));
- _operations.iterate([&](const operation::Index &, operation::Node &node) {
- auto backend = _backend_resolver.getBackend(typeid(node));
+ // LowerInfo for in/output operands
+ for (auto operand : node.getInputs())
+ {
+ auto &&lower_info = operands_lower_info.at(operand);
+ lower_info->addUseBackend(backend);
+ }
+ for (auto operand : node.getOutputs())
+ {
+ auto &&lower_info = operands_lower_info.at(operand);
+ lower_info->addDefBackend(backend);
+ }
+ });
+
+ // Add def backend to model input/output operand as default backend
+ for (auto index : getInputs())
+ {
+ auto &&lower_info = operands_lower_info.at(index);
+ lower_info->addDefBackend(_backend_resolver->getDefaultBackend());
+ }
- // Operation LowerInfo
- node.lower_info(nnfw::make_unique<operation::LowerInfo>(backend));
+ for (auto index : getOutputs())
+ {
+ auto &&lower_info = operands_lower_info.at(index);
+ lower_info->addUseBackend(_backend_resolver->getDefaultBackend());
+ }
- // LowerInfo for in/output operands
+ // Add DefBackend constants same as UseBackend
+ // NOTE This assumes a constant operand is used by only one operation
+ _model->operations.iterate([&](const model::operation::Index &, model::operation::Node &node) {
+ // LowerInfo for input operands
for (auto operand : node.getInputs())
{
auto &&lower_info = operands_lower_info.at(operand);
- lower_info->addUseLayout(backend.config()->getOperandLayout());
- }
- for (auto operand : node.getOutputs())
- {
- auto &&lower_info = operands_lower_info.at(operand);
- lower_info->addDefLayout(backend.config()->getOperandLayout());
+ if (lower_info->def_backends().empty())
+ {
+ lower_info->addDefBackend(lower_info->use_backends().getOnlyElement());
+ }
}
});
// Set LowerInfo for each operand from the operand::LowerInfo holder
- _operands.iterate([&](const operand::Index &index, operand::Object &object) {
+ _model->operands.iterate([&](const model::operand::Index &index,
+ model::operand::Object &object) {
object.lower_info(std::move(operands_lower_info[index]));
// Dump operand LowerInfo
+ // TODO Extract this dumping procedure to be reusable
+ if (!object.lower_info()->def_backends().empty() ||
+ !object.lower_info()->use_backends().empty())
{
- auto layouts_to_string = [](const operand::LayoutSet &layouts) {
+ auto backends_to_string = [](const operand::BackendSet &backends) {
std::string str;
- for (auto layout : layouts)
+ for (auto backend : backends)
{
- const char *name = "";
- if (layout == operand::Layout::NHWC)
- name = "NHWC";
- if (layout == operand::Layout::NCHW)
- name = "NCHW";
- str += name;
+ str += backend->config()->id();
+ str += " ";
+ }
+ return "{ " + str + "}";
+ };
+
+ auto operation_index_to_string = [](const model::operation::IndexList &operations) {
+ std::string str;
+ for (auto op : operations.list())
+ {
+ str += std::to_string(op.value());
str += " ";
}
return "{ " + str + "}";
};
const auto &lower_info = object.lower_info();
- const auto &shape = lower_info->shape();
- std::string def_layouts = layouts_to_string(lower_info->def_layouts());
- std::string use_layouts = layouts_to_string(lower_info->use_layouts());
+ const auto &shape = object.shape();
+ const auto &lower_shape = lower_info->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 = backends_to_string(lower_info->def_backends());
+ std::string use_layouts = backends_to_string(lower_info->use_backends());
VERBOSE(Lower) << "* Operand #" << index.value() << " LowerInfo" << std::endl;
- VERBOSE(Lower) << " - 4D Shape (NHWC) : { " << shape.n() << " " << shape.h() << " "
- << shape.w() << " " << shape.c() << " "
+ VERBOSE(Lower) << " - Shape : { " << shape.dim(0) << " "
+ << (shape.rank() > 1 ? shape.dim(1) : 0) << " "
+ << (shape.rank() > 2 ? shape.dim(2) : 0) << " "
+ << (shape.rank() > 3 ? shape.dim(3) : 0) << " "
<< "}" << std::endl;
- VERBOSE(Lower) << " - Def Layout : " << def_layouts << std::endl;
- VERBOSE(Lower) << " - Use Layout : " << use_layouts << std::endl;
+ VERBOSE(Lower) << " - Def Operations : " << def_ops << std::endl;
+ VERBOSE(Lower) << " - Use Operations : " << use_ops << std::endl;
+ VERBOSE(Lower) << " - Lower Info" << std::endl;
+ VERBOSE(Lower) << " - 4D Shape (NHWC) : { " << lower_shape.n() << " " << lower_shape.h()
+ << " " << lower_shape.w() << " " << lower_shape.c() << " "
+ << "}" << std::endl;
+ VERBOSE(Lower) << " - Def Backends : " << def_layouts << std::endl;
+ VERBOSE(Lower) << " - Use Backends : " << use_layouts << std::endl;
}
});
}
- // Graph verifications for the LOWERED phase
+ // Run PermutationInsertionPass
{
- verifier::DAGChecker dag_checker;
- dag_checker.verify(*this);
+ pass::PermutationInsertionPass pi_pass(*this);
+ pi_pass.run();
+ pass::PermutationEliminationPass pe_pass(*this);
+ pe_pass.run();
}
- _phase = Phase::LOWERED;
+ // Graph verifications for the LOWERED phase
+ {
+ assert(verifier::DAGChecker().verify(*this));
+ assert(verifier::EdgeConsistencyChecker().verify(*this));
+ }
}
std::unique_ptr<linear::Linear> Graph::linearize(void)
{
- assert(_phase == Phase::LOWERED);
+ assert(_phase == Phase::MODEL);
- auto linear = nnfw::make_unique<linear::Linear>(*this);
+ auto linear = nnfw::cpp14::make_unique<linear::Linear>(*this);
// TODO Move the operations and operands to linear object
-
- _phase = Phase::LINEARIZED;
-
return std::move(linear);
}
void Graph::initializeUseDef()
{
- operations().iterate([&](const operation::Index &index, const operation::Node &node) -> void {
- auto outputs = node.getOutputs();
- for (auto output : outputs)
- {
- operands().at(output).appendDef(index);
- }
+ operations().iterate(
+ [&](const model::operation::Index &index, const model::operation::Node &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);
+ }
+ });
+}
- auto inputs = node.getInputs();
- for (auto input : inputs)
- {
- operands().at(input).appendUse(index);
- }
- });
+const operation::LowerInfo *Graph::getLowerInfo(const model::operation::Index &index) const
+{
+ auto itr = _operation_lower_info.find(index);
+ if (itr == _operation_lower_info.end())
+ return nullptr;
+ return itr->second.get();
+}
+
+void Graph::setLowerInfo(const model::operation::Index &index,
+ std::unique_ptr<operation::LowerInfo> &&lower_info)
+{
+ _operation_lower_info.insert(std::make_pair(index, std::move(lower_info)));
}
} // namespace graph
@@ -273,7 +287,8 @@ template class Graph::PostDfsIterator<false>;
template <bool is_const>
void Graph::DefaultIterator<is_const>::iterate(GraphRef graph, const IterFn &fn) const
{
- graph._operations.iterate([&](const operation::Index &, NodeRef node) -> void { fn(node); });
+ graph.operations().iterate(
+ [&](const model::operation::Index &index, NodeRef node) -> void { fn(index, node); });
}
//
@@ -285,30 +300,34 @@ void Graph::PostDfsIterator<is_const>::iterate(GraphRef graph, const IterFn &fn)
{
assert(!graph.isBuildingPhase()); // Restrict iteration condition
- std::vector<bool> visited(graph._operations.size(), false);
+ std::unordered_map<model::operation::Index, bool> visited;
+ graph.operations().iterate(
+ [&](const model::operation::Index &index, NodeRef) { visited[index] = false; });
- std::function<void(const operation::Index &, NodeRef)> dfs_recursive =
- [&](const operation::Index &index, NodeRef node) -> void {
- if (visited[index.asInt()])
+ std::function<void(const model::operation::Index &, NodeRef)> dfs_recursive =
+ [&](const model::operation::Index &index, NodeRef node) -> void {
+ if (visited[index])
return;
- visited[index.asInt()] = true;
+ visited[index] = true;
for (auto output : node.getOutputs())
{
- const auto &operand = graph._operands.at(output);
+ const auto &operand = graph.operands().at(output);
for (const auto &use : operand.getUses().list())
{
- dfs_recursive(use, graph._operations.at(use));
+ dfs_recursive(use, graph.operations().at(use));
}
}
- fn(node);
+ fn(index, node);
};
- graph._operations.iterate(dfs_recursive);
+ graph.operations().iterate(dfs_recursive);
// All of the operations(nodes) must have been visited.
- assert(std::all_of(visited.begin(), visited.end(), [](bool v) { return v; }));
+ assert(std::all_of(
+ visited.begin(), visited.end(),
+ [](const std::pair<const model::operation::Index, bool> &v) { return v.second; }));
}
} // namespace graph
diff --git a/runtimes/neurun/src/graph/Graph.h b/runtimes/neurun/src/graph/Graph.h
index dd1489a93..afcfdce12 100644
--- a/runtimes/neurun/src/graph/Graph.h
+++ b/runtimes/neurun/src/graph/Graph.h
@@ -19,10 +19,8 @@
#include <functional>
-#include "graph/operation/Node.h"
-#include "graph/operation/Set.h"
-#include "graph/operand/IndexSet.h"
-#include "graph/operand/Set.h"
+#include "model/operation/Node.h"
+#include "graph/Model.h"
namespace neurun
{
@@ -34,6 +32,14 @@ class Linear;
namespace neurun
{
+namespace compiler
+{
+class BackendResolver;
+} // namespace compiler
+} // namespace neurun
+
+namespace neurun
+{
namespace graph
{
@@ -43,9 +49,7 @@ private:
enum class Phase
{
BUILDING,
- MODEL,
- LOWERED,
- LINEARIZED // Everything is moved to Linear object so this Graph object is no longer effective
+ MODEL
};
public:
@@ -53,9 +57,10 @@ public:
{
public:
using GraphRef = typename std::conditional<is_const, const Graph &, Graph &>::type;
- using NodeRef =
- typename std::conditional<is_const, const operation::Node &, operation::Node &>::type;
- using IterFn = std::function<void(NodeRef)>;
+ using IndexRef = const model::operation::Index &;
+ using NodeRef = typename std::conditional<is_const, const model::operation::Node &,
+ model::operation::Node &>::type;
+ using IterFn = std::function<void(IndexRef, NodeRef)>;
public:
virtual ~Iterator() = default;
@@ -66,6 +71,7 @@ public:
{
public:
using GraphRef = typename Iterator<is_const>::GraphRef;
+ using IndexRef = typename Iterator<is_const>::IndexRef;
using NodeRef = typename Iterator<is_const>::NodeRef;
using IterFn = typename Iterator<is_const>::IterFn;
@@ -78,6 +84,7 @@ public:
{
public:
using GraphRef = typename Iterator<is_const>::GraphRef;
+ using IndexRef = typename Iterator<is_const>::IndexRef;
using NodeRef = typename Iterator<is_const>::NodeRef;
using IterFn = typename Iterator<is_const>::IterFn;
@@ -87,20 +94,21 @@ public:
using PostDfsConstIterator = PostDfsIterator<true>;
public:
- Graph(void) = default;
+ Graph(void);
+ ~Graph(void);
// Graph Building
public:
- operand::Index addOperand(const operand::Shape &shape, const operand::TypeInfo &type);
- operation::Index addOperation(std::unique_ptr<operation::Node> &&node);
- operation::Index insertOperation(const operand::Index &prev_operand_index,
- const operation::Index &next_operation_index,
- std::unique_ptr<operation::Node> &&node);
- void setOperandValue(const operand::Index &ind, std::unique_ptr<operand::Data> &&data);
- void addInput(const operand::Index &ind);
- void addOutput(const operand::Index &ind);
+ model::operand::Index addOperand(const model::operand::Shape &shape,
+ const model::operand::TypeInfo &type);
+ model::operation::Index addOperation(std::unique_ptr<model::operation::Node> &&node);
+ void setOperandValue(const model::operand::Index &ind,
+ std::unique_ptr<model::operand::Data> &&data);
+ void addInput(const model::operand::Index &ind);
+ void addOutput(const model::operand::Index &ind);
void finishBuilding(void);
void lower(void);
+ void removeOperand(const model::operand::Index &ind) { _model->operands.remove(ind); }
std::unique_ptr<linear::Linear> linearize(void);
bool isBuildingPhase(void) const { return _phase == Phase::BUILDING; }
@@ -109,18 +117,33 @@ private:
// Accessors
public:
- const operand::IndexSet &getInputs() const { return _inputs; }
- const operand::IndexSet &getOutputs() const { return _outputs; }
- const operand::Set &operands() const { return _operands; }
- operand::Set &operands() { return _operands; } // TODO Remove this non-const accessor
- const operation::Set &operations() const { return _operations; }
+ const model::operand::IndexSet &getInputs() const { return _model->inputs; }
+ model::operand::IndexSet &getInputs() { return _model->inputs; }
+ const model::operand::IndexSet &getOutputs() const { return _model->outputs; }
+ model::operand::IndexSet &getOutputs() { return _model->outputs; }
+ const model::operand::Set &operands() const { return _model->operands; }
+ model::operand::Set &operands()
+ {
+ return _model->operands;
+ } // TODO Remove this non-const accessor
+ const model::operation::Set &operations() const { return _model->operations; }
+ model::operation::Set &operations() { return _model->operations; }
+ const compiler::BackendResolver *backend_resolver() const { return _backend_resolver.get(); }
private:
Phase _phase{Phase::BUILDING};
- operation::Set _operations;
- operand::Set _operands;
- operand::IndexSet _inputs;
- operand::IndexSet _outputs;
+ std::unique_ptr<Model> _model{new Model};
+
+ // For LOWERED phase
+public:
+ const operation::LowerInfo *getLowerInfo(const model::operation::Index &index) const;
+ void setLowerInfo(const model::operation::Index &index,
+ std::unique_ptr<operation::LowerInfo> &&lower_info);
+
+private:
+ std::unique_ptr<compiler::BackendResolver> _backend_resolver;
+ std::unordered_map<model::operation::Index, std::unique_ptr<operation::LowerInfo>>
+ _operation_lower_info;
};
} // namespace graph
diff --git a/runtimes/neurun/src/graph/Index.h b/runtimes/neurun/src/graph/Index.h
index 864aaffd0..3263d12ad 100644
--- a/runtimes/neurun/src/graph/Index.h
+++ b/runtimes/neurun/src/graph/Index.h
@@ -18,6 +18,7 @@
#define __NEURUN_GRAPH_INDEX_H__
#include <functional>
+#include <limits>
#include <stdint.h>
namespace neurun
@@ -27,7 +28,11 @@ namespace graph
template <typename T, typename DummyTag> class Index
{
+private:
+ static const T UNDEFINED = std::numeric_limits<T>::max();
+
public:
+ explicit Index(void) : _index{UNDEFINED} {}
explicit Index(T o) : _index{o} {}
explicit Index(int32_t o) : _index{static_cast<T>(o)} {} // For legacy code compatibility
Index(const Index &o) : _index{o._index} {}
diff --git a/runtimes/neurun/src/graph/Model.h b/runtimes/neurun/src/graph/Model.h
new file mode 100644
index 000000000..20bb713af
--- /dev/null
+++ b/runtimes/neurun/src/graph/Model.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 __NEURUN_GRAPH_MODEL_H__
+#define __NEURUN_GRAPH_MODEL_H__
+
+#include "model/operation/Set.h"
+#include "model/operand/IndexSet.h"
+#include "model/operand/Set.h"
+
+namespace neurun
+{
+namespace graph
+{
+
+struct Model
+{
+ model::operation::Set operations;
+ model::operand::Set operands;
+ model::operand::IndexSet inputs;
+ model::operand::IndexSet outputs;
+};
+
+} // namespace graph
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_MODEL_H__
diff --git a/runtimes/neurun/src/graph/dumper/Dumper.cc b/runtimes/neurun/src/graph/dumper/Dumper.cc
index 3788317ce..efffc5849 100644
--- a/runtimes/neurun/src/graph/dumper/Dumper.cc
+++ b/runtimes/neurun/src/graph/dumper/Dumper.cc
@@ -18,7 +18,7 @@
#include <string>
-#include "logging.h"
+#include "util/logging.h"
namespace neurun
{
@@ -27,9 +27,9 @@ namespace graph
namespace dumper
{
-using namespace neurun::graph::operation;
+using namespace neurun::model::operation;
-void Dumper::visit(const Conv2D::Implicit::Node &node)
+void Dumper::visit(const Conv2DNode &node)
{
VERBOSE(LIR) << "* Conv2D(Implicit)" << std::endl;
VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ") Kernel("
@@ -38,21 +38,21 @@ void Dumper::visit(const Conv2D::Implicit::Node &node)
VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
}
-void Dumper::visit(const MaxPool2D::Implicit::Node &node)
+void Dumper::visit(const MaxPool2DNode &node)
{
VERBOSE(LIR) << "* MaxPool2D(Implicit)" << std::endl;
VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ")" << std::endl;
VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
}
-void Dumper::visit(const AvgPool2D::Implicit::Node &node)
+void Dumper::visit(const AvgPool2DNode &node)
{
VERBOSE(LIR) << "* AvgPool2D(Implicit)" << std::endl;
VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ")" << std::endl;
VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
}
-void Dumper::visit(const Concat::Node &node)
+void Dumper::visit(const ConcatNode &node)
{
VERBOSE(LIR) << "* Concat" << std::endl;
std::string inputs;
@@ -64,7 +64,7 @@ void Dumper::visit(const Concat::Node &node)
VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
}
-void Dumper::visit(const FullyConnected::Node &node)
+void Dumper::visit(const FullyConnectedNode &node)
{
VERBOSE(LIR) << "* FullyConnected" << std::endl;
VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ") Weight("
@@ -73,7 +73,7 @@ void Dumper::visit(const FullyConnected::Node &node)
VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
}
-void Dumper::visit(const Reshape::Node &node)
+void Dumper::visit(const ReshapeNode &node)
{
VERBOSE(LIR) << "* Reshape" << std::endl;
// TODO The shape index should be "node.getInputs().at(1).value()" but not valid for now
@@ -83,36 +83,28 @@ void Dumper::visit(const Reshape::Node &node)
VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
}
-void Dumper::visit(const Softmax::Node &node)
+void Dumper::visit(const SoftmaxNode &node)
{
VERBOSE(LIR) << "* Softmax" << std::endl;
VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ")" << std::endl;
VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
}
-void Dumper::visit(const NOP::Node &node)
-{
- VERBOSE(LIR) << "* NOP" << std::endl;
- std::string inputs, outputs;
- for (auto i : node.getInputs())
- {
- inputs += std::to_string(i.value()) + ",";
- }
- VERBOSE(LIR) << " - Inputs : IFM(" << inputs << ")" << std::endl;
- for (auto i : node.getOutputs())
- {
- outputs += std::to_string(i.value()) + ",";
- }
- VERBOSE(LIR) << " - Outputs : OFM(" << outputs << ")" << std::endl;
-}
-
-void Dumper::visit(const Permute::Node &node)
+void Dumper::visit(const PermuteNode &node)
{
VERBOSE(LIR) << "* Permute" << std::endl;
VERBOSE(LIR) << " - Inputs : IFM(" << node.getInputs().at(0).value() << ")" << std::endl;
VERBOSE(LIR) << " - Output : OFM(" << node.getOutputs().at(0).value() << ")" << std::endl;
}
+void Dumper::visit(const AddNode &node)
+{
+ VERBOSE(LIR) << "* Add" << std::endl;
+ VERBOSE(LIR) << " - Inputs : Input(" << node.getInputs().at(0).value() << ", "
+ << node.getInputs().at(1).value() << ")" << std::endl;
+ VERBOSE(LIR) << " - Output : Output(" << node.getOutputs().at(0).value() << ")" << std::endl;
+}
+
} // namespace dumper
} // namespace graph
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/dumper/Dumper.h b/runtimes/neurun/src/graph/dumper/Dumper.h
index dee490cbd..8c079a11d 100644
--- a/runtimes/neurun/src/graph/dumper/Dumper.h
+++ b/runtimes/neurun/src/graph/dumper/Dumper.h
@@ -17,7 +17,7 @@
#ifndef __NEURUN_GRAPH_DUMPER_H__
#define __NEURUN_GRAPH_DUMPER_H__
-#include "graph/operation/NodeVisitor.h"
+#include "model/operation/NodeVisitor.h"
namespace neurun
{
@@ -26,21 +26,21 @@ namespace graph
namespace dumper
{
-class Dumper : public graph::operation::NodeVisitor
+class Dumper : public model::operation::NodeVisitor
{
public:
Dumper() = default;
public:
- void visit(const graph::operation::Conv2D::Implicit::Node &node) override;
- void visit(const graph::operation::MaxPool2D::Implicit::Node &node) override;
- void visit(const graph::operation::AvgPool2D::Implicit::Node &node) override;
- void visit(const graph::operation::Concat::Node &node) override;
- void visit(const graph::operation::FullyConnected::Node &node) override;
- void visit(const graph::operation::Reshape::Node &node) override;
- void visit(const graph::operation::Softmax::Node &node) override;
- void visit(const graph::operation::NOP::Node &node) override;
- void visit(const graph::operation::Permute::Node &node) override;
+ void visit(const model::operation::Conv2DNode &node) override;
+ void visit(const model::operation::MaxPool2DNode &node) override;
+ void visit(const model::operation::AvgPool2DNode &node) override;
+ void visit(const model::operation::ConcatNode &node) override;
+ void visit(const model::operation::FullyConnectedNode &node) override;
+ void visit(const model::operation::ReshapeNode &node) override;
+ void visit(const model::operation::SoftmaxNode &node) override;
+ void visit(const model::operation::PermuteNode &node) override;
+ void visit(const model::operation::AddNode &node) override;
};
} // namespace dumper
diff --git a/runtimes/neurun/src/graph/operand/BackendSet.cc b/runtimes/neurun/src/graph/operand/BackendSet.cc
new file mode 100644
index 000000000..9a284d722
--- /dev/null
+++ b/runtimes/neurun/src/graph/operand/BackendSet.cc
@@ -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.
+ */
+
+#include "BackendSet.h"
+
+#include <cassert>
+
+namespace neurun
+{
+namespace graph
+{
+namespace operand
+{
+
+BackendSet::BackendSet(std::initializer_list<const backend::Backend *> backends)
+{
+ for (auto backend : backends)
+ {
+ _set.insert(backend);
+ }
+}
+
+const backend::Backend *BackendSet::getOnlyElement() const
+{
+ assert(_set.size() == 1u);
+ return *_set.begin();
+}
+
+BackendSet BackendSet::operator|(const BackendSet &other) const
+{
+ auto ret = *this;
+ for (auto backend : other)
+ {
+ ret.add(backend);
+ }
+ return ret;
+}
+
+BackendSet BackendSet::operator&(const BackendSet &other) const
+{
+ BackendSet ret;
+ for (auto backend : other)
+ {
+ if (contains(backend))
+ {
+ ret.add(backend);
+ }
+ }
+ return ret;
+}
+
+BackendSet BackendSet::operator-(const BackendSet &other) const
+{
+ auto ret = *this;
+ for (auto backend : other)
+ {
+ ret.remove(backend);
+ }
+ return ret;
+}
+
+} // namespace operand
+} // namespace graph
+} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operand/BackendSet.h b/runtimes/neurun/src/graph/operand/BackendSet.h
new file mode 100644
index 000000000..8b457a084
--- /dev/null
+++ b/runtimes/neurun/src/graph/operand/BackendSet.h
@@ -0,0 +1,72 @@
+/*
+ * 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 __NEURUN_GRAPH_OPERAND_BACKEND_SET_H__
+#define __NEURUN_GRAPH_OPERAND_BACKEND_SET_H__
+
+#include <initializer_list>
+#include <unordered_set>
+
+namespace neurun
+{
+namespace backend
+{
+class Backend;
+} // namespace backend
+} // namespace neurun
+
+namespace neurun
+{
+namespace graph
+{
+namespace operand
+{
+
+class BackendSet
+{
+public:
+ BackendSet() = default;
+ BackendSet(std::initializer_list<const backend::Backend *> backends);
+
+public:
+ void add(const backend::Backend *backend) { _set.insert(backend); }
+ void remove(const backend::Backend *backend) { _set.erase(backend); }
+ uint32_t size() const { return static_cast<uint32_t>(_set.size()); }
+ bool empty() const { return _set.empty(); }
+ bool contains(const backend::Backend *backend) const { return _set.find(backend) != _set.end(); }
+ const backend::Backend *getOnlyElement() const;
+
+public:
+ BackendSet operator|(const BackendSet &other) const; // Union
+ BackendSet operator&(const BackendSet &other) const; // Intersect
+ BackendSet operator-(const BackendSet &other) const; // Minus
+
+public:
+ std::unordered_set<const backend::Backend *>::const_iterator begin() const
+ {
+ return _set.begin();
+ }
+ std::unordered_set<const backend::Backend *>::const_iterator end() const { return _set.end(); }
+
+private:
+ std::unordered_set<const backend::Backend *> _set;
+};
+
+} // namespace operand
+} // namespace graph
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_OPERAND_BACKEND_SET_H__
diff --git a/runtimes/neurun/src/graph/operand/LowerInfo.h b/runtimes/neurun/src/graph/operand/LowerInfo.h
index d91c29fb7..7900e54d9 100644
--- a/runtimes/neurun/src/graph/operand/LowerInfo.h
+++ b/runtimes/neurun/src/graph/operand/LowerInfo.h
@@ -19,7 +19,7 @@
#include <stdint.h>
-#include "LayoutSet.h"
+#include "BackendSet.h"
namespace neurun
{
@@ -60,17 +60,19 @@ public:
public:
const Shape4D &shape(void) const { return _shape; }
- const LayoutSet &def_layouts(void) const { return _def_layouts; }
- const LayoutSet &use_layouts(void) const { return _use_layouts; }
+ const BackendSet &def_backends(void) const { return _def_backends; }
+ const BackendSet &use_backends(void) const { return _use_backends; }
public:
- void addDefLayout(const Layout &layout) { _def_layouts.add(layout); }
- void addUseLayout(const Layout &layout) { _use_layouts.add(layout); }
+ void addDefBackend(const backend::Backend *backend) { _def_backends.add(backend); }
+ void addUseBackend(const backend::Backend *backend) { _use_backends.add(backend); }
+ void removeDefBackend(const backend::Backend *backend) { _def_backends.remove(backend); }
+ void removeUseBackend(const backend::Backend *backend) { _use_backends.remove(backend); }
private:
Shape4D _shape;
- LayoutSet _def_layouts;
- LayoutSet _use_layouts;
+ BackendSet _def_backends;
+ BackendSet _use_backends;
};
} // namespace operand
diff --git a/runtimes/neurun/src/graph/operand/ParentInfo.h b/runtimes/neurun/src/graph/operand/ParentInfo.h
new file mode 100644
index 000000000..5e6f56237
--- /dev/null
+++ b/runtimes/neurun/src/graph/operand/ParentInfo.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 ParentInfo.h
+ * @brief This file contains ParentInfo class and internal Coordinate4D class
+ * to represent subsumption between operand
+ */
+
+#ifndef __NEURUN_GRAPH_OPERAND_PARENT_INFO_H__
+#define __NEURUN_GRAPH_OPERAND_PARENT_INFO_H__
+
+#include <stdint.h>
+
+#include "model/operand/Index.h"
+#include "util/feature/Coordinate4D.h"
+
+namespace neurun
+{
+namespace graph
+{
+namespace operand
+{
+
+using neurun::util::feature::Coordinate4D;
+
+/**
+ * @brief Class to represent parent operand in child operand
+ */
+class ParentInfo
+{
+public:
+ /**
+ * @brief Construct a new ParentInfo object
+ * @param[in] parent Index of parent operand
+ * @param[in] coordinate Offset of child operand in parent operand
+ * @return
+ */
+ ParentInfo(const model::operand::Index parent, const Coordinate4D &coordinate)
+ : _parent{parent}, _coordinate{coordinate}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return parent index
+ * @return Parent index
+ */
+ model::operand::Index parent(void) const { return _parent; }
+ /**
+ * @brief Retern offset in parent
+ * @return Offset
+ */
+ Coordinate4D offset(void) const { return _coordinate; }
+
+private:
+ model::operand::Index _parent;
+ Coordinate4D _coordinate;
+};
+
+} // namespace operand
+} // namespace graph
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_OPERAND_PARENT_INFO_H__
diff --git a/runtimes/neurun/src/graph/operand/Shape4DConvert.h b/runtimes/neurun/src/graph/operand/Shape4DConvert.h
index b840d19b8..73cf0903a 100644
--- a/runtimes/neurun/src/graph/operand/Shape4DConvert.h
+++ b/runtimes/neurun/src/graph/operand/Shape4DConvert.h
@@ -26,7 +26,7 @@ namespace graph
namespace operand
{
-inline LowerInfo::Shape4D asShape4D(const Shape &shape)
+inline LowerInfo::Shape4D asShape4D(const model::operand::Shape &shape)
{
switch (shape.rank())
{
@@ -34,16 +34,16 @@ inline LowerInfo::Shape4D asShape4D(const Shape &shape)
return LowerInfo::Shape4D(1, 1, 1, 1);
case 1u:
- return LowerInfo::Shape4D(1, 1, 1, shape.dim(0));
+ return LowerInfo::Shape4D(shape.dim(0), 1, 1, 1);
case 2u:
- return LowerInfo::Shape4D(1, 1, shape.dim(1), shape.dim(0));
+ return LowerInfo::Shape4D(shape.dim(0), shape.dim(1), 1, 1);
case 3u:
- return LowerInfo::Shape4D(1, shape.dim(2), shape.dim(1), shape.dim(0));
+ return LowerInfo::Shape4D(shape.dim(0), shape.dim(1), shape.dim(2), 1);
case 4u:
- return LowerInfo::Shape4D(shape.dim(3), shape.dim(2), shape.dim(1), shape.dim(0));
+ return LowerInfo::Shape4D(shape.dim(0), shape.dim(1), shape.dim(2), shape.dim(3));
default:
throw "Unsupported rank > 4";
diff --git a/runtimes/neurun/src/graph/operation/AvgPool2D.h b/runtimes/neurun/src/graph/operation/AvgPool2D.h
deleted file mode 100644
index a856b9cd4..000000000
--- a/runtimes/neurun/src/graph/operation/AvgPool2D.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 __NEURUN_GRAPH_OPERATION_AVGPOOL2D_H__
-#define __NEURUN_GRAPH_OPERATION_AVGPOOL2D_H__
-
-#include <memory>
-
-#include "graph/operation/Node.h"
-
-namespace neurun
-{
-namespace graph
-{
-namespace operation
-{
-namespace AvgPool2D
-{
-namespace Implicit
-{
-
-struct Param
-{
- int32_t kw_index;
- int32_t kh_index;
-
- int32_t hstride_index;
- int32_t vstride_index;
-
- int32_t padding_index;
- int32_t activation_index;
-};
-
-class Node : public graph::operation::Node
-{
-public:
- Node(const graph::operation::Node::InitParam &init_param);
-
-public:
- virtual void accept(NodeVisitor &&) const override;
-
-public:
- virtual void setInputs(const operand::IndexSet &indexes) override;
- virtual void setOutputs(const operand::IndexSet &indexes) override;
-
-public:
- const Param &param() const { return _param; }
-
-private:
- Param _param;
-};
-
-} // namespace Implicit
-} // namespace AvgPool2D
-} // namespace operation
-} // namespace graph
-} // namespace neurun
-
-#endif // __NEURUN_GRAPH_OPERATION_AVGPOOL2D_H__
diff --git a/runtimes/neurun/src/graph/operation/LowerInfo.cc b/runtimes/neurun/src/graph/operation/LowerInfo.cc
index 2998b1922..7862fd0c9 100644
--- a/runtimes/neurun/src/graph/operation/LowerInfo.cc
+++ b/runtimes/neurun/src/graph/operation/LowerInfo.cc
@@ -23,7 +23,7 @@ namespace graph
namespace operation
{
-LowerInfo::LowerInfo(const backend::Backend &backend) : _backend(backend)
+LowerInfo::LowerInfo(const backend::Backend *backend) : _backend(backend)
{
// DO NOTHING
}
diff --git a/runtimes/neurun/src/graph/operation/LowerInfo.h b/runtimes/neurun/src/graph/operation/LowerInfo.h
index f3fbbf178..e920b0eb9 100644
--- a/runtimes/neurun/src/graph/operation/LowerInfo.h
+++ b/runtimes/neurun/src/graph/operation/LowerInfo.h
@@ -31,11 +31,11 @@ namespace operation
class LowerInfo
{
public:
- LowerInfo(const backend::Backend &backend);
- const backend::Backend &backend() const { return _backend; }
+ LowerInfo(const backend::Backend *backend);
+ const backend::Backend *backend() const { return _backend; }
private:
- backend::Backend _backend;
+ const backend::Backend *_backend;
};
} // namespace operation
diff --git a/runtimes/neurun/src/graph/operation/NodeVisitor.h b/runtimes/neurun/src/graph/operation/NodeVisitor.h
deleted file mode 100644
index 28d19b0af..000000000
--- a/runtimes/neurun/src/graph/operation/NodeVisitor.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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 __NEURUN_GRAPH_OPERATION_NODE_VISITOR_H__
-#define __NEURUN_GRAPH_OPERATION_NODE_VISITOR_H__
-
-#include "Conv2D.h"
-#include "MaxPool2D.h"
-#include "AvgPool2D.h"
-#include "Concat.h"
-#include "Reshape.h"
-#include "FullyConnected.h"
-#include "Softmax.h"
-#include "NOP.h"
-#include "Permute.h"
-
-namespace neurun
-{
-namespace graph
-{
-namespace operation
-{
-
-struct NodeVisitor
-{
- virtual ~NodeVisitor() = default;
-
- virtual void visit(const Conv2D::Implicit::Node &) = 0;
- virtual void visit(const MaxPool2D::Implicit::Node &) = 0;
- virtual void visit(const AvgPool2D::Implicit::Node &) = 0;
- virtual void visit(const Concat::Node &) = 0;
- virtual void visit(const Reshape::Node &) = 0;
- virtual void visit(const FullyConnected::Node &) = 0;
- virtual void visit(const Softmax::Node &) = 0;
- virtual void visit(const NOP::Node &) = 0;
- virtual void visit(const Permute::Node &) = 0;
-};
-
-} // namespace operation
-} // namespace graph
-} // namespace neurun
-
-#endif // __NEURUN_GRAPH_OPERATION_NODE_VISITOR_H__
diff --git a/runtimes/neurun/src/graph/operation/Permute.cc b/runtimes/neurun/src/graph/operation/Permute.cc
deleted file mode 100644
index 2688e5e5f..000000000
--- a/runtimes/neurun/src/graph/operation/Permute.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-#include "Permute.h"
-
-#include <cassert>
-
-#include "NodeVisitor.h"
-
-namespace neurun
-{
-namespace graph
-{
-namespace operation
-{
-namespace Permute
-{
-
-void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
-
-Node::Node(const operand::Index &input, const operand::Index &output)
-{
- setInputs({input});
- setOutputs({output});
-}
-
-void Node::setInputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setInputs(indexes);
-}
-
-void Node::setOutputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setOutputs(indexes);
-}
-
-} // namespace Permute
-} // namespace operation
-} // namespace graph
-} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/Permute.h b/runtimes/neurun/src/graph/operation/Permute.h
deleted file mode 100644
index 540f869b1..000000000
--- a/runtimes/neurun/src/graph/operation/Permute.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __NEURUN_GRAPH_OPERATION_PERMUTE_PERMUTE_H__
-#define __NEURUN_GRAPH_OPERATION_PERMUTE_PERMUTE_H__
-
-#include "graph/operation/Node.h"
-
-namespace neurun
-{
-namespace graph
-{
-namespace operation
-{
-namespace Permute
-{
-
-class Node : public graph::operation::Node
-{
-public:
- virtual void accept(NodeVisitor &&) const override;
-
-public:
- Node(const operand::Index &input, const operand::Index &output);
-
-public:
- virtual void setInputs(const operand::IndexSet &indexes) override;
- virtual void setOutputs(const operand::IndexSet &indexes) override;
-};
-
-} // namespace Permute
-} // namespace operation
-} // namespace graph
-} // namespace neurun
-
-#endif // __NEURUN_GRAPH_OPERATION_PERMUTE_PERMUTE_H__
diff --git a/runtimes/neurun/src/graph/operation/NOP.cc b/runtimes/neurun/src/graph/pass/OperandPass.cc
index 18c3246ce..3c24d3830 100644
--- a/runtimes/neurun/src/graph/operation/NOP.cc
+++ b/runtimes/neurun/src/graph/pass/OperandPass.cc
@@ -14,23 +14,23 @@
* limitations under the License.
*/
-#include "NOP.h"
+#include "OperandPass.h"
-#include "NodeVisitor.h"
-#include "LowerInfo.h"
+#include "graph/Graph.h"
namespace neurun
{
namespace graph
{
-namespace operation
-{
-namespace NOP
+namespace pass
{
-void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+void OperandPass::run()
+{
+ _graph.operands().iterate([&](const model::operand::Index &index,
+ model::operand::Object &object) { callback(index, object); });
+}
-} // namespace NOP
-} // namespace operation
+} // namespace pass
} // namespace graph
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/pass/OperandPass.h b/runtimes/neurun/src/graph/pass/OperandPass.h
new file mode 100644
index 000000000..b84391082
--- /dev/null
+++ b/runtimes/neurun/src/graph/pass/OperandPass.h
@@ -0,0 +1,56 @@
+/*
+ * 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 __NEURUN_GRAPH_PASS_OPERAND_PASS_H__
+#define __NEURUN_GRAPH_PASS_OPERAND_PASS_H__
+
+#include "Pass.h"
+#include "model/operand/Index.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operand
+{
+class Object;
+} // namespace operand
+} // namespace graph
+} // namespace neurun
+
+namespace neurun
+{
+namespace graph
+{
+namespace pass
+{
+
+class OperandPass : public Pass
+{
+public:
+ using Pass::Pass;
+
+public:
+ virtual std::string id() = 0;
+ virtual void run() override final;
+ virtual void callback(const model::operand::Index &i, model::operand::Object &o) = 0;
+};
+
+} // namespace pass
+} // namespace graph
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_OPERAND_PASS_H__
diff --git a/runtimes/neurun/src/graph/operation/Node.cc b/runtimes/neurun/src/graph/pass/OperationPass.cc
index f472bc08c..e71f79188 100644
--- a/runtimes/neurun/src/graph/operation/Node.cc
+++ b/runtimes/neurun/src/graph/pass/OperationPass.cc
@@ -14,28 +14,23 @@
* limitations under the License.
*/
-#include "Node.h"
+#include "OperationPass.h"
-#include "LowerInfo.h"
+#include "graph/Graph.h"
namespace neurun
{
namespace graph
{
-namespace operation
+namespace pass
{
-Node::Node() = default;
-
-Node::~Node() = default;
-
-void Node::lower_info(std::unique_ptr<LowerInfo> &&lower_info)
+void OperationPass::run()
{
- _lower_info = std::move(lower_info);
+ _graph.operations().iterate([&](const model::operation::Index &index,
+ model::operation::Node &node) { callback(index, node); });
}
-const LowerInfo *Node::lower_info() const { return _lower_info.get(); }
-
-} // namespace operation
+} // namespace pass
} // namespace graph
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/pass/OperationPass.h b/runtimes/neurun/src/graph/pass/OperationPass.h
new file mode 100644
index 000000000..e86f1aa57
--- /dev/null
+++ b/runtimes/neurun/src/graph/pass/OperationPass.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.
+ */
+
+/**
+ * @file OperationPass.h
+ * @brief This file contains OperationPass class
+ */
+
+#ifndef __NEURUN_GRAPH_PASS_OPERATION_PASS_H__
+#define __NEURUN_GRAPH_PASS_OPERATION_PASS_H__
+
+#include "Pass.h"
+
+#include "model/operation/Index.h"
+#include "model/operation/Node.h"
+
+namespace neurun
+{
+namespace graph
+{
+namespace pass
+{
+
+/**
+ * @brief Class to iterate over operations and calls callback() method
+ */
+class OperationPass : public Pass
+{
+public:
+ using Pass::Pass;
+
+public:
+ /**
+ * @brief Returns string id for this pass. Same with class name.
+ *
+ * @return string id
+ */
+ virtual std::string id() = 0;
+
+ /**
+ * @brief Run the pass
+ */
+ virtual void run() override final;
+
+ /**
+ * @brief The function that will be executed for each operations
+ *
+ * @param i[in] Index of the operation node
+ * @param n[in] The operation node
+ */
+ virtual void callback(const model::operation::Index &i, model::operation::Node &n) = 0;
+};
+
+} // namespace pass
+} // namespace graph
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_OPERATION_PASS_H__
diff --git a/runtimes/neurun/src/backend/cpu/MemoryAllocator.cc b/runtimes/neurun/src/graph/pass/Pass.cc
index 13d2a7ffc..4c3436961 100644
--- a/runtimes/neurun/src/backend/cpu/MemoryAllocator.cc
+++ b/runtimes/neurun/src/graph/pass/Pass.cc
@@ -14,4 +14,15 @@
* limitations under the License.
*/
-//#include "internal/cpu/MemoryAllocator.h"
+#include "Pass.h"
+
+namespace neurun
+{
+namespace graph
+{
+namespace pass
+{
+
+} // namespace pass
+} // namespace graph
+} // namespace neurun
diff --git a/runtimes/neurun/src/graph/pass/Pass.h b/runtimes/neurun/src/graph/pass/Pass.h
new file mode 100644
index 000000000..4200936d1
--- /dev/null
+++ b/runtimes/neurun/src/graph/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 __NEURUN_GRAPH_PASS_PASS_H__
+#define __NEURUN_GRAPH_PASS_PASS_H__
+
+#include <string>
+
+namespace neurun
+{
+namespace graph
+{
+class Graph;
+} // namespace graph
+} // namespace neurun
+
+namespace neurun
+{
+namespace graph
+{
+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 graph
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_PASS_H__
diff --git a/runtimes/neurun/src/graph/pass/PermutationEliminationPass.cc b/runtimes/neurun/src/graph/pass/PermutationEliminationPass.cc
new file mode 100644
index 000000000..848f6b574
--- /dev/null
+++ b/runtimes/neurun/src/graph/pass/PermutationEliminationPass.cc
@@ -0,0 +1,192 @@
+/*
+ * 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 "model/operand/Object.h"
+#include "graph/Graph.h"
+#include "backend/interface/IConfig.h"
+#include "util/logging.h"
+#include "compiler/BackendResolver.h"
+
+namespace neurun
+{
+namespace graph
+{
+namespace pass
+{
+void PermutationEliminationPass::callback(const model::operand::Index &inp_index,
+ model::operand::Object &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 model::operand::Index &inp_index,
+ model::operand::Object &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
+ _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 model::operand::Index &out_index,
+ model::operand::Object &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
+ _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 model::operand::IndexSet &inp_indexes, const model::operand::IndexSet &out_indexes,
+ bool is_for_model_input)
+{
+ auto input_def_backends = _graph.operands().at(inp_indexes.at(0)).lower_info()->def_backends();
+ auto output_def_backends = _graph.operands().at(out_indexes.at(0)).lower_info()->def_backends();
+
+ auto input_layout = input_def_backends.getOnlyElement()->config()->getOperandLayout();
+ auto output_layout = output_def_backends.getOnlyElement()->config()->getOperandLayout();
+
+ if (input_def_backends.size() != 1 || output_def_backends.size() != 1)
+ {
+ return false;
+ }
+
+ // all operands' backend must be the same
+ for (auto index : inp_indexes)
+ {
+ auto op_backend_set = _graph.operands().at(index).lower_info()->def_backends();
+ if (op_backend_set.size() != 1 ||
+ input_layout != op_backend_set.getOnlyElement()->config()->getOperandLayout())
+ {
+ return false;
+ }
+ }
+ // all operands' backend must be the same
+ for (auto index : out_indexes)
+ {
+ auto op_backend_set = _graph.operands().at(index).lower_info()->def_backends();
+ if (op_backend_set.size() != 1 ||
+ output_layout != op_backend_set.getOnlyElement()->config()->getOperandLayout())
+ {
+ 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 == graph::operand::Layout::NHWC &&
+ output_layout == graph::operand::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 == graph::operand::Layout::NCHW &&
+ output_layout == graph::operand::Layout::NHWC);
+}
+
+} // namespace pass
+} // namespace graph
+} // namespace neurun
diff --git a/runtimes/neurun/src/graph/pass/PermutationEliminationPass.h b/runtimes/neurun/src/graph/pass/PermutationEliminationPass.h
new file mode 100644
index 000000000..2b528c479
--- /dev/null
+++ b/runtimes/neurun/src/graph/pass/PermutationEliminationPass.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.
+ */
+
+#ifndef __NEURUN_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__
+#define __NEURUN_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__
+
+#include "OperandPass.h"
+#include "model/operand/Object.h"
+#include "model/operand/IndexSet.h"
+
+namespace neurun
+{
+namespace graph
+{
+namespace pass
+{
+
+class PermutationEliminationPass : public OperandPass
+{
+public:
+ using OperandPass::OperandPass;
+
+public:
+ virtual std::string id() override { return "PermutationEliminationPass"; }
+
+ virtual void callback(const model::operand::Index &index, model::operand::Object &object);
+
+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 model::operand::Index &inp_index, model::operand::Object &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 model::operand::Index &out_index, model::operand::Object &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 model::operand::IndexSet &inp_indexes,
+ const model::operand::IndexSet &out_indexes,
+ bool is_for_model_input);
+};
+
+} // namespace pass
+} // namespace graph
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_PERMUTATION_ELIMINATION_PASS_H__
diff --git a/runtimes/neurun/src/graph/pass/PermutationInsertionPass.cc b/runtimes/neurun/src/graph/pass/PermutationInsertionPass.cc
new file mode 100644
index 000000000..9b833b8c5
--- /dev/null
+++ b/runtimes/neurun/src/graph/pass/PermutationInsertionPass.cc
@@ -0,0 +1,191 @@
+/*
+ * 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 <cassert>
+#include <utility>
+#include <unordered_map>
+
+#include "model/operand/Object.h"
+#include "graph/operation/LowerInfo.h"
+#include "graph/Graph.h"
+#include "backend/interface/IConfig.h"
+#include "util/logging.h"
+#include "cpp14/memory.h"
+#include "model/operation/PermuteNode.h"
+#include "graph/operand/Shape4DConvert.h"
+#include "compiler/BackendResolver.h"
+
+namespace neurun
+{
+namespace graph
+{
+namespace pass
+{
+
+void PermutationInsertionPass::callback(const model::operand::Index &index,
+ model::operand::Object &object)
+{
+ auto &&operand_li = object.lower_info();
+ assert(operand_li);
+
+ // NOTE Later, constants also will have Def
+ // Ignore constants
+ if (operand_li->def_backends().size() == 0)
+ {
+ return;
+ }
+
+ std::list<model::operation::Index> permute_indexes;
+
+ // Build a map for all necessary type of operands
+ std::unordered_map<const backend::Backend *, model::operand::Index> backend_to_index;
+ {
+ assert(operand_li->def_backends().size() == 1);
+ for (auto backend : operand_li->def_backends())
+ {
+ backend_to_index.insert({backend, index});
+ }
+
+ auto insert_set = operand_li->use_backends() - operand_li->def_backends();
+ for (auto backend : insert_set)
+ {
+ const auto permute_operation_index = insertPermute(index, backend);
+ 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);
+ backend_to_index.insert({backend, permuted_operand_index});
+ }
+ }
+
+ // Update operations' input that uses this operand
+ {
+ std::list<model::operation::Index> 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);
+ auto operation_li = _graph.getLowerInfo(use);
+ assert(operation_li);
+ auto backend = operation_li->backend();
+
+ auto use_node_inputs = operation.getInputs();
+ assert(use_node_inputs.contains(index));
+
+ auto new_index = backend_to_index.at(backend);
+ if (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);
+ }
+ }
+}
+
+model::operation::Index
+PermutationInsertionPass::insertPermute(const model::operand::Index &operand_index,
+ const backend::Backend *backend)
+{
+ 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());
+ auto &out_operand = _graph.operands().at(out_operand_index);
+ out_operand.setAsOperationOutput();
+ // 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);
+ }
+ out_operand.setAsOperationOutput();
+ auto out_operand_li =
+ nnfw::cpp14::make_unique<operand::LowerInfo>(operand::asShape4D(operand.shape()));
+ out_operand_li->addDefBackend(backend);
+ out_operand_li->addUseBackend(backend);
+ out_operand.lower_info(std::move(out_operand_li));
+
+ // Update LowerInfo of input operand
+ operand.lower_info()->removeUseBackend(backend);
+ operand.lower_info()->addUseBackend(operand.lower_info()->def_backends().getOnlyElement());
+
+ using PermuteNode = model::operation::PermuteNode;
+
+ // Find Permutation Type
+ auto type = [&]() {
+ auto input_layout =
+ operand.lower_info()->def_backends().getOnlyElement()->config()->getOperandLayout();
+ auto output_layout =
+ out_operand.lower_info()->def_backends().getOnlyElement()->config()->getOperandLayout();
+
+ if (input_layout == graph::operand::Layout::NHWC &&
+ output_layout == graph::operand::Layout::NCHW)
+ {
+ return PermuteNode::Type::NHWC_TO_NCHW;
+ }
+ else if (input_layout == graph::operand::Layout::NCHW &&
+ output_layout == graph::operand::Layout::NHWC)
+ {
+ return PermuteNode::Type::NCHW_TO_NHWC;
+ }
+ else
+ {
+ return PermuteNode::Type::COPY;
+ }
+ }();
+
+ // Insert permute operation to the graph
+ auto insert_node = nnfw::cpp14::make_unique<PermuteNode>(operand_index, out_operand_index, type);
+
+ auto node_index = _graph.operations().append(std::move(insert_node));
+ const auto &node = _graph.operations().at(node_index);
+
+ _graph.setLowerInfo(node_index, nnfw::cpp14::make_unique<graph::operation::LowerInfo>(
+ _graph.backend_resolver()->getDefaultBackend()));
+
+ // Update Use/Def info
+ {
+ _graph.operands().at(operand_index).appendUse(node_index);
+
+ auto node_out_indexes = node.getOutputs();
+ auto node_out_index = node_out_indexes.at(model::operand::IO::Index{0});
+ _graph.operands().at(node_out_index).appendDef(node_index);
+ }
+ return node_index;
+}
+} // namespace pass
+} // namespace graph
+} // namespace neurun
diff --git a/runtimes/neurun/src/graph/pass/PermutationInsertionPass.h b/runtimes/neurun/src/graph/pass/PermutationInsertionPass.h
new file mode 100644
index 000000000..b2d417e82
--- /dev/null
+++ b/runtimes/neurun/src/graph/pass/PermutationInsertionPass.h
@@ -0,0 +1,57 @@
+/*
+ * 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 __NEURUN_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__
+#define __NEURUN_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__
+
+#include "OperandPass.h"
+#include "model/operand/Object.h" //for model::operation::Index
+
+namespace neurun
+{
+namespace graph
+{
+namespace pass
+{
+
+class PermutationInsertionPass : public OperandPass
+{
+public:
+ using OperandPass::OperandPass;
+
+public:
+ virtual std::string id() override { return "PermutationInsertionPass"; }
+ virtual void callback(const model::operand::Index &index, model::operand::Object &object);
+
+ /**
+ * @brief Insert Permute operation that has given operand as input
+ *
+ * @param operand_index is the target operand index for the insertion
+ * @param backend is the output operand's backend type
+ *
+ * @return model::operation::Index
+ */
+ model::operation::Index insertPermute(const model::operand::Index &operand_index,
+ const backend::Backend *backend);
+
+private:
+};
+
+} // namespace pass
+} // namespace graph
+} // namespace neurun
+
+#endif // __NEURUN_GRAPH_PASS_PERMUTATION_INSERTION_PASS_H__
diff --git a/runtimes/neurun/src/graph/verifier/IVerifier.cc b/runtimes/neurun/src/graph/verifier/IVerifier.cc
deleted file mode 100644
index f8402695a..000000000
--- a/runtimes/neurun/src/graph/verifier/IVerifier.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 "IVerifier.h"
-
-#include "graph/Graph.h"
-
-namespace neurun
-{
-namespace graph
-{
-namespace verifier
-{
-
-bool DAGChecker::verify(const Graph &graph) const
-{
- auto &operations = graph.operations();
- bool cyclic = false;
- std::vector<bool> visited(operations.size(), false);
- std::vector<bool> on_stack(operations.size(), false);
-
- std::function<void(const operation::Index &index, const operation::Node &)> dfs_recursive =
- [&](const operation::Index &index, const operation::Node &node) -> void {
- if (on_stack[index.value()])
- cyclic = true;
- if (visited[index.value()])
- return;
- visited[index.value()] = true;
- on_stack[index.value()] = true;
-
- auto outputs = node.getOutputs();
- for (auto output : outputs)
- {
- // TODO Fix traversing algorithm
- // Every time need to search for operations that has `outgoing` as incoming from all
- // operations but we can hold that info cached
- operations.iterate([&](const operation::Index &cand_index, const operation::Node &cand_node) {
- auto inputs = cand_node.getInputs();
- for (auto input : inputs)
- {
- if (output == input)
- {
- dfs_recursive(cand_index, cand_node);
- }
- }
- });
- }
-
- on_stack[index.value()] = false;
- };
-
- operations.iterate(dfs_recursive);
-
- return !cyclic;
-}
-
-} // namespace verifier
-} // namespace graph
-} // namespace neurun
diff --git a/runtimes/neurun/src/graph/verifier/Verifier.cc b/runtimes/neurun/src/graph/verifier/Verifier.cc
new file mode 100644
index 000000000..a5b53af85
--- /dev/null
+++ b/runtimes/neurun/src/graph/verifier/Verifier.cc
@@ -0,0 +1,97 @@
+/*
+ * 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 "graph/Graph.h"
+
+#include "util/logging.h"
+
+namespace neurun
+{
+namespace graph
+{
+namespace verifier
+{
+
+//
+// DAGChecker
+//
+
+bool DAGChecker::verify(const Graph &graph) const
+{
+ auto &operations = graph.operations();
+ bool cyclic = false;
+
+ std::unordered_map<model::operation::Index, bool> visited;
+ operations.iterate([&](const model::operation::Index &index, const model::operation::Node &) {
+ visited[index] = false;
+ });
+ std::unordered_map<model::operation::Index, bool> on_stack = visited; // Copy from visited
+
+ std::function<void(const model::operation::Index &index, const model::operation::Node &)>
+ dfs_recursive =
+ [&](const model::operation::Index &index, const model::operation::Node &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 model::operation::Index &index, const model::operation::Node &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 graph
+} // namespace neurun
diff --git a/runtimes/neurun/src/graph/verifier/IVerifier.h b/runtimes/neurun/src/graph/verifier/Verifier.h
index 17fe03f24..5f1f79ee6 100644
--- a/runtimes/neurun/src/graph/verifier/IVerifier.h
+++ b/runtimes/neurun/src/graph/verifier/Verifier.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_VERIFIER_I_VERIFIER_H__
-#define __NEURUN_GRAPH_VERIFIER_I_VERIFIER_H__
+#ifndef __NEURUN_GRAPH_VERIFIER_VERIFIER_H__
+#define __NEURUN_GRAPH_VERIFIER_VERIFIER_H__
namespace neurun
{
@@ -55,8 +55,14 @@ public:
virtual bool verify(const Graph &graph) const override;
};
+class EdgeConsistencyChecker : public IVerifier
+{
+public:
+ virtual bool verify(const Graph &graph) const override;
+};
+
} // namespace verifier
} // namespace graph
} // namespace neurun
-#endif // __NEURUN_GRAPH_VERIFIER_I_VERIFIER_H__
+#endif // __NEURUN_GRAPH_VERIFIER_VERIFIER_H__
diff --git a/runtimes/neurun/src/internal/Convert.cc b/runtimes/neurun/src/internal/Convert.cc
deleted file mode 100644
index c0260b04e..000000000
--- a/runtimes/neurun/src/internal/Convert.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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"
-
-namespace internal
-{
-
-::arm_compute::TensorShape asTensorShape(int32_t h, int32_t w)
-{
- return ::arm_compute::TensorShape(w, h);
-}
-
-::arm_compute::TensorShape asTensorShape(const nnfw::util::feature::Shape &shape)
-{
- return ::arm_compute::TensorShape(shape.W, shape.H, shape.C, shape.N);
-}
-
-::arm_compute::TensorShape asTensorShape(const nnfw::util::kernel::Shape &shape)
-{
- return ::arm_compute::TensorShape(shape.W, shape.H, shape.C, shape.N);
-}
-
-::arm_compute::TensorInfo asTensorInfo(const nnfw::util::feature::Shape &shape)
-{
- return ::arm_compute::TensorInfo(asTensorShape(shape), 1, ::arm_compute::DataType::F32);
-}
-
-::arm_compute::TensorInfo asTensorInfo(const nnfw::util::kernel::Shape &shape)
-{
- return ::arm_compute::TensorInfo(asTensorShape(shape), 1, ::arm_compute::DataType::F32);
-}
-
-::arm_compute::TensorInfo asTensorInfo(int32_t size)
-{
- return ::arm_compute::TensorInfo(::arm_compute::TensorShape(size), 1,
- ::arm_compute::DataType::F32);
-}
-
-::arm_compute::TensorInfo asTensorInfo(int32_t h, int32_t w)
-{
- return ::arm_compute::TensorInfo(::arm_compute::TensorShape(w, h), 1,
- ::arm_compute::DataType::F32);
-}
-
-} // namespace internal
diff --git a/runtimes/neurun/src/internal/Convert.h b/runtimes/neurun/src/internal/Convert.h
deleted file mode 100644
index f279133aa..000000000
--- a/runtimes/neurun/src/internal/Convert.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 __INTERNAL_CONVERT_H__
-#define __INTERNAL_CONVERT_H__
-
-#include <arm_compute/core/TensorInfo.h>
-#include <arm_compute/core/TensorShape.h>
-
-#include "util/feature/Shape.h"
-#include "util/kernel/Shape.h"
-
-namespace internal
-{
-
-::arm_compute::TensorShape asTensorShape(int32_t h, int32_t w);
-::arm_compute::TensorShape asTensorShape(const nnfw::util::feature::Shape &shape);
-::arm_compute::TensorShape asTensorShape(const nnfw::util::kernel::Shape &shape);
-
-::arm_compute::TensorInfo asTensorInfo(const nnfw::util::feature::Shape &shape);
-::arm_compute::TensorInfo asTensorInfo(const nnfw::util::kernel::Shape &shape);
-::arm_compute::TensorInfo asTensorInfo(int32_t size);
-::arm_compute::TensorInfo asTensorInfo(int32_t h, int32_t w);
-
-} // namespace internal
-
-#endif // __INTERNAL_CONVERT_H__
diff --git a/runtimes/neurun/src/internal/nnapi/feature/Reader.h b/runtimes/neurun/src/internal/nnapi/feature/Reader.h
deleted file mode 100644
index eb513512d..000000000
--- a/runtimes/neurun/src/internal/nnapi/feature/Reader.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 __INTERNAL_NNAPI_FEATURE_READER_H__
-#define __INTERNAL_NNAPI_FEATURE_READER_H__
-
-#include "internal/nnapi/feature/Utils.h"
-
-#include "util/feature/Reader.h"
-
-namespace internal
-{
-namespace nnapi
-{
-namespace feature
-{
-
-template <typename T> class Reader;
-
-template <> class Reader<float> final : public nnfw::util::feature::Reader<float>
-{
-public:
- Reader(const ::nnfw::util::feature::Shape &shape, const uint8_t *ptr, size_t len)
- : _shape{shape}, _ptr{ptr}, _len{len}
- {
- // DO NOTHING
- }
-
-public:
- const nnfw::util::feature::Shape &shape(void) const { return _shape; }
-
-public:
- float at(uint32_t ch, uint32_t row, uint32_t col) const override
- {
- uint32_t index = index_of(_shape, ch, row, col);
-
- const auto arr = reinterpret_cast<const float *>(_ptr);
-
- return arr[index];
- }
- float at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override
- {
- uint32_t index = index_of(_shape, batch, ch, row, col);
-
- const auto arr = reinterpret_cast<const float *>(_ptr);
-
- return arr[index];
- }
-
-private:
- nnfw::util::feature::Shape _shape;
-
-private:
- const uint8_t *_ptr;
- const size_t _len;
-};
-
-} // namespace feature
-} // namespace nnapi
-} // namespace internal
-
-#endif // __INTERNAL_NNAPI_FEATURE_READER_H__
diff --git a/runtimes/neurun/src/internal/nnapi/kernel/Reader.h b/runtimes/neurun/src/internal/nnapi/kernel/Reader.h
deleted file mode 100644
index 9d93800bf..000000000
--- a/runtimes/neurun/src/internal/nnapi/kernel/Reader.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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 __INTERNAL_NNAPI_KERNEL_READER_H__
-#define __INTERNAL_NNAPI_KERNEL_READER_H__
-
-#include "util/kernel/Shape.h"
-#include "util/kernel/Reader.h"
-
-namespace internal
-{
-namespace nnapi
-{
-namespace kernel
-{
-
-template <typename T> class Reader final : public nnfw::util::kernel::Reader<T>
-{
-public:
- Reader(const ::nnfw::util::kernel::Shape &shape, const uint8_t *base, size_t size)
- : _shape{shape}, _base{base}, _size{size}
- {
- // DO NOTHING
- }
-
-public:
- const nnfw::util::kernel::Shape &shape(void) const { return _shape; }
-
-public:
- T at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const override
- {
- // NNAPI uses NHWC ordering
- uint32_t index = 0;
-
- index += nth * _shape.H * _shape.W * _shape.C;
- index += row * _shape.W * _shape.C;
- index += col * _shape.C;
- index += ch;
-
- const T *ptr = reinterpret_cast<const T *>(_base);
-
- return ptr[index];
- }
-
-private:
- nnfw::util::kernel::Shape _shape;
-
-private:
- const uint8_t *_base;
- const size_t _size;
-};
-
-} // namespace kernel
-} // namespace nnapi
-} // namespace internal
-
-#endif // __INTERNAL_NNAPI_KERNEL_READER_H__
diff --git a/runtimes/neurun/src/internal/nnapi/kernel/View.h b/runtimes/neurun/src/internal/nnapi/kernel/View.h
deleted file mode 100644
index 86d19b87f..000000000
--- a/runtimes/neurun/src/internal/nnapi/kernel/View.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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 __INTERNAL_NNAPI_KERNEL_VIEW_H__
-#define __INTERNAL_NNAPI_KERNEL_VIEW_H__
-
-#include "util/kernel/Shape.h"
-#include "util/kernel/Reader.h"
-
-#include <arm_compute/core/ITensor.h>
-
-namespace internal
-{
-namespace nnapi
-{
-namespace kernel
-{
-
-template <typename T> class View final : public nnfw::util::kernel::Reader<float>
-{
-public:
- View(::arm_compute::ITensor *tensor) : _tensor{tensor}
- {
- assert(tensor->info()->data_type() == ::arm_compute::DataType::F32);
-
- _shape.N = tensor->info()->dimension(3);
- _shape.C = tensor->info()->dimension(2);
- _shape.H = tensor->info()->dimension(1);
- _shape.W = tensor->info()->dimension(0);
- }
-
-public:
- const nnfw::util::kernel::Shape &shape(void) const { return _shape; }
-
-public:
- float at(uint32_t nth, uint32_t row, uint32_t col, uint32_t ch) const override
- {
- // NNAPI uses NHWC ordering
- uint32_t index = 0;
-
- index += nth * _shape.H * _shape.W * _shape.C;
- index += row * _shape.W * _shape.C;
- index += col * _shape.C;
- index += ch;
-
- float *ptr = reinterpret_cast<float *>(_tensor->buffer());
-
- return ptr[index];
- }
-
- float &at(uint32_t nth, uint32_t row, uint32_t col, uint32_t ch)
- {
- // NNAPI uses NHWC ordering
- uint32_t index = 0;
-
- index += nth * _shape.H * _shape.W * _shape.C;
- index += row * _shape.W * _shape.C;
- index += col * _shape.C;
- index += ch;
-
- float *ptr = reinterpret_cast<float *>(_tensor->buffer());
-
- return ptr[index];
- }
-
-private:
- nnfw::util::kernel::Shape _shape;
- ::arm_compute::ITensor *_tensor;
-};
-
-} // namespace kernel
-} // namespace nnapi
-} // namespace internal
-
-#endif // __INTERNAL_NNAPI_KERNEL_VIEW_H__
diff --git a/runtimes/neurun/src/kernel/acl_cl/CLFunction.h b/runtimes/neurun/src/kernel/acl_cl/CLFunction.h
new file mode 100644
index 000000000..f34210c8a
--- /dev/null
+++ b/runtimes/neurun/src/kernel/acl_cl/CLFunction.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 __NEURUN_KERNEL_ACL_CL_CL_FUNCTION_H__
+#define __NEURUN_KERNEL_ACL_CL_CL_FUNCTION_H__
+
+#include "exec/interface/IFunction.h"
+#include <arm_compute/runtime/IFunction.h>
+#include <memory>
+
+namespace neurun
+{
+namespace kernel
+{
+namespace acl_cl
+{
+
+class CLFunction : public ::neurun::exec::IFunction
+{
+public:
+ CLFunction() = delete;
+
+public:
+ CLFunction(std::unique_ptr<::arm_compute::IFunction> &&func)
+ : _func(std::forward<std::unique_ptr<::arm_compute::IFunction>>(func))
+ {
+ // DO NOTHING
+ }
+
+public:
+ void run() override { _func->run(); }
+ void prepare() override { _func->prepare(); }
+
+private:
+ std::unique_ptr<::arm_compute::IFunction> _func;
+};
+
+} // namespace acl_cl
+} // namespace kernel
+} // namespace neurun
+
+#endif // __NEURUN_KERNEL_ACL_CL_CL_FUNCTION_H__
diff --git a/runtimes/neurun/src/kernel/acl_cl/CMakeLists.txt b/runtimes/neurun/src/kernel/acl_cl/CMakeLists.txt
index 857fe6fe6..0658effea 100644
--- a/runtimes/neurun/src/kernel/acl_cl/CMakeLists.txt
+++ b/runtimes/neurun/src/kernel/acl_cl/CMakeLists.txt
@@ -4,11 +4,9 @@ add_library(${LIB_NEURUN_KERNEL_ACL_CL} STATIC ${SOURCES})
target_include_directories(${LIB_NEURUN_KERNEL_ACL_CL} PUBLIC ${NNFW_INCLUDE_DIR})
target_include_directories(${LIB_NEURUN_KERNEL_ACL_CL} PUBLIC ${NEURUN_INCLUDE_DIR})
-target_include_directories(${LIB_NEURUN_KERNEL_ACL_CL} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow) # TODO We should not need this
target_link_libraries(${LIB_NEURUN_KERNEL_ACL_CL} arm_compute)
-target_link_libraries(${LIB_NEURUN_KERNEL_ACL_CL} tensorflow-lite) # TODO We should not need this
-target_link_libraries(${LIB_NEURUN_KERNEL_ACL_CL} ${LIB_NEURUN_KERNEL_CPU}) # TODO We should not need this
+target_link_libraries(${LIB_NEURUN_KERNEL_ACL_CL} nnfw_lib_misc)
set_target_properties(${LIB_NEURUN_KERNEL_ACL_CL} PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(${LIB_NEURUN_KERNEL_ACL_CL} PROPERTIES OUTPUT_NAME kernel_acl_cl)
diff --git a/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.cc b/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.cc
index b75ac90f0..3844317ab 100644
--- a/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.cc
+++ b/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.cc
@@ -18,23 +18,23 @@
#include <arm_compute/runtime/CL/CLScheduler.h>
-#include "backend/acl_cl/kernel/View.h"
-#include "logging.h"
+#include "util/feature/nchw/View.h"
+#include "util/logging.h"
namespace
{
-bool matchSizeExceptAxis(const ::arm_compute::ICLTensor *t1, const ::arm_compute::ICLTensor *t2,
- uint32_t axis)
+bool matchSizeExceptAxis(const ::neurun::backend::acl_cl::operand::ICLTensor *t1,
+ const ::neurun::backend::acl_cl::operand::ICLTensor *t2, uint32_t axis)
{
- assert(t1->info()->num_dimensions() <= 4);
- assert(t2->info()->num_dimensions() <= 4);
+ assert(t1->num_dimensions() <= 4);
+ assert(t2->num_dimensions() <= 4);
for (uint32_t i = 0; i < 4; i++)
{
if (axis == i)
continue;
- if (t1->info()->dimension(i) != t2->info()->dimension(i))
+ if (t1->dimension(i) != t2->dimension(i))
return false;
}
return true;
@@ -66,10 +66,10 @@ bool ConcatLayer::concatenationFloat32()
for (auto input : _input_allocs)
{
assert(matchSizeExceptAxis(_output_alloc, input, _axis));
- axis_sum += input->info()->dimension(_axis);
+ axis_sum += input->dimension(_axis);
}
- assert(_output_alloc->info()->dimension(_axis) == axis_sum);
+ assert(_output_alloc->dimension(_axis) == axis_sum);
}
VERBOSE(Concat_RUN) << "START Concat" << std::endl;
@@ -81,12 +81,12 @@ bool ConcatLayer::concatenationFloat32()
auto &queue = ::arm_compute::CLScheduler::get().queue();
_output_alloc->map(queue);
- ::internal::arm_compute::kernel::View<float> output_view{_output_alloc};
+ util::feature::nchw::View<float> output_view{_output_alloc};
for (auto input : _input_allocs)
{
input->map(queue);
- const ::internal::arm_compute::kernel::View<float> input_reader{input};
+ const util::feature::nchw::View<float> input_reader{input};
for (uint32_t n = 0; n < input_reader.shape().N; n++)
{
@@ -124,8 +124,9 @@ bool ConcatLayer::concatenationFloat32()
return true;
}
-void ConcatLayer::configure(const std::vector<::arm_compute::ICLTensor *> &input_allocs,
- int32_t axis, ::arm_compute::ICLTensor *output_alloc)
+void ConcatLayer::configure(
+ const std::vector<::neurun::backend::acl_cl::operand::ICLTensor *> &input_allocs, int32_t axis,
+ ::neurun::backend::acl_cl::operand::ICLTensor *output_alloc)
{
_input_allocs = input_allocs;
_output_alloc = output_alloc;
diff --git a/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.h b/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.h
index 4767721fa..d468a6dfb 100644
--- a/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.h
+++ b/runtimes/neurun/src/kernel/acl_cl/ConcatLayer.h
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-#ifndef __INTERNAL_KERNEL_ACL_CL_CONCAT_LAYER_H__
-#define __INTERNAL_KERNEL_ACL_CL_CONCAT_LAYER_H__
+#ifndef __NEURUN_KERNEL_ACL_CL_CONCAT_LAYER_H__
+#define __NEURUN_KERNEL_ACL_CL_CONCAT_LAYER_H__
#include <NeuralNetworks.h>
-#include <arm_compute/core/CL/ICLTensor.h>
#include <arm_compute/runtime/IFunction.h>
-#include "graph/operand/DataType.h"
+#include "model/operand/DataType.h"
+#include "backend/acl_cl/operand/ICLTensor.h"
-using OperandType = neurun::graph::operand::DataType;
+using OperandType = neurun::model::operand::DataType;
namespace neurun
{
@@ -44,9 +44,9 @@ public:
ConcatLayer();
public:
- void configure(const std::vector<::arm_compute::ICLTensor *> &input_allocs,
+ void configure(const std::vector<::neurun::backend::acl_cl::operand::ICLTensor *> &input_allocs,
int32_t axis /* NNAPI tensor axis from NHWC order */,
- ::arm_compute::ICLTensor *output_alloc);
+ ::neurun::backend::acl_cl::operand::ICLTensor *output_alloc);
void run();
@@ -54,8 +54,8 @@ private:
bool concatenationFloat32();
private:
- std::vector<::arm_compute::ICLTensor *> _input_allocs;
- ::arm_compute::ICLTensor *_output_alloc;
+ std::vector<::neurun::backend::acl_cl::operand::ICLTensor *> _input_allocs;
+ ::neurun::backend::acl_cl::operand::ICLTensor *_output_alloc;
int32_t _axis;
OperandType _input_type;
};
@@ -64,4 +64,4 @@ private:
} // namespace kernel
} // namespace neurun
-#endif // __INTERNAL_KERNEL_ACL_CL_CONCAT_LAYER_H__
+#endif // __NEURUN_KERNEL_ACL_CL_CONCAT_LAYER_H__
diff --git a/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.cc b/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.cc
deleted file mode 100644
index fa1d77579..000000000
--- a/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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 IS UNUSED BUT LEFT FOR FUTURE REFERNCE
-//
-
-#if 0
-
-#include "TensorConvertFromCommonLayer.h"
-
-#include "internal/nnapi/feature/Reader.h"
-#include "backend/acl_cl/feature/View.h"
-
-#include <util/feature/IndexIterator.h>
-#include <arm_compute/runtime/CL/CLScheduler.h>
-
-namespace neurun
-{
-namespace kernel
-{
-namespace acl_cl
-{
-
-bool TensorConvertFromCommonLayer::convert()
-{
- auto inputBuffer = _inputTensor->buffer();
- auto inputSize = _inputTensor->info()->total_size();
-
- auto &queue = ::arm_compute::CLScheduler::get().queue();
-
- _outputTensor->map(queue);
-
- if (_tensorShape.rank() == 2)
- {
- const auto len = _tensorShape.dim(1);
-
- auto base = reinterpret_cast<const float *>(inputBuffer);
-
- for (int32_t n = 0; n < len; ++n)
- {
- auto from = base + n;
- auto into =
- reinterpret_cast<float *>(_outputTensor->ptr_to_element(::arm_compute::Coordinates{n}));
-
- *into = *from;
- }
- }
- else if (_tensorShape.rank() == 4)
- {
- auto featureShape = _tensorShape.asFeature();
-
- const ::internal::nnapi::feature::Reader<float> from{featureShape, inputBuffer, inputSize};
- ::internal::arm_compute::feature::View<float> into{_outputTensor};
-
- ::nnfw::util::feature::iterate(featureShape)
- << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(batch, ch, row, col);
- into.at(batch, ch, row, col) = value;
- };
- }
-
- _outputTensor->unmap(queue);
-}
-
-void TensorConvertFromCommonLayer::configure(::internal::common::Tensor *inputTensor,
- ::arm_compute::ICLTensor *outputTensor,
- const ::neurun::graph::operand::Shape &tensorShape)
-{
- _inputTensor = inputTensor;
- _outputTensor = outputTensor;
- _tensorShape = tensorShape;
-}
-
-void TensorConvertFromCommonLayer::run() { convert(); }
-
-} // namespace acl_cl
-} // namespace kernel
-} // namespace neurun
-
-#endif
diff --git a/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.h b/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.h
deleted file mode 100644
index bd031a106..000000000
--- a/runtimes/neurun/src/kernel/acl_cl/TensorConvertFromCommonLayer.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 IS UNUSED BUT LEFT FOR FUTURE REFERNCE
-//
-
-#if 0
-
-#ifndef __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_FROM_COMMON_LAYER_H__
-#define __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_FROM_COMMON_LAYER_H__
-
-#include <NeuralNetworks.h>
-
-#include <arm_compute/runtime/IFunction.h>
-#include <arm_compute/core/CL/ICLTensor.h>
-
-#include "internal/Model.h"
-#include "internal/common/Tensor.h"
-
-namespace neurun
-{
-namespace kernel
-{
-namespace acl_cl
-{
-
-class TensorConvertFromCommonLayer : public ::arm_compute::IFunction
-{
-public:
- TensorConvertFromCommonLayer() {}
-
-public:
- bool convert();
-
- void configure(::internal::common::Tensor *inputTensor, ::arm_compute::ICLTensor *outputTensor,
- const ::neurun::graph::operand::Shape &tensorShape);
-
- void run();
-
-private:
- ::internal::common::Tensor *_inputTensor;
- ::arm_compute::ICLTensor *_outputTensor;
-
- ::neurun::graph::operand::Shape _tensorShape{1};
-};
-
-} // namespace acl_cl
-} // namespace kernel
-} // namespace neurun
-
-#endif // __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_FROM_COMMON_LAYER_H__
-
-#endif
diff --git a/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.cc b/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.cc
deleted file mode 100644
index 985524bc3..000000000
--- a/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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 IS UNUSED BUT LEFT FOR FUTURE REFERNCE
-//
-
-#if 0
-
-#include "TensorConvertToCommonLayer.h"
-
-#include "backend/acl_cl/feature/View.h"
-#include "internal/nnapi/feature/View.h"
-
-#include <util/feature/IndexIterator.h>
-#include <arm_compute/runtime/CL/CLScheduler.h>
-
-namespace neurun
-{
-namespace kernel
-{
-namespace acl_cl
-{
-
-bool TensorConvertToCommonLayer::convert()
-{
- auto outputBuffer = _outputTensor->buffer();
- auto outputSize = _outputTensor->info()->total_size();
-
- auto &queue = ::arm_compute::CLScheduler::get().queue();
-
- _inputTensor->map(queue);
-
- if (_tensorShape.rank() == 2)
- {
- const auto len = _tensorShape.dim(1);
-
- auto base = reinterpret_cast<float *>(outputBuffer);
-
- for (int32_t n = 0; n < len; ++n)
- {
- auto from = reinterpret_cast<const float *>(
- _inputTensor->ptr_to_element(::arm_compute::Coordinates{n}));
- auto into = base + n;
-
- *into = *from;
- }
- }
- else if (_tensorShape.rank() == 4)
- {
- auto featureShape = _tensorShape.asFeature();
-
- const ::internal::arm_compute::feature::View<float> from{_inputTensor};
- ::internal::nnapi::feature::View<float> into{featureShape, outputBuffer, outputSize};
-
- ::nnfw::util::feature::iterate(featureShape)
- << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(batch, ch, row, col);
- into.at(batch, ch, row, col) = value;
- };
- }
-
- _inputTensor->unmap(queue);
-}
-
-void TensorConvertToCommonLayer::configure(::arm_compute::ICLTensor *inputTensor,
- ::internal::common::Tensor *outputTensor,
- const ::neurun::graph::operand::Shape &tensorShape)
-{
- _inputTensor = inputTensor;
- _outputTensor = outputTensor;
- _tensorShape = tensorShape;
-}
-
-void TensorConvertToCommonLayer::run() { convert(); }
-
-} // namespace acl_cl
-} // namespace kernel
-} // namespace neurun
-
-#endif
diff --git a/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.h b/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.h
deleted file mode 100644
index 576f1ee71..000000000
--- a/runtimes/neurun/src/kernel/acl_cl/TensorConvertToCommonLayer.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 IS UNUSED BUT LEFT FOR FUTURE REFERNCE
-//
-
-#if 0
-
-#ifndef __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_TO_COMMON_LAYER_H__
-#define __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_TO_COMMON_LAYER_H__
-
-#include <NeuralNetworks.h>
-
-#include <arm_compute/runtime/IFunction.h>
-#include <arm_compute/core/CL/ICLTensor.h>
-
-#include "internal/Model.h"
-#include "internal/common/Tensor.h"
-
-namespace neurun
-{
-namespace kernel
-{
-namespace acl_cl
-{
-
-class TensorConvertToCommonLayer : public ::arm_compute::IFunction
-{
-public:
- TensorConvertToCommonLayer() {}
-
-public:
- bool convert();
-
- void configure(::arm_compute::ICLTensor *inputTensor, ::internal::common::Tensor *outputTensor,
- const ::neurun::graph::operand::Shape &tensorShape);
-
- void run();
-
-private:
- ::arm_compute::ICLTensor *_inputTensor;
- ::internal::common::Tensor *_outputTensor;
-
- ::neurun::graph::operand::Shape _tensorShape{1};
-};
-
-} // namespace acl_cl
-} // namespace kernel
-} // namespace neurun
-
-#endif // __INTERNAL_KERNELS_ACL_CL_TENSOR_CONVERT_TO_COMMON_LAYER_H__
-
-#endif
diff --git a/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.cc b/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.cc
index 2a6a84e10..f434a6dec 100644
--- a/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.cc
+++ b/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.cc
@@ -27,14 +27,14 @@ namespace kernel
namespace cpu
{
-#define AVGPOOLING_PARAMETERS \
- uint32_t height = getSizeOfDimension(_inputShape, 1); \
- uint32_t width = getSizeOfDimension(_inputShape, 2); \
- uint32_t outHeight = getSizeOfDimension(_outputShape, 1); \
- uint32_t outWidth = getSizeOfDimension(_outputShape, 2); \
- \
- uint32_t paddingHeight = (uint32_t)_paddingTop; \
- uint32_t paddingWidth = (uint32_t)_paddingLeft;
+#define AVGPOOLING_PARAMETERS \
+ tflite::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()
: _inputData(nullptr), _outputData(nullptr), _inputShape(), _outputShape(), _paddingLeft(0),
@@ -47,31 +47,31 @@ AvgPoolLayer::AvgPoolLayer()
bool 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;
- ::tflite::optimized_ops::AveragePool(
- reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape), _strideWidth,
- _strideHeight, paddingWidth, paddingHeight, _kernelWidth, _kernelHeight,
- output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData),
- convertShapeToDims(_outputShape));
+ ::tflite::optimized_ops::AveragePool(op_params, convertShapeToTFLiteShape(_inputShape),
+ reinterpret_cast<const float *>(_inputData),
+ convertShapeToTFLiteShape(_outputShape),
+ reinterpret_cast<float *>(_outputData));
return true;
}
bool AvgPoolLayer::averagePoolQuant8()
{
-
AVGPOOLING_PARAMETERS
int32_t output_activation_min = 0;
int32_t output_activation_max = 0;
CalculateActivationRangeUint8(_activation, _outputShape, &output_activation_min,
&output_activation_max);
+ op_params.quantized_activation_min = output_activation_min;
+ op_params.quantized_activation_max = output_activation_max;
- ::tflite::optimized_ops::AveragePool(_inputData, convertShapeToDims(_inputShape), _strideWidth,
- _strideHeight, paddingWidth, paddingHeight, _kernelWidth,
- _kernelHeight, output_activation_min, output_activation_max,
- _outputData, convertShapeToDims(_outputShape));
+ ::tflite::optimized_ops::AveragePool(op_params, convertShapeToTFLiteShape(_inputShape),
+ _inputData, convertShapeToTFLiteShape(_outputShape),
+ _outputData);
return true;
}
diff --git a/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.h b/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.h
index 9f390a9e1..280f7ae5f 100644
--- a/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.h
+++ b/runtimes/neurun/src/kernel/cpu/AvgPoolLayer.h
@@ -19,7 +19,7 @@
#include <NeuralNetworks.h>
-#include <arm_compute/runtime/IFunction.h>
+#include "exec/interface/IFunction.h"
#include "kernel/cpu/OperationUtils.h"
@@ -30,7 +30,7 @@ namespace kernel
namespace cpu
{
-class AvgPoolLayer : public ::arm_compute::IFunction
+class AvgPoolLayer : public ::neurun::exec::IFunction
{
public:
AvgPoolLayer();
diff --git a/runtimes/neurun/src/kernel/cpu/CMakeLists.txt b/runtimes/neurun/src/kernel/cpu/CMakeLists.txt
index dddf154c3..436cb898c 100644
--- a/runtimes/neurun/src/kernel/cpu/CMakeLists.txt
+++ b/runtimes/neurun/src/kernel/cpu/CMakeLists.txt
@@ -6,8 +6,8 @@ target_include_directories(${LIB_NEURUN_KERNEL_CPU} PUBLIC ${NNFW_INCLUDE_DIR})
target_include_directories(${LIB_NEURUN_KERNEL_CPU} PUBLIC ${NEURUN_INCLUDE_DIR})
target_include_directories(${LIB_NEURUN_KERNEL_CPU} PUBLIC ${CMAKE_SOURCE_DIR}/externals/tensorflow)
-target_link_libraries(${LIB_NEURUN_KERNEL_CPU} arm_compute) # TODO We should not need this
target_link_libraries(${LIB_NEURUN_KERNEL_CPU} tensorflow-lite)
+target_link_libraries(${LIB_NEURUN_KERNEL_CPU} nnfw_lib_misc)
set_target_properties(${LIB_NEURUN_KERNEL_CPU} PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(${LIB_NEURUN_KERNEL_CPU} PROPERTIES OUTPUT_NAME kernel_cpu)
diff --git a/runtimes/neurun/src/kernel/cpu/ConcatLayer.cc b/runtimes/neurun/src/kernel/cpu/ConcatLayer.cc
index 5fe5e3993..be093b437 100644
--- a/runtimes/neurun/src/kernel/cpu/ConcatLayer.cc
+++ b/runtimes/neurun/src/kernel/cpu/ConcatLayer.cc
@@ -24,6 +24,7 @@ namespace neurun
{
namespace kernel
{
+
namespace cpu
{
@@ -36,13 +37,21 @@ ConcatLayer::ConcatLayer()
bool ConcatLayer::concatenationFloat32()
{
- int num_inputs = _inputShapes.size();
- std::vector<::tflite::Dims<4> *> inputDimsPtr(num_inputs);
- std::vector<::tflite::Dims<4>> inputDims(num_inputs);
- for (int i = 0; i < num_inputs; i++)
+ uint32_t num_inputs = _inputShapes.size();
+
+ tflite::ConcatenationParams op_params;
+ op_params.axis = _axis;
+ op_params.inputs_count = num_inputs;
+
+ std::vector<::tflite::RuntimeShape *> inputDimsPtr;
+ std::vector<::tflite::RuntimeShape> inputDims;
+ inputDimsPtr.reserve(num_inputs);
+ inputDims.reserve(num_inputs);
+
+ for (uint32_t i = 0; i < num_inputs; i++)
{
- inputDims[i] = convertShapeToDims(_inputShapes[i]);
- inputDimsPtr[i] = &inputDims[i];
+ inputDims.push_back(convertShapeToTFLiteShape(_inputShapes[i]));
+ inputDimsPtr.push_back(&inputDims[i]);
}
std::vector<const float *> inputFloatPtrs;
@@ -52,24 +61,44 @@ bool ConcatLayer::concatenationFloat32()
inputFloatPtrs.emplace_back(reinterpret_cast<const float *>(ptr));
}
- ::tflite::optimized_ops::Concatenation<::tflite::FusedActivationFunctionType::kNone, float>(
- getNumberOfDimensions(_outputShape) - _axis - 1, inputFloatPtrs.data(), inputDimsPtr.data(),
- num_inputs, reinterpret_cast<float *>(_outputData), convertShapeToDims(_outputShape));
+ ::tflite::optimized_ops::Concatenation<float>(
+ op_params, inputDimsPtr.data(), inputFloatPtrs.data(),
+ convertShapeToTFLiteShape(_outputShape), reinterpret_cast<float *>(_outputData));
return true;
}
bool ConcatLayer::concatenationQuant8()
{
int num_inputs = _inputShapes.size();
- std::vector<::tflite::Dims<4> *> inputDimsPtr(num_inputs);
- std::vector<::tflite::Dims<4>> inputDims(num_inputs);
- for (int i = 0; i < num_inputs; i++)
+
+ std::vector<int32_t> input_zeropoints(num_inputs);
+ std::vector<float> input_scales(num_inputs);
+ for (uint32_t i = 0; i < num_inputs; i++)
{
- inputDims[i] = convertShapeToDims(_inputShapes[i]);
- inputDimsPtr[i] = &inputDims[i];
+ input_zeropoints[i] = _inputShapes[i].offset;
+ input_scales[i] = _inputShapes[i].scale;
}
- ::tflite::optimized_ops::Concatenation<::tflite::FusedActivationFunctionType::kNone, uint8_t>(
- getNumberOfDimensions(_outputShape) - _axis - 1, _inputDataPtrs.data(), inputDimsPtr.data(),
- num_inputs, _outputData, convertShapeToDims(_outputShape));
+
+ tflite::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 = _outputShape.offset;
+ op_params.output_scale = _outputShape.scale;
+
+ std::vector<::tflite::RuntimeShape *> inputDimsPtr;
+ std::vector<::tflite::RuntimeShape> inputDims;
+ inputDimsPtr.reserve(num_inputs);
+ inputDims.reserve(num_inputs);
+ for (uint32_t i = 0; i < num_inputs; i++)
+ {
+ inputDims.push_back(convertShapeToTFLiteShape(_inputShapes[i]));
+ inputDimsPtr.push_back(&inputDims[i]);
+ }
+
+ ::tflite::optimized_ops::Concatenation<uint8_t>(
+ op_params, inputDimsPtr.data(), _inputDataPtrs.data(),
+ convertShapeToTFLiteShape(_outputShape), _outputData);
return true;
}
diff --git a/runtimes/neurun/src/kernel/cpu/ConcatLayer.h b/runtimes/neurun/src/kernel/cpu/ConcatLayer.h
index 9aacab5e8..64f813508 100644
--- a/runtimes/neurun/src/kernel/cpu/ConcatLayer.h
+++ b/runtimes/neurun/src/kernel/cpu/ConcatLayer.h
@@ -20,7 +20,7 @@
#include <NeuralNetworks.h>
-#include <arm_compute/runtime/IFunction.h>
+#include "exec/interface/IFunction.h"
#include "kernel/cpu/OperationUtils.h"
@@ -31,7 +31,7 @@ namespace kernel
namespace cpu
{
-class ConcatLayer : public ::arm_compute::IFunction
+class ConcatLayer : public ::neurun::exec::IFunction
{
public:
ConcatLayer();
diff --git a/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.cc b/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.cc
index 81e88e0f0..c694fa75f 100644
--- a/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.cc
+++ b/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.cc
@@ -33,55 +33,51 @@ static constexpr int kStaticBufferSize = 1605632;
static char static_scratch_buffer[kStaticBufferSize];
static std::mutex executionMutex;
-#define ANDROID_NN_CONV_PARAMETERS(Type) \
- uint32_t height = getSizeOfDimension(_inputShape, 1); \
- uint32_t width = getSizeOfDimension(_inputShape, 2); \
- uint32_t kernelHeight = getSizeOfDimension(_kernelShape, 1); \
- uint32_t kernelWidth = getSizeOfDimension(_kernelShape, 2); \
- uint32_t outHeight = getSizeOfDimension(_outputShape, 1); \
- uint32_t outWidth = getSizeOfDimension(_outputShape, 2); \
- uint32_t inDepth = getSizeOfDimension(_inputShape, 3); \
- \
- uint32_t paddingHeight = (uint32_t)_paddingTop; \
- uint32_t paddingWidth = (uint32_t)_paddingLeft; \
- \
- ::tflite::Dims<4> im2colDim; \
- im2colDim.sizes[3] = (int)getSizeOfDimension(_outputShape, 0); \
- im2colDim.sizes[2] = (int)getSizeOfDimension(_outputShape, 1); \
- im2colDim.sizes[1] = (int)getSizeOfDimension(_outputShape, 2); \
- im2colDim.sizes[0] = (int)inDepth * kernelHeight * kernelWidth; \
- \
- im2colDim.strides[0] = 1; \
- for (int i = 1; i < 4; i++) \
- { \
- im2colDim.strides[i] = im2colDim.strides[i - 1] * im2colDim.sizes[i - 1]; \
- } \
- Type *im2colData = nullptr; \
- uint64_t im2colByteSize = sizeof(Type); \
- std::unique_ptr<Type[]> im2colGuard; \
- for (int i = 0; i < 4; i++) \
- { \
- im2colByteSize *= im2colDim.sizes[i]; \
- } \
- /* http://b/77982879, tflite::optimized_ops::Conv uses int for offsets */ \
- if (im2colByteSize >= 0x7fffffff) \
- { \
- std::cout << "Conv size is too large, not enough memory" << std::endl; \
- return false; \
- } \
- if (im2colByteSize <= kStaticBufferSize) \
- { \
- im2colData = reinterpret_cast<Type *>(static_scratch_buffer); \
- } \
- else \
- { \
- im2colData = new (std::nothrow) Type[im2colByteSize / sizeof(Type)]; \
- if (im2colData == nullptr) \
- { \
- std::cout << "Conv size is too large, not enough memory" << std::endl; \
- return false; \
- } \
- im2colGuard.reset(im2colData); \
+#define ANDROID_NN_CONV_PARAMETERS(Type) \
+ uint32_t height = getSizeOfDimension(_inputShape, 1); \
+ uint32_t width = getSizeOfDimension(_inputShape, 2); \
+ uint32_t kernelHeight = getSizeOfDimension(_kernelShape, 1); \
+ uint32_t kernelWidth = getSizeOfDimension(_kernelShape, 2); \
+ uint32_t outHeight = getSizeOfDimension(_outputShape, 1); \
+ uint32_t outWidth = getSizeOfDimension(_outputShape, 2); \
+ uint32_t inDepth = getSizeOfDimension(_inputShape, 3); \
+ \
+ uint32_t paddingHeight = (uint32_t)_paddingTop; \
+ uint32_t paddingWidth = (uint32_t)_paddingLeft; \
+ \
+ Shape im2colShape; \
+ im2colShape.dimensions.resize(4); \
+ im2colShape.dimensions[0] = getSizeOfDimension(_outputShape, 0); \
+ im2colShape.dimensions[1] = getSizeOfDimension(_outputShape, 1); \
+ im2colShape.dimensions[2] = getSizeOfDimension(_outputShape, 2); \
+ im2colShape.dimensions[3] = inDepth * kernelHeight * kernelWidth; \
+ \
+ Type *im2colData = nullptr; \
+ uint64_t im2colByteSize = sizeof(Type); \
+ std::unique_ptr<Type[]> im2colGuard; \
+ for (int i = 0; i < 4; i++) \
+ { \
+ im2colByteSize *= im2colShape.dimensions[i]; \
+ } \
+ /* http://b/77982879, tflite::optimized_ops::Conv uses int for offsets */ \
+ if (im2colByteSize >= 0x7fffffff) \
+ { \
+ std::cout << "Conv size is too large, not enough memory" << std::endl; \
+ return false; \
+ } \
+ if (im2colByteSize <= kStaticBufferSize) \
+ { \
+ im2colData = reinterpret_cast<Type *>(static_scratch_buffer); \
+ } \
+ else \
+ { \
+ im2colData = new (std::nothrow) Type[im2colByteSize / sizeof(Type)]; \
+ if (im2colData == nullptr) \
+ { \
+ std::cout << "Conv size is too large, not enough memory" << std::endl; \
+ return false; \
+ } \
+ im2colGuard.reset(im2colData); \
}
ConvolutionLayer::ConvolutionLayer()
@@ -112,19 +108,32 @@ bool ConvolutionLayer::convFloat32()
float output_activation_min, output_activation_max;
CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max);
int32_t dilationWidthFactor = 1, dilationHeightFactor = 1;
+
+ ::tflite::ConvParams op_params;
+ op_params.padding_type = ::tflite::PaddingType::kSame;
+ op_params.padding_values.width = paddingWidth;
+ op_params.padding_values.height = paddingHeight;
+ op_params.stride_width = _strideWidth;
+ op_params.stride_height = _strideHeight;
+ op_params.dilation_width_factor = dilationWidthFactor;
+ op_params.dilation_height_factor = dilationHeightFactor;
+ op_params.float_activation_min = output_activation_min;
+ op_params.float_activation_max = output_activation_max;
+
::tflite::optimized_ops::Conv(
- reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape),
- reinterpret_cast<const float *>(_kernelData), convertShapeToDims(_kernelShape),
- reinterpret_cast<const float *>(_biasData), convertShapeToDims(_biasShape), _strideWidth,
- _strideHeight, dilationWidthFactor, dilationHeightFactor, paddingWidth, paddingHeight,
- output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData),
- convertShapeToDims(_outputShape), im2colDataToPass, im2colDim);
+ op_params, convertShapeToTFLiteShape(_inputShape),
+ reinterpret_cast<const float *>(_inputData), convertShapeToTFLiteShape(_kernelShape),
+ reinterpret_cast<const float *>(_kernelData), convertShapeToTFLiteShape(_biasShape),
+ reinterpret_cast<const float *>(_biasData), convertShapeToTFLiteShape(_outputShape),
+ reinterpret_cast<float *>(_outputData), convertShapeToTFLiteShape(im2colShape),
+ im2colDataToPass);
return true;
}
bool ConvolutionLayer::convQuant8()
{
ANDROID_NN_CONV_PARAMETERS(uint8_t)
+
int32_t inputOffset = -_inputShape.offset;
int32_t kernelOffset = -_kernelShape.offset;
int32_t outputOffset = _outputShape.offset;
@@ -141,6 +150,24 @@ bool ConvolutionLayer::convQuant8()
}
CalculateActivationRangeUint8(_activation, _outputShape, &output_activation_min,
&output_activation_max);
+ int32_t dilationWidthFactor = 1, dilationHeightFactor = 1;
+
+ ::tflite::ConvParams op_params;
+ op_params.padding_type = ::tflite::PaddingType::kSame;
+ op_params.padding_values.width = paddingWidth;
+ op_params.padding_values.height = paddingHeight;
+ op_params.stride_width = _strideWidth;
+ op_params.stride_height = _strideHeight;
+ op_params.dilation_width_factor = dilationWidthFactor;
+ op_params.dilation_height_factor = dilationHeightFactor;
+ op_params.input_offset = inputOffset;
+ op_params.weights_offset = kernelOffset;
+ op_params.output_offset = outputOffset;
+ 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;
+
static gemmlowp::GemmContext gemm_context;
// Prevent concurrent executions that may access the scratch buffer and
// gemm_context.
@@ -148,11 +175,10 @@ bool ConvolutionLayer::convQuant8()
// Alow gemmlowp automatically decide how many threads to use.
gemm_context.set_max_num_threads(0);
::tflite::optimized_ops::Conv(
- _inputData, convertShapeToDims(_inputShape), inputOffset, _kernelData,
- convertShapeToDims(_kernelShape), kernelOffset, reinterpret_cast<const int32_t *>(_biasData),
- convertShapeToDims(_biasShape), _strideWidth, _strideHeight, paddingWidth, paddingHeight,
- outputOffset, output_multiplier, output_shift, output_activation_min, output_activation_max,
- _outputData, convertShapeToDims(_outputShape), im2colData, im2colDim, &gemm_context);
+ op_params, convertShapeToTFLiteShape(_inputShape), _inputData,
+ convertShapeToTFLiteShape(_kernelShape), _kernelData, convertShapeToTFLiteShape(_biasShape),
+ reinterpret_cast<const int32_t *>(_biasData), convertShapeToTFLiteShape(_outputShape),
+ _outputData, convertShapeToTFLiteShape(im2colShape), im2colData, &gemm_context);
return true;
}
diff --git a/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.h b/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.h
index b7afbcec6..9b7f55ff1 100644
--- a/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.h
+++ b/runtimes/neurun/src/kernel/cpu/ConvolutionLayer.h
@@ -19,7 +19,7 @@
#include <NeuralNetworks.h>
-#include <arm_compute/runtime/IFunction.h>
+#include "exec/interface/IFunction.h"
#include "kernel/cpu/OperationUtils.h"
@@ -30,7 +30,7 @@ namespace kernel
namespace cpu
{
-class ConvolutionLayer : public ::arm_compute::IFunction
+class ConvolutionLayer : public ::neurun::exec::IFunction
{
public:
ConvolutionLayer();
diff --git a/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.cc b/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.cc
index 41b9afc0c..abe82db5e 100644
--- a/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.cc
+++ b/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.cc
@@ -44,64 +44,39 @@ FullyConnectedLayer::FullyConnectedLayer()
static std::mutex executionMutex;
bool FullyConnectedLayer::fullyConnectedFloat32()
{
- float output_activation_min, output_activation_max;
- CalculateActivationRangeFloat(_activation, &output_activation_min, &output_activation_max);
- // b/80425683, optimized implementation produces incorrect results when the
- // number of input elements is the squre of batch_size.
- uint32_t batch_size = getSizeOfDimension(_outputShape, 0);
- uint32_t input_n_elements = getNumberOfElements(_inputShape);
- if (batch_size * batch_size == input_n_elements)
+ int total_input_size = 1;
+ for (int i = 0; i < _inputShape.dimensions.size(); i++)
{
- ::tflite::reference_ops::FullyConnected(
- reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape),
- reinterpret_cast<const float *>(_weightsData), convertShapeToDims(_weightsShape),
- reinterpret_cast<const float *>(_biasData), convertShapeToDims(_biasShape),
- output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData),
- convertShapeToDims(_outputShape));
- }
- else
- {
- ::tflite::optimized_ops::FullyConnected(
- reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape),
- reinterpret_cast<const float *>(_weightsData), convertShapeToDims(_weightsShape),
- reinterpret_cast<const float *>(_biasData), convertShapeToDims(_biasShape),
- output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData),
- convertShapeToDims(_outputShape));
+ total_input_size *= _inputShape.dimensions[i];
}
+
+ int input_size = _weightsShape.dimensions[1];
+ const int batch_size = total_input_size / input_size;
+ const int num_units = _weightsShape.dimensions[0];
+
+ TfLiteFusedActivation act = convertFusedActivation(_activation);
+
+ ::tflite::tensor_utils::VectorBatchVectorAssign(reinterpret_cast<const float *>(_biasData),
+ num_units, batch_size,
+ reinterpret_cast<float *>(_outputData));
+
+ // Compute output += weight * input
+ ::tflite::tensor_utils::MatrixBatchVectorMultiplyAccumulate(
+ reinterpret_cast<const float *>(_weightsData), num_units, input_size,
+ reinterpret_cast<const float *>(_inputData), batch_size,
+ reinterpret_cast<float *>(_outputData), /*result_stride=*/1);
+
+ // Apply activation function
+ ::tflite::tensor_utils::ApplyActivationToVector(reinterpret_cast<float *>(_outputData),
+ batch_size * num_units, act,
+ reinterpret_cast<float *>(_outputData));
+
return true;
}
bool FullyConnectedLayer::fullyConnectedQuant8()
{
- int32_t inputOffset = -_inputShape.offset;
- int32_t weightsOffset = -_weightsShape.offset;
- int32_t outputOffset = _outputShape.offset;
- float 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;
- // Caution : 'Convolution' can make misleading. It seems it is just math term.
- if (!GetQuantizedConvolutionMultipler(_inputShape, _weightsShape, _biasShape, _outputShape,
- &real_multiplier) ||
- !QuantizeMultiplierSmallerThanOne(real_multiplier, &output_multiplier, &output_shift))
- {
- return false;
- }
- CalculateActivationRangeUint8(_activation, _outputShape, &output_activation_min,
- &output_activation_max);
- static gemmlowp::GemmContext gemm_context;
- // Prevent concurrent executions that access gemm_context.
- std::unique_lock<std::mutex> lock(executionMutex);
- // Alow gemmlowp automatically decide how many threads to use.
- gemm_context.set_max_num_threads(0);
- ::tflite::optimized_ops::FullyConnected(
- _inputData, convertShapeToDims(_inputShape), inputOffset, _weightsData,
- convertShapeToDims(_weightsShape), weightsOffset,
- reinterpret_cast<const int32_t *>(_biasData), convertShapeToDims(_biasShape), outputOffset,
- output_multiplier, output_shift, output_activation_min, output_activation_max, _outputData,
- convertShapeToDims(_outputShape), &gemm_context);
- return true;
+ throw std::runtime_error{"FullyConnectedLayer : Not tested for TENSOR_QUANT8_ASYMM"};
}
void FullyConnectedLayer::configure(uint8_t *inputData, const Shape inputShape,
diff --git a/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.h b/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.h
index b1ba172b0..20a388349 100644
--- a/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.h
+++ b/runtimes/neurun/src/kernel/cpu/FullyConnectedLayer.h
@@ -19,7 +19,7 @@
#include <NeuralNetworks.h>
-#include <arm_compute/runtime/IFunction.h>
+#include "exec/interface/IFunction.h"
#include "kernel/cpu/OperationUtils.h"
@@ -30,7 +30,7 @@ namespace kernel
namespace cpu
{
-class FullyConnectedLayer : public ::arm_compute::IFunction
+class FullyConnectedLayer : public ::neurun::exec::IFunction
{
public:
FullyConnectedLayer();
diff --git a/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.cc b/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.cc
index 3d96bb401..c4a288b07 100644
--- a/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.cc
+++ b/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.cc
@@ -26,14 +26,14 @@ namespace kernel
namespace cpu
{
-#define MAXPOOLING_PARAMETERS \
- uint32_t height = getSizeOfDimension(_inputShape, 1); \
- uint32_t width = getSizeOfDimension(_inputShape, 2); \
- uint32_t outHeight = getSizeOfDimension(_outputShape, 1); \
- uint32_t outWidth = getSizeOfDimension(_outputShape, 2); \
- \
- uint32_t paddingHeight = (uint32_t)_paddingTop; \
- uint32_t paddingWidth = (uint32_t)_paddingLeft;
+#define MAXPOOLING_PARAMETERS \
+ tflite::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()
: _inputData(nullptr), _outputData(nullptr), _inputShape(), _outputShape(), _paddingLeft(0),
@@ -46,31 +46,30 @@ MaxPoolLayer::MaxPoolLayer()
bool 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;
- ::tflite::optimized_ops::MaxPool(
- reinterpret_cast<const float *>(_inputData), convertShapeToDims(_inputShape), _strideWidth,
- _strideHeight, paddingWidth, paddingHeight, _kernelWidth, _kernelHeight,
- output_activation_min, output_activation_max, reinterpret_cast<float *>(_outputData),
- convertShapeToDims(_outputShape));
+ ::tflite::optimized_ops::MaxPool(op_params, convertShapeToTFLiteShape(_inputShape),
+ reinterpret_cast<const float *>(_inputData),
+ convertShapeToTFLiteShape(_outputShape),
+ reinterpret_cast<float *>(_outputData));
return true;
}
bool MaxPoolLayer::maxPoolQuant8()
{
-
MAXPOOLING_PARAMETERS
int32_t output_activation_min = 0;
int32_t output_activation_max = 0;
CalculateActivationRangeUint8(_activation, _outputShape, &output_activation_min,
&output_activation_max);
+ op_params.quantized_activation_min = output_activation_min;
+ op_params.quantized_activation_max = output_activation_max;
- ::tflite::optimized_ops::MaxPool(_inputData, convertShapeToDims(_inputShape), _strideWidth,
- _strideHeight, paddingWidth, paddingHeight, _kernelWidth,
- _kernelHeight, output_activation_min, output_activation_max,
- _outputData, convertShapeToDims(_outputShape));
+ ::tflite::optimized_ops::MaxPool(op_params, convertShapeToTFLiteShape(_inputShape), _inputData,
+ convertShapeToTFLiteShape(_outputShape), _outputData);
return true;
}
diff --git a/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.h b/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.h
index b42efb9f6..2b185550b 100644
--- a/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.h
+++ b/runtimes/neurun/src/kernel/cpu/MaxPoolLayer.h
@@ -19,7 +19,7 @@
#include <NeuralNetworks.h>
-#include <arm_compute/runtime/IFunction.h>
+#include "exec/interface/IFunction.h"
#include "kernel/cpu/OperationUtils.h"
@@ -30,7 +30,7 @@ namespace kernel
namespace cpu
{
-class MaxPoolLayer : public ::arm_compute::IFunction
+class MaxPoolLayer : public ::neurun::exec::IFunction
{
public:
MaxPoolLayer();
diff --git a/runtimes/neurun/src/kernel/cpu/OperationUtils.cc b/runtimes/neurun/src/kernel/cpu/OperationUtils.cc
index 5ec2f8e62..b28508c27 100644
--- a/runtimes/neurun/src/kernel/cpu/OperationUtils.cc
+++ b/runtimes/neurun/src/kernel/cpu/OperationUtils.cc
@@ -184,7 +184,7 @@ int32_t CalculateInputRadius(int input_integer_bits, int input_left_shift)
return static_cast<int32_t>(std::floor(max_input_rescaled));
}
-Shape getShape(const ::neurun::graph::operand::Object &o)
+Shape getShape(const ::neurun::model::operand::Object &o)
{
Shape shape;
diff --git a/runtimes/neurun/src/kernel/cpu/OperationUtils.h b/runtimes/neurun/src/kernel/cpu/OperationUtils.h
index 5914d04e3..3610990a5 100644
--- a/runtimes/neurun/src/kernel/cpu/OperationUtils.h
+++ b/runtimes/neurun/src/kernel/cpu/OperationUtils.h
@@ -23,11 +23,13 @@
#include <limits>
#include <vector>
+#include "tensorflow/contrib/lite/c/builtin_op_data.h"
#include "tensorflow/contrib/lite/kernels/internal/types.h"
-#include "graph/operand/Object.h"
-#include "graph/operand/DataType.h"
+#include "tensorflow/contrib/lite/kernels/internal/tensor.h"
+#include "model/operand/Object.h"
+#include "model/operand/DataType.h"
-using OperandType = neurun::graph::operand::DataType;
+using OperandType = neurun::model::operand::DataType;
namespace neurun
{
@@ -75,6 +77,51 @@ inline ::tflite::Dims<4> convertShapeToDims(const Shape &shape)
return dims;
}
+inline ::tflite::RuntimeShape convertShapeToTFLiteShape(const Shape &shape)
+{
+ std::vector<int32_t> raw_shape;
+ raw_shape.resize(4);
+
+ for (uint32_t i = 0; i < 4; ++i)
+ {
+ if (i >= shape.dimensions.size())
+ {
+ raw_shape[i] = 1;
+ }
+ else
+ {
+ raw_shape[i] = shape.dimensions[i];
+ }
+ }
+
+ return ::tflite::GetTensorShape(raw_shape);
+}
+
+inline TfLiteFusedActivation convertFusedActivation(FuseCode act)
+{
+ if (act == ANEURALNETWORKS_FUSED_NONE)
+ {
+ return kTfLiteActNone;
+ }
+
+ if (act == ANEURALNETWORKS_FUSED_RELU)
+ {
+ return kTfLiteActRelu;
+ }
+
+ if (act == ANEURALNETWORKS_FUSED_RELU1)
+ {
+ return kTfLiteActRelu1;
+ }
+
+ if (act == ANEURALNETWORKS_FUSED_RELU6)
+ {
+ return kTfLiteActRelu6;
+ }
+
+ return kTfLiteActNone;
+}
+
__wur bool QuantizeMultiplierSmallerThanOne(double double_multiplier, int32_t *quantized_multiplier,
int32_t *right_shift);
@@ -92,7 +139,7 @@ void CalculateActivationRangeUint8(int32_t activation, const Shape &outputShape,
int32_t CalculateInputRadius(int input_integer_bits, int input_left_shift);
-Shape getShape(const ::neurun::graph::operand::Object &o);
+Shape getShape(const ::neurun::model::operand::Object &o);
uint32_t sizeOfData(OperandType type, const std::vector<uint32_t> &dimensions);
diff --git a/runtimes/neurun/src/kernel/cpu/PermuteLayer.cc b/runtimes/neurun/src/kernel/cpu/PermuteLayer.cc
new file mode 100644
index 000000000..ba8c5ab92
--- /dev/null
+++ b/runtimes/neurun/src/kernel/cpu/PermuteLayer.cc
@@ -0,0 +1,201 @@
+/*
+ * 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"
+
+#include "util/feature/nhwc/Reader.h"
+#include "util/feature/nhwc/View.h"
+#include "util/feature/nchw/View.h"
+#include "util/feature/Coordinate4D.h"
+
+#include <misc/feature/IndexIterator.h>
+
+namespace neurun
+{
+namespace kernel
+{
+namespace cpu
+{
+
+using Type = model::operation::PermuteNode::Type;
+
+void PermuteLayer::configure(std::shared_ptr<::neurun::backend::operand::IObject> input,
+ std::shared_ptr<::neurun::backend::operand::IObject> output,
+ const model::operand::Shape &shape, Type type)
+{
+ _input = input;
+ _output = output;
+ _shape = shape;
+ _type = type;
+}
+
+void PermuteLayer::run()
+{
+ auto rank = _shape.rank();
+
+ switch (_type)
+ {
+ case Type::NHWC_TO_NCHW:
+ {
+ auto fn = [&](::neurun::backend::operand::ITensor &tensor) {
+ auto input_tensor = _input->ptr();
+
+ auto input_buffer = input_tensor->buffer();
+ auto input_size = input_tensor->total_size();
+
+ auto output_buffer = tensor.buffer();
+ auto output_size = tensor.total_size();
+ switch (rank)
+ {
+ case 0:
+ case 1:
+ {
+ memcpy(output_buffer, input_buffer, input_size);
+ break;
+ }
+ case 2:
+ {
+ auto matrix_shape = _shape.asMatrix();
+
+ for (auto h = 0; h < matrix_shape.H; ++h)
+ {
+ neurun::util::feature::Coordinate4D coord{0, h, 0, 0};
+ memcpy(output_buffer + tensor.calcOffset(coord), input_buffer + h * matrix_shape.W,
+ matrix_shape.W * sizeof(float));
+ }
+ break;
+ }
+ case 3:
+ {
+ const int32_t depth = _shape.dim(0);
+ const int32_t height = _shape.dim(1);
+ const int32_t width = _shape.dim(2);
+
+ for (auto c = 0; c < depth; ++c)
+ {
+ for (auto h = 0; h < height; ++h)
+ {
+ neurun::util::feature::Coordinate4D coord{0, h, 0, c};
+ memcpy(output_buffer + tensor.calcOffset(coord),
+ input_buffer + c * height * width + h * width, width * sizeof(float));
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ auto feature = _shape.asFeature();
+
+ const util::feature::nhwc::Reader<float> from{
+ feature, reinterpret_cast<const float *>(input_buffer), input_size};
+ util::feature::nchw::View<float> into{&tensor};
+
+ ::nnfw::misc::feature::iterate(feature)
+ << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(batch, ch, row, col);
+ into.at(batch, ch, row, col) = value;
+ };
+ break;
+ }
+ default:
+ throw "NYI";
+ break;
+ }
+ };
+ _output->access(fn);
+ break;
+ }
+ case Type::NCHW_TO_NHWC:
+ {
+ auto fn = [&](::neurun::backend::operand::ITensor &tensor) {
+ auto input_buffer = tensor.buffer();
+ auto input_size = tensor.total_size();
+
+ auto output_tensor = _output->ptr();
+
+ auto output_buffer = output_tensor->buffer();
+ auto output_size = output_tensor->total_size();
+
+ switch (rank)
+ {
+ case 0:
+ case 1:
+ {
+ memcpy(output_buffer, input_buffer, output_size);
+ break;
+ }
+ case 2:
+ {
+ auto matrix_shape = _shape.asMatrix();
+
+ for (auto h = 0; h < matrix_shape.H; ++h)
+ {
+ neurun::util::feature::Coordinate4D coord{0, h, 0, 0};
+ memcpy(output_buffer + h * matrix_shape.W, input_buffer + tensor.calcOffset(coord),
+ matrix_shape.W * sizeof(float));
+ }
+ break;
+ }
+ case 3:
+ {
+ const int32_t depth = _shape.dim(0);
+ const int32_t height = _shape.dim(1);
+ const int32_t width = _shape.dim(2);
+
+ for (auto c = 0; c < depth; ++c)
+ {
+ for (auto h = 0; h < height; ++h)
+ {
+ neurun::util::feature::Coordinate4D coord{0, h, 0, c};
+ memcpy(output_buffer + c * height * width + h * width,
+ input_buffer + tensor.calcOffset(coord), width * sizeof(float));
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ auto feature = _shape.asFeature();
+
+ const util::feature::nchw::View<float> from{&tensor};
+ util::feature::nhwc::View<float> into{feature, reinterpret_cast<float *>(output_buffer),
+ output_size};
+
+ ::nnfw::misc::feature::iterate(feature)
+ << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(batch, ch, row, col);
+ into.at(batch, ch, row, col) = value;
+ };
+ break;
+ }
+ default:
+ throw "NYI";
+ break;
+ }
+ };
+ _input->access(fn);
+ break;
+ }
+ case Type::COPY:
+ // If two different backends using same tensor layout, we need this.
+ throw "NYI";
+ break;
+ }
+}
+
+} // namespace cpu
+} // namespace kernel
+} // namespace neurun
diff --git a/runtimes/neurun/src/kernel/cpu/PermuteLayer.h b/runtimes/neurun/src/kernel/cpu/PermuteLayer.h
new file mode 100644
index 000000000..d9e1709bc
--- /dev/null
+++ b/runtimes/neurun/src/kernel/cpu/PermuteLayer.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 __NEURUN_KERNEL_CPU_PERMUTE_LAYER_H__
+#define __NEURUN_KERNEL_CPU_PERMUTE_LAYER_H__
+
+#include <NeuralNetworks.h>
+
+#include "exec/interface/IFunction.h"
+
+#include "util/feature/nhwc/View.h"
+#include "OperationUtils.h"
+#include "backend/interface/operand/IObject.h"
+#include "model/operation/PermuteNode.h"
+
+namespace neurun
+{
+namespace kernel
+{
+namespace cpu
+{
+
+class PermuteLayer : public ::neurun::exec::IFunction
+{
+public:
+ PermuteLayer() = default;
+
+public:
+ void configure(std::shared_ptr<::neurun::backend::operand::IObject> input,
+ std::shared_ptr<::neurun::backend::operand::IObject> output,
+ const model::operand::Shape &shape, model::operation::PermuteNode::Type type);
+ void run();
+
+private:
+ std::shared_ptr<::neurun::backend::operand::IObject> _input;
+ std::shared_ptr<::neurun::backend::operand::IObject> _output;
+ model::operand::Shape _shape;
+ model::operation::PermuteNode::Type _type;
+};
+
+} // namespace cpu
+} // namespace kernel
+} // namespace neurun
+
+#endif // __NEURUN_KERNEL_CPU_PERMUTE_LAYER_H__
diff --git a/runtimes/neurun/src/kernel/cpu/ReshapeLayer.h b/runtimes/neurun/src/kernel/cpu/ReshapeLayer.h
index 395cc1d7f..51d0bacee 100644
--- a/runtimes/neurun/src/kernel/cpu/ReshapeLayer.h
+++ b/runtimes/neurun/src/kernel/cpu/ReshapeLayer.h
@@ -19,7 +19,7 @@
#include <NeuralNetworks.h>
-#include <arm_compute/runtime/IFunction.h>
+#include "exec/interface/IFunction.h"
#include "kernel/cpu/OperationUtils.h"
@@ -30,7 +30,7 @@ namespace kernel
namespace cpu
{
-class ReshapeLayer : public ::arm_compute::IFunction
+class ReshapeLayer : public ::neurun::exec::IFunction
{
public:
ReshapeLayer();
diff --git a/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.cc b/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.cc
index 4f5a69f2e..c998c65f6 100644
--- a/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.cc
+++ b/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.cc
@@ -33,45 +33,86 @@ SoftMaxLayer::SoftMaxLayer()
// 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)
+{
+ TF_LITE_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;
+ }
+}
+
bool SoftMaxLayer::softmaxFloat32()
{
- ::tflite::Dims<4> dim;
+ Shape shapeIn4D;
+
if (getNumberOfDimensions(_inputShape) == 2)
{
uint32_t batch_size = getSizeOfDimension(_inputShape, 0);
uint32_t input_size = getNumberOfElements(_inputShape) / batch_size;
- Shape shapeIn4D;
- shapeIn4D.dimensions = {batch_size, 1, 1, input_size};
- dim = convertShapeToDims(shapeIn4D);
+ Softmax(reinterpret_cast<const float *>(_inputData), input_size, batch_size, _beta,
+ reinterpret_cast<float *>(_outputData));
}
else if (getNumberOfDimensions(_inputShape) == 4)
{
- dim = convertShapeToDims(_inputShape);
+ ::tflite::SoftmaxParams op_params;
+ op_params.beta = _beta;
+ ::tflite::optimized_ops::Softmax(op_params, convertShapeToTFLiteShape(_inputShape),
+ reinterpret_cast<const float *>(_inputData),
+ convertShapeToTFLiteShape(_outputShape),
+ reinterpret_cast<float *>(_outputData));
}
else
{
std::cout << "only 2D and 4D tensors supported" << std::endl;
return false;
}
- ::tflite::optimized_ops::Softmax(reinterpret_cast<const float *>(_inputData), dim, _beta,
- reinterpret_cast<float *>(_outputData), dim);
+
return true;
}
bool SoftMaxLayer::softmaxQuant8()
{
- ::tflite::Dims<4> dim;
+ Shape shapeIn4D = _inputShape;
+
if (getNumberOfDimensions(_inputShape) == 2)
{
uint32_t batch_size = getSizeOfDimension(_inputShape, 0);
uint32_t input_size = getNumberOfElements(_inputShape) / batch_size;
- Shape shapeIn4D;
shapeIn4D.dimensions = {batch_size, 1, 1, input_size};
- dim = convertShapeToDims(shapeIn4D);
}
else if (getNumberOfDimensions(_inputShape) == 4)
{
- dim = convertShapeToDims(_inputShape);
+ shapeIn4D = _inputShape;
}
else
{
@@ -94,8 +135,13 @@ bool SoftMaxLayer::softmaxQuant8()
return false;
}
float diff_min = -1.0f * CalculateInputRadius(kScaledDiffIntegerBits, input_left_shift);
- ::tflite::optimized_ops::Softmax(_inputData, dim, input_multiplier, input_left_shift, diff_min,
- _outputData, dim);
+
+ ::tflite::SoftmaxParams op_params;
+ op_params.input_multiplier = input_multiplier;
+ op_params.input_left_shift = input_left_shift;
+ op_params.diff_min = diff_min;
+ ::tflite::optimized_ops::Softmax(op_params, convertShapeToTFLiteShape(shapeIn4D), _inputData,
+ convertShapeToTFLiteShape(shapeIn4D), _outputData);
return true;
}
diff --git a/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.h b/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.h
index 8057be52f..df1aa4044 100644
--- a/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.h
+++ b/runtimes/neurun/src/kernel/cpu/SoftMaxLayer.h
@@ -19,7 +19,7 @@
#include <NeuralNetworks.h>
-#include <arm_compute/runtime/IFunction.h>
+#include "exec/interface/IFunction.h"
#include "kernel/cpu/OperationUtils.h"
@@ -30,7 +30,7 @@ namespace kernel
namespace cpu
{
-class SoftMaxLayer : public ::arm_compute::IFunction
+class SoftMaxLayer : public ::neurun::exec::IFunction
{
public:
SoftMaxLayer();
diff --git a/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.cc b/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.cc
deleted file mode 100644
index 00e914732..000000000
--- a/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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 IS UNUSED BUT LEFT FOR FUTURE REFERNCE
-//
-
-#if 0
-
-#include "TensorConvertFromCommonLayer.h"
-
-#include "internal/nnapi/feature/Reader.h"
-#include "internal/nnapi/feature/View.h"
-
-#include <util/feature/IndexIterator.h>
-
-namespace neurun
-{
-namespace kernel
-{
-namespace cpu
-{
-
-bool TensorConvertFromCommonLayer::convert()
-{
- auto inputBuffer = _inputTensor->buffer();
- auto inputSize = _inputTensor->info()->total_size();
-
- auto outputBuffer = _outputTensor->buffer();
- auto outputSize = _outputTensor->info()->total_size();
-
- if (_tensorShape.rank() == 2)
- {
- const auto len = _tensorShape.dim(1);
-
- auto base = reinterpret_cast<const float *>(inputBuffer);
-
- for (int32_t n = 0; n < len; ++n)
- {
- auto from = base + n;
- auto into =
- reinterpret_cast<float *>(_outputTensor->ptr_to_element(::arm_compute::Coordinates{n}));
-
- *into = *from;
- }
- }
- else if (_tensorShape.rank() == 4)
- {
- auto featureShape = _tensorShape.asFeature();
-
- const ::internal::nnapi::feature::Reader<float> from{featureShape, inputBuffer, inputSize};
- ::internal::nnapi::feature::View<float> into{featureShape, outputBuffer, outputSize};
-
- ::nnfw::util::feature::iterate(featureShape)
- << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(batch, ch, row, col);
- into.at(batch, ch, row, col) = value;
- };
- }
-}
-
-void TensorConvertFromCommonLayer::configure(::internal::common::Tensor *inputTensor,
- ::internal::cpu::Tensor *outputTensor,
- const Shape &tensorShape)
-{
- _inputTensor = inputTensor;
- _outputTensor = outputTensor;
- _tensorShape = tensorShape;
-}
-
-void TensorConvertFromCommonLayer::run() { convert(); }
-
-} // namespace cpu
-} // namespace kernel
-} // namespace neurun
-
-#endif
diff --git a/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.h b/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.h
deleted file mode 100644
index 56f7bcf32..000000000
--- a/runtimes/neurun/src/kernel/cpu/TensorConvertFromCommonLayer.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 IS UNUSED BUT LEFT FOR FUTURE REFERNCE
-//
-
-#if 0
-
-#ifndef __NEURUN_KERNEL_CPU_TENSOR_CONVERT_FROM_COMMON_LAYER_H__
-#define __NEURUN_KERNEL_CPU_TENSOR_CONVERT_FROM_COMMON_LAYER_H__
-
-#include <NeuralNetworks.h>
-
-#include <arm_compute/runtime/IFunction.h>
-
-#include "internal/Model.h"
-#include "internal/common/Tensor.h"
-#include "internal/cpu.h"
-
-namespace neurun
-{
-namespace kernel
-{
-namespace cpu
-{
-
-class TensorConvertFromCommonLayer : public ::arm_compute::IFunction
-{
-public:
- TensorConvertFromCommonLayer() {}
-
-public:
- bool convert();
-
- void configure(::internal::common::Tensor *inputTensor, ::internal::cpu::Tensor *outputTensor,
- const Shape &tensorShape);
-
- void run();
-
-private:
- ::internal::common::Tensor *_inputTensor;
- ::internal::cpu::Tensor *_outputTensor;
-
- Shape _tensorShape{1};
-};
-
-} // namespace cpu
-} // namespace kernel
-} // namespace neurun
-
-#endif // __NEURUN_KERNEL_CPU_TENSOR_CONVERT_FROM_COMMON_LAYER_H__
-
-#endif
diff --git a/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.cc b/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.cc
deleted file mode 100644
index 7d721f494..000000000
--- a/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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 IS UNUSED BUT LEFT FOR FUTURE REFERNCE
-//
-
-#if 0
-
-#include "TensorConvertToCommonLayer.h"
-
-#include "internal/nnapi/feature/Reader.h"
-#include "internal/nnapi/feature/View.h"
-
-#include <util/feature/IndexIterator.h>
-
-namespace neurun
-{
-namespace kernel
-{
-namespace cpu
-{
-
-bool TensorConvertToCommonLayer::convert()
-{
- auto inputBuffer = _inputTensor->buffer();
- auto inputSize = _inputTensor->info()->total_size();
-
- auto outputBuffer = _outputTensor->buffer();
- auto outputSize = _outputTensor->info()->total_size();
-
- if (_tensorShape.rank() == 2)
- {
- const auto len = _tensorShape.dim(1);
-
- auto base = reinterpret_cast<float *>(outputBuffer);
-
- for (int32_t n = 0; n < len; ++n)
- {
- auto from = reinterpret_cast<const float *>(
- _inputTensor->ptr_to_element(::arm_compute::Coordinates{n}));
- auto into = base + n;
-
- *into = *from;
- }
- }
- else if (_tensorShape.rank() == 4)
- {
- auto featureShape = _tensorShape.asFeature();
-
- const ::internal::nnapi::feature::Reader<float> from{featureShape, inputBuffer, inputSize};
- ::internal::nnapi::feature::View<float> into{featureShape, outputBuffer, outputSize};
-
- ::nnfw::util::feature::iterate(featureShape)
- << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
- const auto value = from.at(batch, ch, row, col);
- into.at(batch, ch, row, col) = value;
- };
- }
-}
-
-void TensorConvertToCommonLayer::configure(::internal::cpu::Tensor *inputTensor,
- ::internal::common::Tensor *outputTensor,
- const Shape &tensorShape)
-{
- _inputTensor = inputTensor;
- _outputTensor = outputTensor;
- _tensorShape = tensorShape;
-}
-
-void TensorConvertToCommonLayer::run() { convert(); }
-
-} // namespace cpu
-} // namespace kernel
-} // namespace neurun
-
-#endif
diff --git a/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.h b/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.h
deleted file mode 100644
index 7e96d1aff..000000000
--- a/runtimes/neurun/src/kernel/cpu/TensorConvertToCommonLayer.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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 IS UNUSED BUT LEFT FOR FUTURE REFERNCE
-//
-
-#if 0
-
-#ifndef __NEURUN_KERNEL_CPU_TENSOR_CONVERT_TO_COMMON_LAYER_H__
-#define __NEURUN_KERNEL_CPU_TENSOR_CONVERT_TO_COMMON_LAYER_H__
-
-#include <NeuralNetworks.h>
-
-#include <arm_compute/runtime/IFunction.h>
-
-#include "internal/Model.h"
-#include "internal/common/Tensor.h"
-#include "internal/cpu.h"
-
-namespace neurun
-{
-namespace kernel
-{
-namespace cpu
-{
-
-class TensorConvertToCommonLayer : public ::arm_compute::IFunction
-{
-public:
- TensorConvertToCommonLayer() {}
-
-public:
- bool convert();
-
- void configure(::internal::cpu::Tensor *inputTensor, ::internal::common::Tensor *outputTensor,
- const Shape &tensorShape);
-
- void run();
-
-private:
- ::internal::cpu::Tensor *_inputTensor;
- ::internal::common::Tensor *_outputTensor;
-
- Shape _tensorShape{1};
-};
-
-} // namespace cpu
-} // namespace kernel
-} // namespace neurun
-
-#endif // __NEURUN_KERNEL_CPU_TENSOR_CONVERT_TO_COMMON_LAYER_H__
-
-#endif
diff --git a/runtimes/neurun/src/linear/Linear.cc b/runtimes/neurun/src/linear/Linear.cc
index 2ffcbdb93..6452bbd49 100644
--- a/runtimes/neurun/src/linear/Linear.cc
+++ b/runtimes/neurun/src/linear/Linear.cc
@@ -14,19 +14,26 @@
* limitations under the License.
*/
+#include <algorithm>
+
#include "Linear.h"
#include "graph/Graph.h"
#include "graph/operation/LowerInfo.h"
-#include "backend/IStageGenerator.h"
+#include "backend/interface/IStageGenerator.h"
+#include "backend/interface/IConfig.h"
+#include "compiler/SubTensorInfo.h"
+#include "compiler/TensorInfo.h"
+
+#include "util/logging.h"
namespace neurun
{
namespace linear
{
-Linear::Linear(const graph::Graph &graph)
+Linear::Linear(const graph::Graph &graph) : _graph(graph)
{
// Linearize with topological sort
//
@@ -36,38 +43,157 @@ Linear::Linear(const graph::Graph &graph)
// 3. Reverse the order of nodes
graph::Graph::PostDfsConstIterator().iterate(
- graph, [&](const neurun::graph::operation::Node &node) { _operations.emplace_back(&node); });
+ graph, [&](const model::operation::Index &index, const model::operation::Node &node) {
+ const auto lower_info = graph.getLowerInfo(index);
+ _operations.emplace_back(&node, lower_info);
+ });
std::reverse(std::begin(_operations), std::end(_operations));
}
-void Linear::accept(graph::operation::NodeVisitor &&visitor) const
+void Linear::accept(model::operation::NodeVisitor &&visitor) const
{
for (const auto op : _operations)
{
- op->accept(std::move(visitor));
+ op.node->accept(std::move(visitor));
}
}
-backend::TensorBuilderSet Linear::markTensors() const
+backend::TensorBuilderSet Linear::planTensors()
{
+ using ITensorBuilderPtr = std::shared_ptr<backend::ITensorBuilder>;
+ using FnOnTensorBuilder =
+ std::function<void(const model::operand::Index &ind, ITensorBuilderPtr)>;
+
+ const auto &operands = _graph.operands();
+ auto iterTensorBuilders = [&operands](const model::operand::Index &ind, FnOnTensorBuilder fn) {
+ const auto &obj = operands.at(ind);
+ for (auto backend : obj.lower_info()->def_backends())
+ {
+ auto tensor_builder = backend->tensor_builder();
+ fn(ind, tensor_builder);
+ }
+ };
+
backend::TensorBuilderSet tensor_builders;
+
+ std::unordered_map<model::operand::Index, uint32_t> uses_map;
+ std::vector<model::operand::Index> constants;
+
+ _graph.operands().iterate(
+ [&](const model::operand::Index &ind, const model::operand::Object &obj) {
+ uses_map[ind] = obj.getUses().size();
+
+ // If a tensor is a constant, increase the use of the tensor.
+ // It makes the tensor not be dealloced.
+ if (obj.getUsage() == model::operand::OperandUsage::CONSTANT)
+ {
+ constants.push_back(ind);
+ uses_map[ind]++;
+ }
+
+ for (auto backend : obj.lower_info()->def_backends())
+ {
+ bool isSubTensor = false;
+ auto tensor_builder = backend->tensor_builder();
+
+ if (backend->config()->SupportSubTensorAlloc())
+ {
+ const auto parentInfo = obj.parent_info();
+ if (parentInfo != nullptr)
+ {
+ isSubTensor = true;
+ }
+ }
+
+ if (isSubTensor)
+ {
+ const compiler::SubTensorInfo info(obj);
+ tensor_builder->registerSubTensorInfo(ind, info);
+ }
+ else
+ {
+ const auto info = compiler::TensorInfo(obj.shape(), obj.typeInfo());
+ tensor_builder->registerTensorInfo(ind, info);
+ }
+
+ // Prepare tensor builders to be returned
+ tensor_builders.insert(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]++;
+ }
+
+ // Allocate constant operands first
+ VERBOSE(LINEAR) << "TENSORS as CONSTANT" << std::endl;
+ for (const auto &ind : constants)
+ {
+ iterTensorBuilders(ind, [](const model::operand::Index &ind, ITensorBuilderPtr tensor_builder) {
+ tensor_builder->notifyFirstUse(ind);
+ });
+ }
+
+ // Allocate Model's inputs
+ VERBOSE(LINEAR) << "TENSORS as MODEL INPUT" << std::endl;
+ for (const auto &ind : _graph.getInputs())
+ {
+ iterTensorBuilders(ind, [](const model::operand::Index &ind, ITensorBuilderPtr tensor_builder) {
+ tensor_builder->notifyFirstUse(ind);
+ });
+ }
+
+ // At each operation,
+ // 1. Scan USE of inputs. Decrease the USE and deallocate if the USE is 0
+ // 2. Scan DEF of outputs. If the DEF, allocate it
+ VERBOSE(LINEAR) << "TENSORS" << std::endl;
for (const auto op : _operations)
{
- const auto tensor_builder = op->lower_info()->backend().stage_gen()->tensor_builder();
- for (const auto &ind : op->getInputs())
+ for (const auto &ind : op.node->getOutputs())
{
- tensor_builder->mark(ind);
- tensor_builders.insert(tensor_builder);
+ const auto &obj = operands.at(ind);
+ if (obj.getDef().size())
+ {
+ iterTensorBuilders(ind,
+ [](const model::operand::Index &ind, ITensorBuilderPtr tensor_builder) {
+ tensor_builder->notifyFirstUse(ind);
+ });
+ }
}
- for (const auto &ind : op->getOutputs())
+
+ for (const auto &ind : op.node->getInputs())
{
- tensor_builder->mark(ind);
- tensor_builders.insert(tensor_builder);
+ uses_map[ind]--;
+ if (uses_map[ind] == 0)
+ {
+ iterTensorBuilders(ind,
+ [](const model::operand::Index &ind, ITensorBuilderPtr tensor_builder) {
+ tensor_builder->notifyLastUse(ind);
+ });
+ }
}
}
+
+ // Now, model outputs should be not deallocated
+ assert(std::all_of(_graph.getOutputs().begin(), _graph.getOutputs().end(),
+ [&uses_map](const model::operand::Index &ind) { return uses_map[ind] > 0; }));
+
+ // Set subtensor information
+ // Todo: move this phase outside as optimization phase
return tensor_builders;
}
+void Linear::iterate(const std::function<void(const Element &element)> &fn) const
+{
+ for (const auto op : _operations)
+ {
+ fn(op);
+ }
+}
+
} // namespace linear
} // namespace neurun
diff --git a/runtimes/neurun/src/linear/Linear.h b/runtimes/neurun/src/linear/Linear.h
index ffbc68ecb..fb3f539d4 100644
--- a/runtimes/neurun/src/linear/Linear.h
+++ b/runtimes/neurun/src/linear/Linear.h
@@ -19,8 +19,8 @@
#include <vector>
-#include "graph/operation/Node.h"
-#include "backend/ITensorBuilder.h"
+#include "model/operation/Node.h"
+#include "backend/interface/ITensorBuilder.h"
namespace neurun
{
@@ -46,6 +46,17 @@ namespace neurun
namespace linear
{
+struct Element
+{
+ const model::operation::Node *node;
+ const graph::operation::LowerInfo *lower_info;
+
+ Element(const model::operation::Node *node, const graph::operation::LowerInfo *lower_info)
+ : node{node}, lower_info{lower_info}
+ {
+ }
+};
+
class Linear
{
public:
@@ -55,14 +66,16 @@ public:
Linear(const Linear &linear) = delete;
public:
- void accept(graph::operation::NodeVisitor &&visitor) const;
+ void accept(model::operation::NodeVisitor &&visitor) const;
// TODO Should not return TensorBuilderSet
- virtual backend::TensorBuilderSet markTensors() const;
+ backend::TensorBuilderSet planTensors();
+
+ void iterate(const std::function<void(const Element &element)> &fn) const;
-public:
private:
- std::vector<const graph::operation::Node *> _operations;
+ const graph::Graph &_graph;
+ std::vector<Element> _operations;
};
} // namespace linear
diff --git a/runtimes/neurun/src/graph/operand/Data.h b/runtimes/neurun/src/model/operand/Data.h
index e36a9a2ae..506cb185a 100644
--- a/runtimes/neurun/src/graph/operand/Data.h
+++ b/runtimes/neurun/src/model/operand/Data.h
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERAND_DATA_H__
-#define __NEURUN_GRAPH_OPERAND_DATA_H__
+#ifndef __NEURUN_MODEL_OPERAND_DATA_H__
+#define __NEURUN_MODEL_OPERAND_DATA_H__
#include <algorithm>
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -72,7 +72,7 @@ private:
};
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERAND_DATA_H__
+#endif // __NEURUN_MODEL_OPERAND_DATA_H__
diff --git a/runtimes/neurun/src/graph/operand/DataType.h b/runtimes/neurun/src/model/operand/DataType.h
index 8878901fd..d75a0dbf1 100644
--- a/runtimes/neurun/src/graph/operand/DataType.h
+++ b/runtimes/neurun/src/model/operand/DataType.h
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERAND_DATATYPE_H__
-#define __NEURUN_GRAPH_OPERAND_DATATYPE_H__
+#ifndef __NEURUN_MODEL_OPERAND_DATATYPE_H__
+#define __NEURUN_MODEL_OPERAND_DATATYPE_H__
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -37,7 +37,7 @@ enum class DataType
};
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERAND_DATATYPE_H__
+#endif // __NEURUN_MODEL_OPERAND_DATATYPE_H__
diff --git a/runtimes/neurun/src/graph/operand/Index.h b/runtimes/neurun/src/model/operand/Index.h
index a6850d061..1c84ba451 100644
--- a/runtimes/neurun/src/graph/operand/Index.h
+++ b/runtimes/neurun/src/model/operand/Index.h
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERAND_INDEX_H__
-#define __NEURUN_GRAPH_OPERAND_INDEX_H__
+#ifndef __NEURUN_MODEL_OPERAND_INDEX_H__
+#define __NEURUN_MODEL_OPERAND_INDEX_H__
#include "graph/Index.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -29,12 +29,12 @@ namespace operand
using Index = ::neurun::graph::Index<uint32_t, struct IndexTag>;
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -45,7 +45,7 @@ using Index = ::neurun::graph::Index<uint32_t, struct IndexTag>;
} // namespace IO
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERAND_INDEX_H__
+#endif // __NEURUN_MODEL_OPERAND_INDEX_H__
diff --git a/runtimes/neurun/src/graph/operand/IndexSet.cc b/runtimes/neurun/src/model/operand/IndexSet.cc
index 037965a6d..b83d314e4 100644
--- a/runtimes/neurun/src/graph/operand/IndexSet.cc
+++ b/runtimes/neurun/src/model/operand/IndexSet.cc
@@ -20,7 +20,7 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -51,6 +51,11 @@ bool IndexSet::contains(const Index &index) const
return std::find(_set.begin(), _set.end(), index) != _set.end();
}
+void IndexSet::replace(const Index &from, const Index &to)
+{
+ std::replace(_set.begin(), _set.end(), from, to);
+}
+
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operand/IndexSet.h b/runtimes/neurun/src/model/operand/IndexSet.h
index 2d37de788..e8827de9c 100644
--- a/runtimes/neurun/src/graph/operand/IndexSet.h
+++ b/runtimes/neurun/src/model/operand/IndexSet.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERAND_INDEX_SET_H__
-#define __NEURUN_GRAPH_OPERAND_INDEX_SET_H__
+#ifndef __NEURUN_MODEL_OPERAND_INDEX_SET_H__
+#define __NEURUN_MODEL_OPERAND_INDEX_SET_H__
#include <initializer_list>
#include <vector>
@@ -24,7 +24,7 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -45,6 +45,7 @@ public:
const Index &at(IO::Index set_index) const { return _set.at(set_index.asInt()); }
const Index &at(uint32_t index) const { return _set.at(index); }
bool contains(const Index &index) const;
+ void replace(const Index &from, const Index &to);
public:
std::vector<Index>::const_iterator begin(void) const { return _set.begin(); }
@@ -55,7 +56,7 @@ private:
};
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERAND_INDEX_SET_H__
+#endif // __NEURUN_MODEL_OPERAND_INDEX_SET_H__
diff --git a/runtimes/neurun/src/graph/operand/Object.cc b/runtimes/neurun/src/model/operand/Object.cc
index 7b95cea97..63cf29bd3 100644
--- a/runtimes/neurun/src/graph/operand/Object.cc
+++ b/runtimes/neurun/src/model/operand/Object.cc
@@ -18,7 +18,7 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -73,7 +73,7 @@ bool Object::setUsage(const OperandUsage usage)
return true;
}
-void Object::appendUse(const ::neurun::graph::operation::Index &idx)
+void Object::appendUse(const ::neurun::model::operation::Index &idx)
{
assert(_usage != OperandUsage::NOT_DEFINED);
assert(!_uses.contains(idx));
@@ -81,7 +81,7 @@ void Object::appendUse(const ::neurun::graph::operation::Index &idx)
_uses.append(idx);
}
-void Object::removeUse(const ::neurun::graph::operation::Index &idx)
+void Object::removeUse(const ::neurun::model::operation::Index &idx)
{
assert(_usage != OperandUsage::NOT_DEFINED);
assert(_uses.contains(idx));
@@ -89,7 +89,7 @@ void Object::removeUse(const ::neurun::graph::operation::Index &idx)
_uses.remove(idx);
}
-void Object::appendDef(const ::neurun::graph::operation::Index &idx)
+void Object::appendDef(const ::neurun::model::operation::Index &idx)
{
assert(_usage != OperandUsage::NOT_DEFINED && _usage != OperandUsage::CONSTANT);
assert(_def.size() == 0);
@@ -97,7 +97,7 @@ void Object::appendDef(const ::neurun::graph::operation::Index &idx)
_def.append(idx);
}
-void Object::removeDef(const ::neurun::graph::operation::Index &idx)
+void Object::removeDef(const ::neurun::model::operation::Index &idx)
{
assert(_usage != OperandUsage::NOT_DEFINED);
assert(_def.contains(idx));
@@ -105,13 +105,24 @@ void Object::removeDef(const ::neurun::graph::operation::Index &idx)
_def.remove(idx);
}
-void Object::lower_info(std::unique_ptr<LowerInfo> &&lower_info)
+void Object::lower_info(std::unique_ptr<graph::operand::LowerInfo> &&lower_info)
{
_lower_info = std::move(lower_info);
}
-const LowerInfo *Object::lower_info() const { return _lower_info.get(); }
+const graph::operand::LowerInfo *Object::lower_info() const { return _lower_info.get(); }
+
+graph::operand::LowerInfo *Object::lower_info() { return _lower_info.get(); }
+
+void Object::parent_info(std::unique_ptr<graph::operand::ParentInfo> &&parent_info)
+{
+ _parent_info = std::move(parent_info);
+}
+
+const graph::operand::ParentInfo *Object::parent_info() const { return _parent_info.get(); }
+
+graph::operand::ParentInfo *Object::parent_info() { return _parent_info.get(); }
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operand/Object.h b/runtimes/neurun/src/model/operand/Object.h
index 17e46ab28..eb5f6275e 100644
--- a/runtimes/neurun/src/graph/operand/Object.h
+++ b/runtimes/neurun/src/model/operand/Object.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERAND_OBJECT_H__
-#define __NEURUN_GRAPH_OPERAND_OBJECT_H__
+#ifndef __NEURUN_MODEL_OPERAND_OBJECT_H__
+#define __NEURUN_MODEL_OPERAND_OBJECT_H__
#include <cassert>
#include <cstdint>
@@ -25,12 +25,13 @@
#include "Shape.h"
#include "Data.h"
#include "TypeInfo.h"
-#include "LowerInfo.h"
-#include "graph/operation/IndexList.h"
+#include "graph/operand/LowerInfo.h" // TODO Remove this dependency
+#include "graph/operand/ParentInfo.h" // TODO Remove this dependency
+#include "model/operation/IndexList.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -62,6 +63,7 @@ public:
bool setAsOperationOutput() { return setUsage(OperandUsage::OPERATION_OUTPUT); }
bool usageIsDefined(void) const { return _usage != OperandUsage::NOT_DEFINED; }
bool isModelInput(void) const { return _usage == OperandUsage::MODEL_INPUT; }
+ OperandUsage getUsage() const { return _usage; }
const operation::IndexList &getUses() const { return _uses; }
const operation::IndexList &getDef() const { return _def; }
@@ -94,8 +96,24 @@ public:
}
public:
- void lower_info(std::unique_ptr<LowerInfo> &&lower_info);
- const LowerInfo *lower_info() const;
+ void lower_info(std::unique_ptr<graph::operand::LowerInfo> &&lower_info);
+ const graph::operand::LowerInfo *lower_info() const;
+ graph::operand::LowerInfo *lower_info();
+ /**
+ * @brief Set parent information
+ * @param[in] parent_info Parent information
+ */
+ void parent_info(std::unique_ptr<graph::operand::ParentInfo> &&parent_info);
+ /**
+ * @brief Return parent information pointer as constant
+ * @return Parent information pointer
+ */
+ const graph::operand::ParentInfo *parent_info() const;
+ /**
+ * @brief Return parent information pointer
+ * @return Perent information pointer
+ */
+ graph::operand::ParentInfo *parent_info();
private:
const Shape _shape;
@@ -106,11 +124,12 @@ private:
operation::IndexList _uses;
operation::IndexList _def; // size is 0 (constant) or 1 (from def operation)
- std::unique_ptr<LowerInfo> _lower_info;
+ std::unique_ptr<graph::operand::LowerInfo> _lower_info;
+ std::unique_ptr<graph::operand::ParentInfo> _parent_info;
};
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERAND_OBJECT_H__
+#endif // __NEURUN_MODEL_OPERAND_OBJECT_H__
diff --git a/runtimes/neurun/src/graph/operand/Set.cc b/runtimes/neurun/src/model/operand/Set.cc
index 60dad2336..d93c21514 100644
--- a/runtimes/neurun/src/graph/operand/Set.cc
+++ b/runtimes/neurun/src/model/operand/Set.cc
@@ -16,11 +16,11 @@
#include "Set.h"
-#include "nnfw/std/memory.h"
+#include "cpp14/memory.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -36,7 +36,7 @@ Index Set::append(const Shape &shape, const TypeInfo &type)
{
auto index = generateIndex();
- _objects[index] = nnfw::make_unique<Object>(shape, type);
+ _objects[index] = nnfw::cpp14::make_unique<Object>(shape, type);
return index;
}
@@ -57,12 +57,28 @@ void Set::iterate(const std::function<void(const Index &, const Object &)> &fn)
void Set::iterate(const std::function<void(const Index &, Object &)> &fn)
{
+ // TODO Remove this workaround
+ // This implementation is a workaround in case of adding operands while iteration
+ //
+ // // Original Implementation (We probably should be back to this)
+ // for (auto &e : _objects)
+ // {
+ // fn(e.first, *e.second);
+ // }
+
+ std::list<Index> l;
+
for (auto &e : _objects)
{
- fn(e.first, *e.second);
+ l.push_back(e.first);
+ }
+
+ for (auto index : l)
+ {
+ fn(index, *_objects[index]);
}
}
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operand/Set.h b/runtimes/neurun/src/model/operand/Set.h
index c8266fed0..9dff7ec3c 100644
--- a/runtimes/neurun/src/graph/operand/Set.h
+++ b/runtimes/neurun/src/model/operand/Set.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERAND_SET_H__
-#define __NEURUN_GRAPH_OPERAND_SET_H__
+#ifndef __NEURUN_MODEL_OPERAND_SET_H__
+#define __NEURUN_MODEL_OPERAND_SET_H__
#include <memory>
#include <unordered_map>
@@ -25,7 +25,7 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -37,6 +37,7 @@ public:
public:
Index append(const Shape &, const TypeInfo &);
+ void remove(const Index &index) { _objects.erase(index); };
public:
const Object &at(const Index &) const;
@@ -54,7 +55,7 @@ private:
};
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERAND_SET_H__
+#endif // __NEURUN_MODEL_OPERAND_SET_H__
diff --git a/runtimes/neurun/src/graph/operand/Shape.cc b/runtimes/neurun/src/model/operand/Shape.cc
index f6d7a6999..f74c48d88 100644
--- a/runtimes/neurun/src/graph/operand/Shape.cc
+++ b/runtimes/neurun/src/model/operand/Shape.cc
@@ -20,7 +20,7 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -34,7 +34,17 @@ int32_t Shape::asVector(void) const
return dim(0);
}
-nnfw::util::feature::Shape Shape::asFeature(void) const
+nnfw::misc::matrix::Shape Shape::asMatrix(void) const
+{
+ assert(rank() == 2);
+
+ const auto height = dim(0);
+ const auto width = dim(1);
+
+ return nnfw::misc::matrix::Shape(height, width);
+}
+
+nnfw::misc::feature::Shape Shape::asFeature(void) const
{
assert(rank() == 4);
@@ -48,10 +58,10 @@ nnfw::util::feature::Shape Shape::asFeature(void) const
const auto height = dim(1);
const auto width = dim(2);
- return nnfw::util::feature::Shape(batch, depth, height, width);
+ return nnfw::misc::feature::Shape(batch, depth, height, width);
}
-nnfw::util::kernel::Shape Shape::asKernel(void) const
+nnfw::misc::kernel::Shape Shape::asKernel(void) const
{
assert(rank() == 4);
@@ -65,9 +75,20 @@ nnfw::util::kernel::Shape Shape::asKernel(void) const
const auto height = dim(1);
const auto width = dim(2);
- return nnfw::util::kernel::Shape(count, depth, height, width);
+ return nnfw::misc::kernel::Shape(count, depth, height, width);
+}
+
+nnfw::misc::tensor::Shape Shape::asTensor(void) const
+{
+ nnfw::misc::tensor::Shape shape{};
+ for (uint32_t i = 0; i < rank(); ++i)
+ {
+ shape.append(dim(i));
+ }
+
+ return shape; // this shape represents shape of NNAPI
}
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operand/Shape.h b/runtimes/neurun/src/model/operand/Shape.h
index 3ae970e85..b80f647d5 100644
--- a/runtimes/neurun/src/graph/operand/Shape.h
+++ b/runtimes/neurun/src/model/operand/Shape.h
@@ -14,18 +14,20 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERAND_SHAPE_H__
-#define __NEURUN_GRAPH_OPERAND_SHAPE_H__
+#ifndef __NEURUN_MODEL_OPERAND_SHAPE_H__
+#define __NEURUN_MODEL_OPERAND_SHAPE_H__
#include <vector>
#include <cstdint>
-#include "util/feature/Shape.h"
-#include "util/kernel/Shape.h"
+#include "misc/feature/Shape.h"
+#include "misc/kernel/Shape.h"
+#include "misc/matrix/Shape.h"
+#include "misc/tensor/Shape.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -33,7 +35,7 @@ namespace operand
struct Shape
{
public:
- Shape(uint32_t rank);
+ Shape(uint32_t rank = 0);
public:
uint32_t rank(void) const { return _dims.size(); }
@@ -45,15 +47,17 @@ public:
public:
int32_t asVector(void) const;
- nnfw::util::feature::Shape asFeature(void) const;
- nnfw::util::kernel::Shape asKernel(void) const;
+ nnfw::misc::matrix::Shape asMatrix(void) const;
+ nnfw::misc::feature::Shape asFeature(void) const;
+ nnfw::misc::kernel::Shape asKernel(void) const;
+ nnfw::misc::tensor::Shape asTensor(void) const;
private:
std::vector<int32_t> _dims;
};
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERAND_SHAPE_H__
+#endif // __NEURUN_MODEL_OPERAND_SHAPE_H__
diff --git a/runtimes/neurun/src/graph/operand/TypeInfo.cc b/runtimes/neurun/src/model/operand/TypeInfo.cc
index 5642b1e8f..0b9f63c93 100644
--- a/runtimes/neurun/src/graph/operand/TypeInfo.cc
+++ b/runtimes/neurun/src/model/operand/TypeInfo.cc
@@ -18,18 +18,18 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
DataType TypeInfo::typeFromOperandCode(OperandCode type)
{
- // Now neurun::graph::operand::DataType share same enum value with OperandCode
+ // Now neurun::model::operand::DataType share same enum value with OperandCode
// in NeuralNetworks.h.
return static_cast<DataType>(static_cast<uint32_t>(type));
}
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operand/TypeInfo.h b/runtimes/neurun/src/model/operand/TypeInfo.h
index 41f4453e5..d16172a09 100644
--- a/runtimes/neurun/src/graph/operand/TypeInfo.h
+++ b/runtimes/neurun/src/model/operand/TypeInfo.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERAND_TYPEINFO_H__
-#define __NEURUN_GRAPH_OPERAND_TYPEINFO_H__
+#ifndef __NEURUN_MODEL_OPERAND_TYPEINFO_H__
+#define __NEURUN_MODEL_OPERAND_TYPEINFO_H__
#include <cstdint>
@@ -25,7 +25,7 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operand
{
@@ -33,6 +33,8 @@ namespace operand
class TypeInfo
{
public:
+ TypeInfo() = default;
+
TypeInfo(OperandCode type, float scale, int32_t offset)
: _type(typeFromOperandCode(type)), _scale(scale), _offset(offset)
{
@@ -45,7 +47,7 @@ public:
int32_t offset() const { return _offset; }
private:
- // Now neurun::graph::operand::DataType share same enum value with OperandCode
+ // Now neurun::model::operand::DataType share same enum value with OperandCode
// in NeuralNetworks.h.
// If we don't share same value, we must fix this mapping function.
DataType typeFromOperandCode(OperandCode type);
@@ -56,7 +58,7 @@ private:
int32_t _offset;
};
} // namespace operand
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERAND_TYPEINFO_H__
+#endif // __NEURUN_MODEL_OPERAND_TYPEINFO_H__
diff --git a/runtimes/neurun/src/model/operation/AddNode.cc b/runtimes/neurun/src/model/operation/AddNode.cc
new file mode 100644
index 000000000..0c9d4e09b
--- /dev/null
+++ b/runtimes/neurun/src/model/operation/AddNode.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 "AddNode.h"
+
+#include <cassert>
+
+#include "NodeVisitor.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operation
+{
+
+void AddNode::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+AddNode::AddNode(const model::operation::Node::InitParam &init_param)
+ : model::operation::Node{OperandConstraint::createExact(2u)}
+{
+ assert(init_param.input_count == 2);
+ assert(init_param.output_count == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Lefthand side operand
+ // 1 -> Righthand side operand
+
+ setInputs({init_param.inputs[0], init_param.inputs[1]});
+ setOutputs({init_param.outputs[0]});
+}
+
+} // namespace operation
+} // namespace model
+} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/Reshape.h b/runtimes/neurun/src/model/operation/AddNode.h
index 168719b46..533fb0ab3 100644
--- a/runtimes/neurun/src/graph/operation/Reshape.h
+++ b/runtimes/neurun/src/model/operation/AddNode.h
@@ -14,38 +14,41 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_RESHAPE_H__
-#define __NEURUN_GRAPH_OPERATION_RESHAPE_H__
+#ifndef __NEURUN_MODEL_OPERATION_ADD_NODE_H__
+#define __NEURUN_MODEL_OPERATION_ADD_NODE_H__
-#include <memory>
-
-#include "graph/operation/Node.h"
+#include "model/operation/Node.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace Reshape
-{
-class Node : public graph::operation::Node
+class AddNode : public model::operation::Node
{
public:
- virtual void accept(NodeVisitor &&) const override;
+ AddNode(const model::operation::Node::InitParam &init_param);
-public:
- Node(const graph::operation::Node::InitParam &init_param);
+ enum Input
+ {
+ LHS = 0,
+ RHS
+ };
+
+ struct Param
+ {
+ operand::Index activation_index;
+ };
public:
- virtual void setInputs(const operand::IndexSet &indexes) override;
- virtual void setOutputs(const operand::IndexSet &indexes) override;
+ virtual void accept(NodeVisitor &&) const override;
+ virtual std::string getName() const override { return "Add"; }
};
-} // namespace Reshape
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_RESHAPE_H__
+#endif // __NEURUN_MODEL_OPERATION_ADD_H__
diff --git a/runtimes/neurun/src/graph/operation/AvgPool2D.cc b/runtimes/neurun/src/model/operation/AvgPool2DNode.cc
index b2612c6b5..8c688e60a 100644
--- a/runtimes/neurun/src/graph/operation/AvgPool2D.cc
+++ b/runtimes/neurun/src/model/operation/AvgPool2DNode.cc
@@ -14,27 +14,23 @@
* limitations under the License.
*/
-#include "AvgPool2D.h"
+#include "AvgPool2DNode.h"
#include <cassert>
#include "NodeVisitor.h"
-#include "LowerInfo.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace AvgPool2D
-{
-namespace Implicit
-{
-void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+void AvgPool2DNode::accept(NodeVisitor &&v) const { v.visit(*this); }
-Node::Node(const graph::operation::Node::InitParam &init_param)
+AvgPool2DNode::AvgPool2DNode(const model::operation::Node::InitParam &init_param)
+ : model::operation::Node{OperandConstraint::createExact(1u)}
{
assert(init_param.input_count == 7);
assert(init_param.output_count == 1);
@@ -52,31 +48,15 @@ Node::Node(const graph::operation::Node::InitParam &init_param)
setInputs({init_param.inputs[0]});
setOutputs({init_param.outputs[0]});
- _param.padding_index = init_param.inputs[1];
- _param.hstride_index = init_param.inputs[2];
- _param.vstride_index = init_param.inputs[3];
-
- _param.kw_index = init_param.inputs[4];
- _param.kh_index = init_param.inputs[5];
- _param.activation_index = init_param.inputs[6];
-}
-
-void Node::setInputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setInputs(indexes);
-}
-
-void Node::setOutputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
+ _param.padding_index = operand::Index{init_param.inputs[1]};
+ _param.hstride_index = operand::Index{init_param.inputs[2]};
+ _param.vstride_index = operand::Index{init_param.inputs[3]};
- graph::operation::Node::setOutputs(indexes);
+ _param.kw_index = operand::Index{init_param.inputs[4]};
+ _param.kh_index = operand::Index{init_param.inputs[5]};
+ _param.activation_index = operand::Index{init_param.inputs[6]};
}
-} // namespace Implicit
-} // namespace AvgPool2D
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/MaxPool2D.h b/runtimes/neurun/src/model/operation/AvgPool2DNode.h
index 30f9b0b50..e66e6146e 100644
--- a/runtimes/neurun/src/graph/operation/MaxPool2D.h
+++ b/runtimes/neurun/src/model/operation/AvgPool2DNode.h
@@ -14,47 +14,45 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_MAXPOOL2D_H__
-#define __NEURUN_GRAPH_OPERATION_MAXPOOL2D_H__
+#ifndef __NEURUN_MODEL_OPERATION_AVGPOOL2D_NODE_H__
+#define __NEURUN_MODEL_OPERATION_AVGPOOL2D_NODE_H__
#include <memory>
-#include "graph/operation/Node.h"
+#include "model/operation/Node.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace MaxPool2D
-{
-namespace Implicit
-{
-struct Param
+class AvgPool2DNode : public model::operation::Node
{
- int32_t kw_index;
- int32_t kh_index;
+public:
+ AvgPool2DNode(const model::operation::Node::InitParam &init_param);
- int32_t hstride_index;
- int32_t vstride_index;
+ enum Input
+ {
+ INPUT = 0
+ };
- int32_t padding_index;
- int32_t activation_index;
-};
+ struct Param
+ {
+ operand::Index kw_index;
+ operand::Index kh_index;
-class Node : public graph::operation::Node
-{
-public:
- virtual void accept(NodeVisitor &&) const override;
+ operand::Index hstride_index;
+ operand::Index vstride_index;
-public:
- Node(const graph::operation::Node::InitParam &init_param);
+ operand::Index padding_index;
+ operand::Index activation_index;
+ };
public:
- virtual void setInputs(const operand::IndexSet &indexes) override;
- virtual void setOutputs(const operand::IndexSet &indexes) override;
+ virtual void accept(NodeVisitor &&) const override;
+ virtual std::string getName() const override { return "AvgPool2D"; }
public:
const Param &param() const { return _param; }
@@ -63,10 +61,8 @@ private:
Param _param;
};
-} // namespace Implicit
-} // namespace MaxPool2D
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_MAXPOOL2D_H__
+#endif // __NEURUN_MODEL_OPERATION_AVGPOOL2D_H__
diff --git a/runtimes/neurun/src/graph/operation/Concat.cc b/runtimes/neurun/src/model/operation/ConcatNode.cc
index 952cf687c..23cfef294 100644
--- a/runtimes/neurun/src/graph/operation/Concat.cc
+++ b/runtimes/neurun/src/model/operation/ConcatNode.cc
@@ -14,27 +14,25 @@
* limitations under the License.
*/
-#include "Concat.h"
+#include "ConcatNode.h"
#include <cassert>
#include "NodeVisitor.h"
-#include "LowerInfo.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace Concat
-{
-void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+void ConcatNode::accept(NodeVisitor &&v) const { v.visit(*this); }
-Node::Node(const graph::operation::Node::InitParam &init_param)
+ConcatNode::ConcatNode(const model::operation::Node::InitParam &init_param)
+ : model::operation::Node{OperandConstraint::createAtLeast(2u)}
{
- assert(init_param.input_count > 2); // At least one one input tensor and axis
+ 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:
@@ -53,17 +51,9 @@ Node::Node(const graph::operation::Node::InitParam &init_param)
}
setOutputs({init_param.outputs[0]});
- _param.axis_index = init_param.inputs[init_param.input_count - 1];
-}
-
-void Node::setOutputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setOutputs(indexes);
+ _param.axis_index = operand::Index{init_param.inputs[init_param.input_count - 1]};
}
-} // namespace Concat
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/Concat.h b/runtimes/neurun/src/model/operation/ConcatNode.h
index dab17d031..b69ee2f23 100644
--- a/runtimes/neurun/src/graph/operation/Concat.h
+++ b/runtimes/neurun/src/model/operation/ConcatNode.h
@@ -14,37 +14,33 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_CONCAT_H__
-#define __NEURUN_GRAPH_OPERATION_CONCAT_H__
+#ifndef __NEURUN_MODEL_OPERATION_CONCAT_NODE_H__
+#define __NEURUN_MODEL_OPERATION_CONCAT_NODE_H__
#include <memory>
-#include "graph/operation/Node.h"
+#include "model/operation/Node.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace Concat
-{
-
-struct Param
-{
- int32_t axis_index;
-};
-class Node : public graph::operation::Node
+class ConcatNode : public model::operation::Node
{
public:
- Node(const graph::operation::Node::InitParam &init_param);
+ ConcatNode(const model::operation::Node::InitParam &init_param);
-public:
- virtual void accept(NodeVisitor &&) const override;
+ struct Param
+ {
+ operand::Index axis_index;
+ };
public:
- virtual void setOutputs(const operand::IndexSet &indexes) override;
+ virtual void accept(NodeVisitor &&) const override;
+ virtual std::string getName() const override { return "Concat"; }
public:
const Param &param() const { return _param; }
@@ -53,9 +49,8 @@ private:
Param _param;
};
-} // namespace Concat
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_CONCAT_H__
+#endif // __NEURUN_MODEL_OPERATION_CONCAT_H__
diff --git a/runtimes/neurun/src/graph/operation/Conv2D.cc b/runtimes/neurun/src/model/operation/Conv2DNode.cc
index f88955db1..7eb2b183d 100644
--- a/runtimes/neurun/src/graph/operation/Conv2D.cc
+++ b/runtimes/neurun/src/model/operation/Conv2DNode.cc
@@ -14,27 +14,23 @@
* limitations under the License.
*/
-#include "Conv2D.h"
+#include "Conv2DNode.h"
#include <cassert>
#include "NodeVisitor.h"
-#include "LowerInfo.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace Conv2D
-{
-namespace Implicit
-{
-void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+void Conv2DNode::accept(NodeVisitor &&v) const { v.visit(*this); }
-Node::Node(const graph::operation::Node::InitParam &init_param)
+Conv2DNode::Conv2DNode(const model::operation::Node::InitParam &init_param)
+ : model::operation::Node{OperandConstraint::createExact(3u)}
{
assert(init_param.input_count == 7 && init_param.output_count == 1);
@@ -52,28 +48,12 @@ Node::Node(const graph::operation::Node::InitParam &init_param)
setInputs({init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]});
setOutputs({init_param.outputs[0]});
- _param.padding_index = init_param.inputs[3];
- _param.hstride_index = init_param.inputs[4];
- _param.vstride_index = init_param.inputs[5];
- _param.activation_index = init_param.inputs[6];
-}
-
-void Node::setInputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 3);
-
- graph::operation::Node::setInputs(indexes);
-}
-
-void Node::setOutputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setOutputs(indexes);
+ _param.padding_index = operand::Index{init_param.inputs[3]};
+ _param.hstride_index = operand::Index{init_param.inputs[4]};
+ _param.vstride_index = operand::Index{init_param.inputs[5]};
+ _param.activation_index = operand::Index{init_param.inputs[6]};
}
-} // namespace Implicit
-} // namespace Conv2D
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/Conv2D.h b/runtimes/neurun/src/model/operation/Conv2DNode.h
index f75058a30..34a95f0d9 100644
--- a/runtimes/neurun/src/graph/operation/Conv2D.h
+++ b/runtimes/neurun/src/model/operation/Conv2DNode.h
@@ -14,44 +14,44 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_CONV2D_H__
-#define __NEURUN_GRAPH_OPERATION_CONV2D_H__
+#ifndef __NEURUN_MODEL_OPERATION_CONV2D_NODE_H__
+#define __NEURUN_MODEL_OPERATION_CONV2D_NODE_H__
#include <memory>
-#include "graph/operation/Node.h"
+#include "model/operation/Node.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace Conv2D
-{
-namespace Implicit
-{
-struct Param
+class Conv2DNode : public model::operation::Node
{
- int32_t hstride_index;
- int32_t vstride_index;
+public:
+ Conv2DNode(const model::operation::Node::InitParam &);
- int32_t padding_index;
- int32_t activation_index;
-};
+ enum Input
+ {
+ INPUT = 0,
+ KERNEL,
+ BIAS
+ };
-class Node : public graph::operation::Node
-{
-public:
- Node(const graph::operation::Node::InitParam &);
+ struct Param
+ {
+ operand::Index hstride_index;
+ operand::Index vstride_index;
-public:
- virtual void accept(NodeVisitor &&) const override;
+ operand::Index padding_index;
+ operand::Index activation_index;
+ };
public:
- virtual void setInputs(const operand::IndexSet &indexes) override;
- virtual void setOutputs(const operand::IndexSet &indexes) override;
+ virtual void accept(NodeVisitor &&) const override;
+ virtual std::string getName() const override { return "Conv2D"; }
public:
const Param &param() const { return _param; }
@@ -60,10 +60,8 @@ private:
Param _param;
};
-} // namespace Implicit
-} // namespace Conv2D
-} // namespace coperation
-} // namespace graph
+} // namespace operation
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_CONV2D_H__
+#endif // __NEURUN_MODEL_OPERATION_CONV2D_NODE_H__
diff --git a/runtimes/neurun/src/graph/operation/FullyConnected.cc b/runtimes/neurun/src/model/operation/FullyConnectedNode.cc
index 0a6553d1e..0fde5182d 100644
--- a/runtimes/neurun/src/graph/operation/FullyConnected.cc
+++ b/runtimes/neurun/src/model/operation/FullyConnectedNode.cc
@@ -14,25 +14,23 @@
* limitations under the License.
*/
-#include "FullyConnected.h"
+#include "FullyConnectedNode.h"
#include <cassert>
#include "NodeVisitor.h"
-#include "LowerInfo.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace FullyConnected
-{
-void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+void FullyConnectedNode::accept(NodeVisitor &&v) const { v.visit(*this); }
-Node::Node(const graph::operation::Node::InitParam &init_param)
+FullyConnectedNode::FullyConnectedNode(const model::operation::Node::InitParam &init_param)
+ : model::operation::Node{OperandConstraint::createExact(3u)}
{
assert(init_param.input_count == 4 && init_param.output_count == 1);
@@ -46,24 +44,9 @@ Node::Node(const graph::operation::Node::InitParam &init_param)
setInputs({init_param.inputs[0], init_param.inputs[1], init_param.inputs[2]});
setOutputs({init_param.outputs[0]});
- _param.activation_index = init_param.inputs[3];
-}
-
-void Node::setInputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 3);
-
- graph::operation::Node::setInputs(indexes);
-}
-
-void Node::setOutputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setOutputs(indexes);
+ _param.activation_index = operand::Index{init_param.inputs[3]};
}
-} // namespace FullyConnected
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/FullyConnected.h b/runtimes/neurun/src/model/operation/FullyConnectedNode.h
index a1f920e4b..9820ddc8c 100644
--- a/runtimes/neurun/src/graph/operation/FullyConnected.h
+++ b/runtimes/neurun/src/model/operation/FullyConnectedNode.h
@@ -14,38 +14,40 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_FULLYCONNECTED_H__
-#define __NEURUN_GRAPH_OPERATION_FULLYCONNECTED_H__
+#ifndef __NEURUN_MODEL_OPERATION_FULLYCONNECTED_NODE_H__
+#define __NEURUN_MODEL_OPERATION_FULLYCONNECTED_NODE_H__
#include <memory>
-#include "graph/operation/Node.h"
+#include "model/operation/Node.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace FullyConnected
-{
-
-struct Param
-{
- int32_t activation_index;
-};
-class Node : public graph::operation::Node
+class FullyConnectedNode : public model::operation::Node
{
public:
- Node(const graph::operation::Node::InitParam &init_param);
+ FullyConnectedNode(const model::operation::Node::InitParam &init_param);
-public:
- virtual void accept(NodeVisitor &&) const override;
+ enum Input
+ {
+ INPUT = 0,
+ WEIGHT,
+ BIAS
+ };
+
+ struct Param
+ {
+ operand::Index activation_index;
+ };
public:
- virtual void setInputs(const operand::IndexSet &indexes) override;
- virtual void setOutputs(const operand::IndexSet &indexes) override;
+ virtual void accept(NodeVisitor &&) const override;
+ virtual std::string getName() const override { return "FullyConnected"; }
public:
const Param &param() const { return _param; }
@@ -54,9 +56,8 @@ private:
Param _param;
};
-} // namespace FullyConnected
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_FULLYCONNECTED_H__
+#endif // __NEURUN_MODEL_OPERATION_FULLYCONNECTED_NODE_H__
diff --git a/runtimes/neurun/src/graph/operation/Index.h b/runtimes/neurun/src/model/operation/Index.h
index 3902d039b..e03dd74d6 100644
--- a/runtimes/neurun/src/graph/operation/Index.h
+++ b/runtimes/neurun/src/model/operation/Index.h
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_INDEX_H__
-#define __NEURUN_GRAPH_OPERATION_INDEX_H__
+#ifndef __NEURUN_MODEL_OPERATION_INDEX_H__
+#define __NEURUN_MODEL_OPERATION_INDEX_H__
#include "graph/Index.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
@@ -29,7 +29,7 @@ namespace operation
using Index = ::neurun::graph::Index<uint32_t, struct IndexTag>;
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_INDEX_H__
+#endif // __NEURUN_MODEL_OPERATION_INDEX_H__
diff --git a/runtimes/neurun/src/graph/operation/IndexList.cc b/runtimes/neurun/src/model/operation/IndexList.cc
index cdc5997ea..e46987036 100644
--- a/runtimes/neurun/src/graph/operation/IndexList.cc
+++ b/runtimes/neurun/src/model/operation/IndexList.cc
@@ -20,7 +20,7 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
@@ -30,11 +30,11 @@ IndexList::IndexList(std::initializer_list<Index> list) : _list(list)
// DO NOTHING
}
-bool IndexList::contains(const ::neurun::graph::operation::Index &index) const
+bool IndexList::contains(const ::neurun::model::operation::Index &index) const
{
return std::find(_list.begin(), _list.end(), index) != _list.end();
}
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/IndexList.h b/runtimes/neurun/src/model/operation/IndexList.h
index cfac46abc..c0af29829 100644
--- a/runtimes/neurun/src/graph/operation/IndexList.h
+++ b/runtimes/neurun/src/model/operation/IndexList.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_INDEX_LIST_H__
-#define __NEURUN_GRAPH_OPERATION_INDEX_LIST_H__
+#ifndef __NEURUN_MODEL_OPERATION_INDEX_LIST_H__
+#define __NEURUN_MODEL_OPERATION_INDEX_LIST_H__
#include <initializer_list>
#include <list>
@@ -24,7 +24,7 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
@@ -49,7 +49,7 @@ private:
};
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_INDEX_LIST_H__
+#endif // __NEURUN_MODEL_OPERATION_INDEX_LIST_H__
diff --git a/runtimes/neurun/src/graph/operation/MaxPool2D.cc b/runtimes/neurun/src/model/operation/MaxPool2DNode.cc
index 76648baf6..3d3686b0e 100644
--- a/runtimes/neurun/src/graph/operation/MaxPool2D.cc
+++ b/runtimes/neurun/src/model/operation/MaxPool2DNode.cc
@@ -14,27 +14,23 @@
* limitations under the License.
*/
-#include "MaxPool2D.h"
+#include "MaxPool2DNode.h"
#include <cassert>
#include "NodeVisitor.h"
-#include "LowerInfo.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace MaxPool2D
-{
-namespace Implicit
-{
-void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+void MaxPool2DNode::accept(NodeVisitor &&v) const { v.visit(*this); }
-Node::Node(const graph::operation::Node::InitParam &init_param)
+MaxPool2DNode::MaxPool2DNode(const model::operation::Node::InitParam &init_param)
+ : model::operation::Node{OperandConstraint::createExact(1u)}
{
assert(init_param.input_count == 7);
assert(init_param.output_count == 1);
@@ -52,31 +48,15 @@ Node::Node(const graph::operation::Node::InitParam &init_param)
setInputs({init_param.inputs[0]});
setOutputs({init_param.outputs[0]});
- _param.padding_index = init_param.inputs[1];
- _param.hstride_index = init_param.inputs[2];
- _param.vstride_index = init_param.inputs[3];
-
- _param.kw_index = init_param.inputs[4];
- _param.kh_index = init_param.inputs[5];
- _param.activation_index = init_param.inputs[6];
-}
-
-void Node::setInputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setInputs(indexes);
-}
-
-void Node::setOutputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
+ _param.padding_index = operand::Index{init_param.inputs[1]};
+ _param.hstride_index = operand::Index{init_param.inputs[2]};
+ _param.vstride_index = operand::Index{init_param.inputs[3]};
- graph::operation::Node::setOutputs(indexes);
+ _param.kw_index = operand::Index{init_param.inputs[4]};
+ _param.kh_index = operand::Index{init_param.inputs[5]};
+ _param.activation_index = operand::Index{init_param.inputs[6]};
}
-} // namespace Implicit
-} // namespace MaxPool2D
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/model/operation/MaxPool2DNode.h b/runtimes/neurun/src/model/operation/MaxPool2DNode.h
new file mode 100644
index 000000000..96d1210a7
--- /dev/null
+++ b/runtimes/neurun/src/model/operation/MaxPool2DNode.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 __NEURUN_MODEL_OPERATION_MAXPOOL2D_NODE_H__
+#define __NEURUN_MODEL_OPERATION_MAXPOOL2D_NODE_H__
+
+#include <memory>
+
+#include "model/operation/Node.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operation
+{
+
+class MaxPool2DNode : public model::operation::Node
+{
+public:
+ MaxPool2DNode(const model::operation::Node::InitParam &init_param);
+
+ enum Input
+ {
+ INPUT = 0
+ };
+
+ struct Param
+ {
+ operand::Index kw_index;
+ operand::Index kh_index;
+
+ operand::Index hstride_index;
+ operand::Index vstride_index;
+
+ operand::Index padding_index;
+ operand::Index activation_index;
+ };
+
+public:
+ virtual void accept(NodeVisitor &&) const override;
+ virtual std::string getName() const override { return "MaxPool2D"; }
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace model
+} // namespace neurun
+
+#endif // __NEURUN_MODEL_OPERATION_MAXPOOL2D_NODE_H__
diff --git a/runtimes/neurun/src/model/operation/Node.Include.h b/runtimes/neurun/src/model/operation/Node.Include.h
new file mode 100644
index 000000000..95e78c7b5
--- /dev/null
+++ b/runtimes/neurun/src/model/operation/Node.Include.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.
+ */
+
+// This file has no ifdef guard intentionally
+
+#include "Conv2DNode.h"
+#include "MaxPool2DNode.h"
+#include "AvgPool2DNode.h"
+#include "ConcatNode.h"
+#include "ReshapeNode.h"
+#include "FullyConnectedNode.h"
+#include "SoftmaxNode.h"
+#include "PermuteNode.h"
+#include "AddNode.h"
diff --git a/runtimes/neurun/src/model/operation/Node.cc b/runtimes/neurun/src/model/operation/Node.cc
new file mode 100644
index 000000000..76397afde
--- /dev/null
+++ b/runtimes/neurun/src/model/operation/Node.cc
@@ -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.
+ */
+
+#include "Node.h"
+
+#include <cassert>
+
+#include "graph/operation/LowerInfo.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operation
+{
+
+Node::Node(OperandConstraint input_constr) : _input_constr{input_constr} {}
+
+Node::~Node() = default;
+
+void Node::setInputs(const operand::IndexSet &indexes)
+{
+ assert(_input_constr.check(indexes.size()));
+ _inputs = indexes;
+}
+
+void Node::setOutputs(const operand::IndexSet &indexes) { _outputs = indexes; }
+
+void Node::replaceInput(const operand::Index &from, const operand::Index &to)
+{
+ _inputs.replace(from, to);
+}
+
+void Node::replaceOutput(const operand::Index &from, const operand::Index &to)
+{
+ _outputs.replace(from, to);
+}
+
+} // namespace operation
+} // namespace model
+} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/Node.h b/runtimes/neurun/src/model/operation/Node.h
index 9e98184e3..76f0d2d00 100644
--- a/runtimes/neurun/src/graph/operation/Node.h
+++ b/runtimes/neurun/src/model/operation/Node.h
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_NODE_H__
-#define __NEURUN_GRAPH_OPERATION_NODE_H__
+#ifndef __NEURUN_MODEL_OPERATION_NODE_H__
+#define __NEURUN_MODEL_OPERATION_NODE_H__
#include <memory>
-#include "graph/operand/IndexSet.h"
+#include "model/operand/Object.h"
+#include "model/operand/IndexSet.h"
+#include "OperandConstraint.h"
namespace neurun
{
@@ -27,8 +29,18 @@ namespace graph
{
namespace operation
{
-
class LowerInfo;
+} // namespace operation
+} // namespace graph
+} // namespace neurun
+
+namespace neurun
+{
+namespace model
+{
+namespace operation
+{
+
struct NodeVisitor;
class Node
@@ -43,31 +55,30 @@ public:
};
public:
- Node();
+ Node(OperandConstraint input_constr);
virtual ~Node();
public:
virtual void accept(NodeVisitor &&) const = 0;
+ virtual std::string getName() const = 0;
public:
- virtual const operand::IndexSet &getInputs() const { return _inputs; }
- virtual const operand::IndexSet &getOutputs() const { return _outputs; }
+ void replaceInput(const operand::Index &from, const operand::Index &to);
+ void replaceOutput(const operand::Index &from, const operand::Index &to);
+ const operand::IndexSet &getInputs() const { return _inputs; }
+ const operand::IndexSet &getOutputs() const { return _outputs; }
// It's for only input/output tensors but const data.
- virtual void setInputs(const operand::IndexSet &indexes) { _inputs = indexes; }
- virtual void setOutputs(const operand::IndexSet &indexes) { _outputs = indexes; }
-
-public:
- void lower_info(std::unique_ptr<LowerInfo> &&lower_info);
- const LowerInfo *lower_info() const;
+ void setInputs(const operand::IndexSet &indexes);
+ void setOutputs(const operand::IndexSet &indexes);
private:
operand::IndexSet _inputs;
operand::IndexSet _outputs;
- std::unique_ptr<LowerInfo> _lower_info;
+ OperandConstraint _input_constr;
};
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_NODE_H__
+#endif // __NEURUN_MODEL_OPERATION_NODE_H__
diff --git a/runtimes/neurun/src/model/operation/NodeVisitor.h b/runtimes/neurun/src/model/operation/NodeVisitor.h
new file mode 100644
index 000000000..8420de998
--- /dev/null
+++ b/runtimes/neurun/src/model/operation/NodeVisitor.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 __NEURUN_MODEL_OPERATION_NODE_VISITOR_H__
+#define __NEURUN_MODEL_OPERATION_NODE_VISITOR_H__
+
+#include "Node.Include.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operation
+{
+
+struct NodeVisitor
+{
+ virtual ~NodeVisitor() = default;
+
+#define OP(InternalName, IsNnApi, NnApiName) \
+ virtual void visit(const InternalName &) {}
+#include "model/operation/Op.lst"
+#undef OP
+};
+
+} // namespace operation
+} // namespace model
+} // namespace neurun
+
+#endif // __NEURUN_MODEL_OPERATION_NODE_VISITOR_H__
diff --git a/runtimes/neurun/src/graph/operation/Op.lst b/runtimes/neurun/src/model/operation/Op.lst
index 23b4123cb..23f4b5118 100644
--- a/runtimes/neurun/src/graph/operation/Op.lst
+++ b/runtimes/neurun/src/model/operation/Op.lst
@@ -20,11 +20,13 @@
// NOTE The relation between "Internal Name" and "NN API Name" is "1 : N".
-// Internal Name | NN API Name
-OP(Conv2D::Implicit , CONV_2D)
-OP(AvgPool2D::Implicit , AVERAGE_POOL_2D)
-OP(MaxPool2D::Implicit , MAX_POOL_2D)
-OP(Concat , CONCATENATION)
-OP(FullyConnected , FULLY_CONNECTED)
-OP(Reshape , RESHAPE)
-OP(Softmax , SOFTMAX)
+// Internal Name | NN API? | NN API Name
+OP(AddNode , true , ADD)
+OP(Conv2DNode , true , CONV_2D)
+OP(AvgPool2DNode , true , AVERAGE_POOL_2D)
+OP(MaxPool2DNode , true , MAX_POOL_2D)
+OP(ConcatNode , true , CONCATENATION)
+OP(FullyConnectedNode , true , FULLY_CONNECTED)
+OP(ReshapeNode , true , RESHAPE)
+OP(SoftmaxNode , true , SOFTMAX)
+OP(PermuteNode , false , NOT_AVAILABLE)
diff --git a/runtimes/neurun/src/model/operation/OperandConstraint.cc b/runtimes/neurun/src/model/operation/OperandConstraint.cc
new file mode 100644
index 000000000..5c69de928
--- /dev/null
+++ b/runtimes/neurun/src/model/operation/OperandConstraint.cc
@@ -0,0 +1,28 @@
+/*
+ * 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 "OperandConstraint.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operation
+{
+
+} // namespace operation
+} // namespace model
+} // namespace neurun
diff --git a/runtimes/neurun/src/model/operation/OperandConstraint.h b/runtimes/neurun/src/model/operation/OperandConstraint.h
new file mode 100644
index 000000000..d1cd8aa2c
--- /dev/null
+++ b/runtimes/neurun/src/model/operation/OperandConstraint.h
@@ -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.
+ */
+
+#ifndef __NEURUN_MODEL_OPERATION_OPERAND_CONSTRAINT_H__
+#define __NEURUN_MODEL_OPERATION_OPERAND_CONSTRAINT_H__
+
+#include <stdint.h>
+#include <limits>
+#include <set>
+
+namespace neurun
+{
+namespace model
+{
+namespace operation
+{
+
+class OperandConstraint
+{
+private:
+ static const uint32_t INF = std::numeric_limits<uint32_t>::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 operation
+} // namespace model
+} // namespace neurun
+
+#endif // __NEURUN_MODEL_OPERATION_OPERAND_CONSTRAINT_H__
diff --git a/runtimes/neurun/src/model/operation/PermuteNode.cc b/runtimes/neurun/src/model/operation/PermuteNode.cc
new file mode 100644
index 000000000..174d2a86b
--- /dev/null
+++ b/runtimes/neurun/src/model/operation/PermuteNode.cc
@@ -0,0 +1,41 @@
+/*
+ * 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 "PermuteNode.h"
+
+#include <cassert>
+
+#include "NodeVisitor.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operation
+{
+
+void PermuteNode::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+PermuteNode::PermuteNode(const operand::Index &input, const operand::Index &output, Type type)
+ : model::operation::Node{OperandConstraint::createExact(1u)}, _param{type}
+{
+ setInputs({input});
+ setOutputs({output});
+}
+
+} // namespace operation
+} // namespace model
+} // namespace neurun
diff --git a/runtimes/neurun/src/model/operation/PermuteNode.h b/runtimes/neurun/src/model/operation/PermuteNode.h
new file mode 100644
index 000000000..b589975be
--- /dev/null
+++ b/runtimes/neurun/src/model/operation/PermuteNode.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 __NEURUN_MODEL_OPERATION_PERMUTE_NODE_H__
+#define __NEURUN_MODEL_OPERATION_PERMUTE_NODE_H__
+
+#include "model/operation/Node.h"
+
+namespace neurun
+{
+namespace model
+{
+namespace operation
+{
+
+class PermuteNode : public model::operation::Node
+{
+public:
+ enum class Type
+ {
+ NHWC_TO_NCHW,
+ NCHW_TO_NHWC,
+ COPY
+ };
+
+ struct Param
+ {
+ Type type;
+ };
+
+public:
+ virtual void accept(NodeVisitor &&) const override;
+ virtual std::string getName() const override { return "Permute"; }
+
+public:
+ PermuteNode(const operand::Index &input, const operand::Index &output, Type type);
+
+public:
+ const Param &param() const { return _param; }
+
+private:
+ Param _param;
+};
+
+} // namespace operation
+} // namespace model
+} // namespace neurun
+
+#endif // __NEURUN_MODEL_OPERATION_PERMUTE_NODE_H__
diff --git a/runtimes/neurun/src/graph/operation/Reshape.cc b/runtimes/neurun/src/model/operation/ReshapeNode.cc
index e6bc2117f..616b8cd65 100644
--- a/runtimes/neurun/src/graph/operation/Reshape.cc
+++ b/runtimes/neurun/src/model/operation/ReshapeNode.cc
@@ -14,25 +14,23 @@
* limitations under the License.
*/
-#include "Reshape.h"
+#include "ReshapeNode.h"
#include <cassert>
#include "NodeVisitor.h"
-#include "LowerInfo.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace Reshape
-{
-void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+void ReshapeNode::accept(NodeVisitor &&v) const { v.visit(*this); }
-Node::Node(const graph::operation::Node::InitParam &init_param)
+ReshapeNode::ReshapeNode(const model::operation::Node::InitParam &init_param)
+ : model::operation::Node{OperandConstraint::createExact(1u)}
{
assert(init_param.input_count == 2 && init_param.output_count == 1);
@@ -47,21 +45,6 @@ Node::Node(const graph::operation::Node::InitParam &init_param)
setOutputs({init_param.outputs[0]});
}
-void Node::setInputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1); // TODO Should be 2 (See also the constructor)
-
- graph::operation::Node::setInputs(indexes);
-}
-
-void Node::setOutputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setOutputs(indexes);
-}
-
-} // namespace Reshape
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/NOP.h b/runtimes/neurun/src/model/operation/ReshapeNode.h
index 51b0f6f71..1758e9ec8 100644
--- a/runtimes/neurun/src/graph/operation/NOP.h
+++ b/runtimes/neurun/src/model/operation/ReshapeNode.h
@@ -14,34 +14,37 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_NOP_H__
-#define __NEURUN_GRAPH_OPERATION_NOP_H__
+#ifndef __NEURUN_MODEL_OPERATION_RESHAPE_NODE_H__
+#define __NEURUN_MODEL_OPERATION_RESHAPE_NODE_H__
#include <memory>
-#include "graph/operation/Node.h"
+#include "model/operation/Node.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace NOP
-{
-class Node : public graph::operation::Node
+class ReshapeNode : public model::operation::Node
{
public:
- Node(const graph::operation::Node::InitParam &) {}
+ ReshapeNode(const model::operation::Node::InitParam &init_param);
+
+ enum Input
+ {
+ INPUT = 0
+ };
public:
virtual void accept(NodeVisitor &&) const override;
+ virtual std::string getName() const override { return "Reshape"; }
};
-} // namespace NOP
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_NOP_H__
+#endif // __NEURUN_MODEL_OPERATION_RESHAPE_NODE_H__
diff --git a/runtimes/neurun/src/graph/operation/Set.cc b/runtimes/neurun/src/model/operation/Set.cc
index a1ddfa6d4..14bd4f584 100644
--- a/runtimes/neurun/src/graph/operation/Set.cc
+++ b/runtimes/neurun/src/model/operation/Set.cc
@@ -20,7 +20,7 @@
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
@@ -63,5 +63,5 @@ void Set::iterate(const std::function<void(const Index &, Node &)> &fn)
}
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/Set.h b/runtimes/neurun/src/model/operation/Set.h
index bc6913ff4..eebf91e65 100644
--- a/runtimes/neurun/src/graph/operation/Set.h
+++ b/runtimes/neurun/src/model/operation/Set.h
@@ -14,19 +14,19 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_SET_H__
-#define __NEURUN_GRAPH_OPERATION_SET_H__
+#ifndef __NEURUN_MODEL_OPERATION_SET_H__
+#define __NEURUN_MODEL_OPERATION_SET_H__
#include <memory>
-#include "graph/operation/Index.h"
+#include "model/operation/Index.h"
#include "Node.h"
#include <unordered_map>
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
@@ -38,6 +38,7 @@ public:
public:
Index append(std::unique_ptr<Node> &&node);
+ void remove(const Index &index) { _nodes.erase(index); };
public:
const Node &at(const Index &) const;
@@ -56,7 +57,7 @@ private:
};
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_SET_H__
+#endif // __NEURUN_MODEL_OPERATION_SET_H__
diff --git a/runtimes/neurun/src/graph/operation/Softmax.cc b/runtimes/neurun/src/model/operation/SoftmaxNode.cc
index 3b3c8661f..d157aa4a7 100644
--- a/runtimes/neurun/src/graph/operation/Softmax.cc
+++ b/runtimes/neurun/src/model/operation/SoftmaxNode.cc
@@ -14,25 +14,23 @@
* limitations under the License.
*/
-#include "Softmax.h"
+#include "SoftmaxNode.h"
#include <cassert>
#include "NodeVisitor.h"
-#include "LowerInfo.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace Softmax
-{
-void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+void SoftmaxNode::accept(NodeVisitor &&v) const { v.visit(*this); }
-Node::Node(const graph::operation::Node::InitParam &init_param)
+SoftmaxNode::SoftmaxNode(const model::operation::Node::InitParam &init_param)
+ : model::operation::Node{OperandConstraint::createExact(1u)}
{
assert(init_param.input_count == 2 && init_param.output_count == 1);
@@ -44,24 +42,9 @@ Node::Node(const graph::operation::Node::InitParam &init_param)
setInputs({init_param.inputs[0]});
setOutputs({init_param.outputs[0]});
- _param.scale_index = init_param.inputs[1];
-}
-
-void Node::setInputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setInputs(indexes);
-}
-
-void Node::setOutputs(const operand::IndexSet &indexes)
-{
- assert(indexes.size() == 1);
-
- graph::operation::Node::setOutputs(indexes);
+ _param.scale_index = operand::Index{init_param.inputs[1]};
}
-} // namespace Softmax
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
diff --git a/runtimes/neurun/src/graph/operation/Softmax.h b/runtimes/neurun/src/model/operation/SoftmaxNode.h
index e87a27518..4a5a72e5a 100644
--- a/runtimes/neurun/src/graph/operation/Softmax.h
+++ b/runtimes/neurun/src/model/operation/SoftmaxNode.h
@@ -14,38 +14,37 @@
* limitations under the License.
*/
-#ifndef __NEURUN_GRAPH_OPERATION_SOFTMAX_H__
-#define __NEURUN_GRAPH_OPERATION_SOFTMAX_H__
+#ifndef __NEURUN_MODEL_OPERATION_SOFTMAX_NODE_H__
+#define __NEURUN_MODEL_OPERATION_SOFTMAX_NODE_H__
#include <memory>
-#include "graph/operation/Node.h"
+#include "model/operation/Node.h"
namespace neurun
{
-namespace graph
+namespace model
{
namespace operation
{
-namespace Softmax
-{
-
-struct Param
-{
- int32_t scale_index;
-};
-class Node : public graph::operation::Node
+class SoftmaxNode : public model::operation::Node
{
public:
- virtual void accept(NodeVisitor &&) const override;
+ SoftmaxNode(const model::operation::Node::InitParam &init_param);
+ enum Input
+ {
+ INPUT = 0
+ };
-public:
- Node(const graph::operation::Node::InitParam &init_param);
+ struct Param
+ {
+ operand::Index scale_index;
+ };
public:
- virtual void setInputs(const operand::IndexSet &indexes) override;
- virtual void setOutputs(const operand::IndexSet &indexes) override;
+ virtual void accept(NodeVisitor &&) const override;
+ virtual std::string getName() const override { return "SoftMax"; }
public:
const Param &param() const { return _param; }
@@ -54,9 +53,8 @@ private:
Param _param;
};
-} // namespace Softmax
} // namespace operation
-} // namespace graph
+} // namespace model
} // namespace neurun
-#endif // __NEURUN_GRAPH_OPERATION_SOFTMAX_H__
+#endif // __NEURUN_MODEL_OPERATION_SOFTMAX_NODE_H__
diff --git a/runtimes/neurun/src/internal/Padding.cc b/runtimes/neurun/src/util/Padding.cc
index 200fa1a02..a24c9ddf7 100644
--- a/runtimes/neurun/src/internal/Padding.cc
+++ b/runtimes/neurun/src/util/Padding.cc
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-#include "internal/Padding.h"
+#include "util/Padding.h"
#include <algorithm>
-namespace internal
+namespace neurun
+{
+namespace util
{
Padding valid_padding(void)
@@ -42,8 +44,8 @@ Padding valid_padding(void)
return padding;
}
-Padding same_padding(const nnfw::util::feature::Shape &ifm_shape,
- const nnfw::util::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw,
+Padding same_padding(const nnfw::misc::feature::Shape &ifm_shape,
+ const nnfw::misc::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw,
uint32_t kh)
{
Padding padding;
@@ -69,4 +71,5 @@ Padding same_padding(const nnfw::util::feature::Shape &ifm_shape,
return padding;
}
-} // namespace internal
+} // namespace util
+} // namespace neurun
diff --git a/runtimes/neurun/src/internal/Padding.h b/runtimes/neurun/src/util/Padding.h
index 84e081a78..05a14eb31 100644
--- a/runtimes/neurun/src/internal/Padding.h
+++ b/runtimes/neurun/src/util/Padding.h
@@ -14,14 +14,16 @@
* limitations under the License.
*/
-#ifndef __INTERNAL_PADDING_H__
-#define __INTERNAL_PADDING_H__
+#ifndef __NEURUN_UTIL_PADDING_H__
+#define __NEURUN_UTIL_PADDING_H__
#include <stdint.h>
-#include <util/feature/Shape.h>
+#include <misc/feature/Shape.h>
-namespace internal
+namespace neurun
+{
+namespace util
{
struct Padding
@@ -39,10 +41,11 @@ struct Stride
};
Padding valid_padding(void);
-Padding same_padding(const nnfw::util::feature::Shape &ifm_shape,
- const nnfw::util::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw,
+Padding same_padding(const nnfw::misc::feature::Shape &ifm_shape,
+ const nnfw::misc::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw,
uint32_t kh);
-} // namespace internal
+} // namespace util
+} // namespace neurun
-#endif // __INTERNAL_PADDING_H__
+#endif // __NEURUN_UTIL_PADDING_H__
diff --git a/runtimes/neurun/src/util/Utils.cc b/runtimes/neurun/src/util/Utils.cc
new file mode 100644
index 000000000..def02db69
--- /dev/null
+++ b/runtimes/neurun/src/util/Utils.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 "Utils.h"
+
+#include <cassert>
+
+namespace neurun
+{
+namespace util
+{
+
+const char *to_string(const PaddingCode &code)
+{
+ assert((ANEURALNETWORKS_PADDING_SAME == code) || (ANEURALNETWORKS_PADDING_VALID == code));
+
+ switch (code)
+ {
+ case ANEURALNETWORKS_PADDING_SAME:
+ return "ANEURALNETWORKS_PADDING_SAME";
+ case ANEURALNETWORKS_PADDING_VALID:
+ return "ANEURALNETWORKS_PADDING_VALID";
+ }
+
+ return nullptr;
+}
+
+} // namespace util
+} // namespace neurun
diff --git a/runtimes/neurun/src/util/Utils.h b/runtimes/neurun/src/util/Utils.h
new file mode 100644
index 000000000..a1e5bf0ba
--- /dev/null
+++ b/runtimes/neurun/src/util/Utils.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.
+ */
+
+/**
+ * @file Utils.h
+ * @brief This file contains utility functions
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __NEURUN_UTIL_UTILS_H__
+#define __NEURUN_UTIL_UTILS_H__
+
+#include "NeuralNetworks.h"
+
+namespace neurun
+{
+namespace util
+{
+
+/**
+ * @brief Converts a PaddingCode to const char*
+ * @param[in] code The PaddingCode to be converted
+ * @return A string holding the converted value
+ */
+const char *to_string(const PaddingCode &code);
+
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_UTILS_H__
diff --git a/runtimes/neurun/src/util/config/Config.lst b/runtimes/neurun/src/util/config/Config.lst
new file mode 100644
index 000000000..e029ebe37
--- /dev/null
+++ b/runtimes/neurun/src/util/config/Config.lst
@@ -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.
+ */
+
+#ifndef CONFIG
+#error Define CONFIG before including this file
+#endif
+
+// Name | Type | Default
+CONFIG(GRAPH_DOT_DUMP , int , "0")
+CONFIG(BACKENDS , std::string , "cpu;acl_cl")
+CONFIG(OP_BACKEND_ALLOPS , std::string , "none")
+CONFIG(DISABLE_COMPILE , bool , "0")
+
+
+// Auto-generate all operations
+
+#define OP(InternalName, IsNnApi, NnApiName) \
+ CONFIG(OP_BACKEND_ ## NnApiName, std::string, "acl_cl")
+#include "model/operation/Op.lst"
+#undef OP
+
diff --git a/runtimes/neurun/src/util/config/ConfigManager.cc b/runtimes/neurun/src/util/config/ConfigManager.cc
new file mode 100644
index 000000000..46b80311c
--- /dev/null
+++ b/runtimes/neurun/src/util/config/ConfigManager.cc
@@ -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.
+ */
+
+#include "ConfigManager.h"
+
+#include <cstdlib>
+
+namespace neurun
+{
+namespace config
+{
+
+ConfigManager &ConfigManager::instance()
+{
+ static ConfigManager manager;
+ return manager;
+}
+
+ConfigManager::ConfigManager()
+{
+ auto fetch_from_env_var = [&](const std::string &key) {
+ const char *value = std::getenv(key.c_str());
+ if (value != nullptr)
+ {
+ _map[key] = value;
+ }
+ };
+
+#define CONFIG(Name, Type, Default) \
+ _map.insert({std::string{#Name}, std::string{Default}}); \
+ fetch_from_env_var(#Name);
+
+#include "Config.lst"
+
+#undef CONFIG
+}
+
+template <> bool ConfigManager::get<bool>(const std::string &key) const
+{
+ auto raw = _map.at(key);
+
+ static const std::array<std::string, 5> false_list{"0", "OFF", "FALSE", "N", "NO"};
+ auto false_found = std::find(false_list.begin(), false_list.end(), raw);
+
+ return (false_found == false_list.end());
+}
+
+template <> int ConfigManager::get<int>(const std::string &key) const
+{
+ auto raw = _map.at(key);
+ return std::stoi(raw);
+}
+
+template <> std::string ConfigManager::get<std::string>(const std::string &key) const
+{
+ auto raw = _map.at(key);
+ return raw;
+}
+
+} // namespace config
+} // namespace neurun
diff --git a/runtimes/neurun/src/util/config/ConfigManager.h b/runtimes/neurun/src/util/config/ConfigManager.h
new file mode 100644
index 000000000..78db03dc1
--- /dev/null
+++ b/runtimes/neurun/src/util/config/ConfigManager.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 __NEURUN_CONFIG_CONFIG_MANAGER_H__
+#define __NEURUN_CONFIG_CONFIG_MANAGER_H__
+
+#include <algorithm>
+#include <string>
+#include <unordered_map>
+
+/**
+ * @file ConfigManager.h
+ * @brief This file contains neurun::config::ConfigManager class
+ */
+
+namespace neurun
+{
+namespace config
+{
+
+/**
+ * @brief Class that manages configurations
+ */
+
+class ConfigManager
+{
+public:
+ static ConfigManager &instance();
+
+private:
+ /**
+ * @brief Construct a new ConfigManager object. Fetch variables from Environment Variables.
+ */
+ ConfigManager();
+
+public:
+ /**
+ * @brief Return the configuration value of given key
+ *
+ * @tparam T Type of the config
+ * @param key String key value
+ *
+ * @return The configuration value of given key value
+ */
+ template <typename T> T get(const std::string &key) const;
+
+private:
+ std::unordered_map<std::string, std::string> _map;
+};
+
+template <> bool ConfigManager::get<bool>(const std::string &key) const;
+template <> int ConfigManager::get<int>(const std::string &key) const;
+template <> std::string ConfigManager::get<std::string>(const std::string &key) const;
+
+} // namespace config
+} // namespace neurun
+
+#endif // __NEURUN_CONFIG_CONFIG_MANAGER_H__
diff --git a/runtimes/neurun/src/util/feature/Coordinate4D.h b/runtimes/neurun/src/util/feature/Coordinate4D.h
new file mode 100644
index 000000000..27d6f7b9e
--- /dev/null
+++ b/runtimes/neurun/src/util/feature/Coordinate4D.h
@@ -0,0 +1,89 @@
+/*
+ * 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 __NEURUN_UTIL_FEATURE_COORDINATE_4D_H__
+#define __NEURUN_UTIL_FEATURE_COORDINATE_4D_H__
+
+#include <stdint.h>
+
+namespace neurun
+{
+namespace util
+{
+namespace feature
+{
+
+/**
+ * @brief Class to represent position(offset) of subtensor.\n
+ * Assume that parent and child are already lowered (can get Shape4D).
+ */
+class Coordinate4D
+{
+public:
+ /**
+ * @brief Construct a new Coordinate4D object
+ */
+ Coordinate4D(void) : _n{0}, _h{0}, _w{0}, _c{0}
+ {
+ // DO NOTHING
+ }
+ /**
+ * @brief Construct a new Coordinate4D object
+ * @param[in] n Batch offset
+ * @param[in] h Height offset
+ * @param[in] w Width offset
+ * @param[in] c Channel offset
+ * @return
+ */
+ Coordinate4D(int32_t n, int32_t h, int32_t w, int32_t c) : _n{n}, _h{h}, _w{w}, _c{c}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Return batch offset
+ * @return Batch offset
+ */
+ int32_t n(void) const { return _n; }
+ /**
+ * @brief Return height offset
+ * @return Height offset
+ */
+ int32_t h(void) const { return _h; }
+ /**
+ * @brief Return width offset
+ * @return Width offset
+ */
+ int32_t w(void) const { return _w; }
+ /**
+ * @brief Return channel offset
+ * @return Channel offset
+ */
+ int32_t c(void) const { return _c; }
+
+private:
+ int32_t _n;
+ int32_t _h;
+ int32_t _w;
+ int32_t _c;
+};
+
+} // namespace feature
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_FEATURE_COORDINATE_4D_H__
diff --git a/runtimes/neurun/src/util/feature/nchw/View.h b/runtimes/neurun/src/util/feature/nchw/View.h
new file mode 100644
index 000000000..048fdecd8
--- /dev/null
+++ b/runtimes/neurun/src/util/feature/nchw/View.h
@@ -0,0 +1,106 @@
+/*
+ * 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 __NEURUN_UTIL_FEATURE_NCHW_VIEW_H__
+#define __NEURUN_UTIL_FEATURE_NCHW_VIEW_H__
+
+#include "misc/feature/Reader.h"
+#include "misc/feature/Shape.h"
+
+#include "backend/interface/operand/ITensor.h"
+#include "util/feature/Coordinate4D.h"
+
+#include <cassert>
+
+namespace neurun
+{
+namespace util
+{
+namespace feature
+{
+namespace nchw
+{
+
+template <typename T> class View final : public nnfw::misc::feature::Reader<T>
+{
+public:
+ View(::neurun::backend::operand::ITensor *tensor) : _tensor{tensor}
+ {
+ // TODO Validate whether tensor is a feature map, or not
+ _shape.N = tensor->dimension(3);
+ _shape.C = tensor->dimension(2);
+ _shape.H = tensor->dimension(1);
+ _shape.W = tensor->dimension(0);
+ }
+
+public:
+ const ::nnfw::misc::feature::Shape &shape(void) const { return _shape; }
+
+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<T *>(_tensor->buffer() + 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<T *>(_tensor->buffer() + 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<T *>(_tensor->buffer() + 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<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+private:
+ size_t feature_index_to_byte_offset(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const
+ {
+ return _tensor->calcOffset(
+ neurun::util::feature::Coordinate4D{static_cast<int32_t>(batch), static_cast<int32_t>(row),
+ static_cast<int32_t>(col), static_cast<int32_t>(ch)});
+ }
+
+private:
+ ::nnfw::misc::feature::Shape _shape;
+ ::neurun::backend::operand::ITensor *_tensor;
+};
+
+} // namespace nchw
+} // namespace feature
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_FEATURE_NCHW_VIEW_H__
diff --git a/runtimes/neurun/src/util/feature/nhwc/Reader.h b/runtimes/neurun/src/util/feature/nhwc/Reader.h
new file mode 100644
index 000000000..85b8cab74
--- /dev/null
+++ b/runtimes/neurun/src/util/feature/nhwc/Reader.h
@@ -0,0 +1,72 @@
+/*
+ * 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 __NEURUN_UTIL_FEATURE_NHWC_READER_H__
+#define __NEURUN_UTIL_FEATURE_NHWC_READER_H__
+
+#include "Utils.h"
+
+#include "misc/feature/Reader.h"
+
+namespace neurun
+{
+namespace util
+{
+namespace feature
+{
+namespace nhwc
+{
+
+template <typename T> class Reader final : public nnfw::misc::feature::Reader<T>
+{
+public:
+ Reader(const ::nnfw::misc::feature::Shape &shape, const T *ptr, size_t len)
+ : _shape{shape}, _ptr{ptr}
+ {
+ (void)len; // Workaround for unused variable in release mode
+ assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len);
+ }
+
+public:
+ const nnfw::misc::feature::Shape &shape(void) const { return _shape; }
+
+public:
+ T at(uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ uint32_t index = index_of(_shape, ch, row, col);
+
+ return _ptr[index];
+ }
+ T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ uint32_t index = index_of(_shape, batch, ch, row, col);
+
+ return _ptr[index];
+ }
+
+private:
+ nnfw::misc::feature::Shape _shape;
+
+private:
+ const T *_ptr;
+};
+
+} // namespace nhwc
+} // namespace feature
+} // namespace util
+} // namespace neurun
+
+#endif // __NEURUN_UTIL_FEATURE_NHWC_READER_H__
diff --git a/runtimes/neurun/src/internal/nnapi/feature/Utils.h b/runtimes/neurun/src/util/feature/nhwc/Utils.h
index e6e1e71bd..3dab4261c 100644
--- a/runtimes/neurun/src/internal/nnapi/feature/Utils.h
+++ b/runtimes/neurun/src/util/feature/nhwc/Utils.h
@@ -14,19 +14,21 @@
* limitations under the License.
*/
-#ifndef __INTERNAL_NNAPI_FEATURE_UTILS_H__
-#define __INTERNAL_NNAPI_FEATURE_UTILS_H__
+#ifndef __NEURUN_UTIL_FEATURE_NHWC_UTILS_H__
+#define __NEURUN_UTIL_FEATURE_NHWC_UTILS_H__
-#include "util/feature/Shape.h"
+#include "misc/feature/Shape.h"
-namespace internal
+namespace neurun
{
-namespace nnapi
+namespace util
{
namespace feature
{
+namespace nhwc
+{
-inline uint32_t index_of(const ::nnfw::util::feature::Shape &shape, uint32_t ch, uint32_t row,
+inline uint32_t index_of(const ::nnfw::misc::feature::Shape &shape, uint32_t ch, uint32_t row,
uint32_t col)
{
uint32_t res = 0;
@@ -39,7 +41,7 @@ inline uint32_t index_of(const ::nnfw::util::feature::Shape &shape, uint32_t ch,
return res;
}
-inline uint32_t index_of(const ::nnfw::util::feature::Shape &shape, uint32_t batch, uint32_t ch,
+inline uint32_t index_of(const ::nnfw::misc::feature::Shape &shape, uint32_t batch, uint32_t ch,
uint32_t row, uint32_t col)
{
uint32_t res = 0;
@@ -53,8 +55,9 @@ inline uint32_t index_of(const ::nnfw::util::feature::Shape &shape, uint32_t bat
return res;
}
+} // namespace nhwc
} // namespace feature
-} // namespace nnapi
-} // namespace internal
+} // namespace util
+} // namespace neurun
-#endif // __INTERNAL_NNAPI_FEATURE_UTILS_H__
+#endif // __NEURUN_UTIL_FEATURE_NHWC_UTILS_H__
diff --git a/runtimes/neurun/src/internal/nnapi/feature/View.h b/runtimes/neurun/src/util/feature/nhwc/View.h
index 60335dbf1..1b9be9e1d 100644
--- a/runtimes/neurun/src/internal/nnapi/feature/View.h
+++ b/runtimes/neurun/src/util/feature/nhwc/View.h
@@ -14,79 +14,75 @@
* limitations under the License.
*/
-#ifndef __INTERNAL_NNAPI_FEATURE_VIEW_H__
-#define __INTERNAL_NNAPI_FEATURE_VIEW_H__
+#ifndef __NEURUN_UTIL_FEATURE_NHWC_VIEW_H__
+#define __NEURUN_UTIL_FEATURE_NHWC_VIEW_H__
-#include "internal/nnapi/feature/Utils.h"
+#include <cassert>
-#include "util/feature/Reader.h"
+#include "Utils.h"
-namespace internal
+#include "misc/feature/Reader.h"
+
+namespace neurun
{
-namespace nnapi
+namespace util
{
namespace feature
{
+namespace nhwc
+{
-template <typename T> class View final : public nnfw::util::feature::Reader<float>
+template <typename T> class View final : public nnfw::misc::feature::Reader<T>
{
public:
- View(const ::nnfw::util::feature::Shape &shape, uint8_t *ptr, size_t len)
- : _shape{shape}, _ptr{ptr}, _len{len}
+ View(const ::nnfw::misc::feature::Shape &shape, T *ptr, size_t len) : _shape{shape}, _ptr{ptr}
{
- // DO NOTHING
+ (void)len; // Workaround for unused variable in release mode
+ assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len);
}
public:
- const nnfw::util::feature::Shape &shape(void) const { return _shape; }
+ const nnfw::misc::feature::Shape &shape(void) const { return _shape; }
public:
T at(uint32_t ch, uint32_t row, uint32_t col) const override
{
uint32_t index = index_of(_shape, ch, row, col);
- T *arr = reinterpret_cast<T *>(_ptr);
-
- return arr[index];
+ return _ptr[index];
}
T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override
{
uint32_t index = index_of(_shape, batch, ch, row, col);
- T *arr = reinterpret_cast<T *>(_ptr);
-
- return arr[index];
+ return _ptr[index];
}
T &at(uint32_t ch, uint32_t row, uint32_t col)
{
uint32_t index = index_of(_shape, ch, row, col);
- T *arr = reinterpret_cast<T *>(_ptr);
-
- return arr[index];
+ return _ptr[index];
}
T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col)
{
uint32_t index = index_of(_shape, batch, ch, row, col);
- T *arr = reinterpret_cast<T *>(_ptr);
-
- return arr[index];
+ return _ptr[index];
}
private:
- nnfw::util::feature::Shape _shape;
+ nnfw::misc::feature::Shape _shape;
private:
- uint8_t *_ptr;
- const size_t _len;
+ T *_ptr;
};
+} // namespace nhwc
} // namespace feature
-} // namespace nnapi
-} // namespace internal
+} // namespace util
+} // namespace neurun
-#endif // __INTERNAL_NNAPI_FEATURE_VIEW_H__
+#endif // __NEURUN_UTIL_FEATURE_NHWC_VIEW_H__
diff --git a/runtimes/neurun/src/logging.h b/runtimes/neurun/src/util/logging.h
index 950df7b52..62d563967 100644
--- a/runtimes/neurun/src/logging.h
+++ b/runtimes/neurun/src/util/logging.h
@@ -14,11 +14,15 @@
* limitations under the License.
*/
-#ifndef __NEURUN_LOGGING_H__
-#define __NEURUN_LOGGING_H__
+#ifndef __NEURUN_UTIL_LOGGING_H__
+#define __NEURUN_UTIL_LOGGING_H__
#include <iostream>
+namespace neurun
+{
+namespace util
+{
namespace logging
{
@@ -45,9 +49,11 @@ private:
static Context ctx;
} // namespace logging
+} // namespace util
+} // namespace neurun
-#define VERBOSE(name) \
- if (::logging::ctx.enabled()) \
+#define VERBOSE(name) \
+ if (::neurun::util::logging::ctx.enabled()) \
std::cout << "[" << #name << "] "
-#endif // __NEURUN_LOGGING_H__
+#endif // __NEURUN_UTIL_LOGGING_H__
diff --git a/runtimes/neurun/test/backend/cpu/MemoryPlanner.cc b/runtimes/neurun/test/backend/cpu/MemoryPlanner.cc
new file mode 100644
index 000000000..04f2e5da4
--- /dev/null
+++ b/runtimes/neurun/test/backend/cpu/MemoryPlanner.cc
@@ -0,0 +1,127 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include "backend/cpu/MemoryPlanner.h"
+#include "model/operand/Index.h"
+
+TEST(Allocator, allocate_test)
+{
+ ::neurun::backend::cpu::Allocator allocator(1024);
+ ASSERT_NE(allocator.base(), nullptr);
+}
+
+TEST(BumpPlanner, claim_test)
+{
+ ::neurun::backend::cpu::BumpPlanner planner;
+
+ auto claim = [&planner](uint32_t index, size_t size, uint32_t expected_offset) {
+ ::neurun::model::operand::Index 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)
+{
+ ::neurun::backend::cpu::FirstFitPlanner planner;
+
+ auto claim = [&planner](uint32_t index, size_t size, uint32_t expected_offset) {
+ ::neurun::model::operand::Index 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) {
+ ::neurun::model::operand::Index 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);
+}
diff --git a/runtimes/neurun/test/graph/Graph.cc b/runtimes/neurun/test/graph/Graph.cc
index 5de3c50d0..e6db3fe49 100644
--- a/runtimes/neurun/test/graph/Graph.cc
+++ b/runtimes/neurun/test/graph/Graph.cc
@@ -22,15 +22,15 @@ TEST(Graph, inputs_and_outputs)
{
::neurun::graph::Graph graph;
- ::neurun::graph::operand::Index index0{0u};
- ::neurun::graph::operand::Index index1{1u};
+ ::neurun::model::operand::Index index0{0u};
+ ::neurun::model::operand::Index index1{1u};
graph.addInput({index0});
graph.addInput({index1});
- ::neurun::graph::operand::Index index10{10u};
- ::neurun::graph::operand::Index index11{11u};
- ::neurun::graph::operand::Index index12{12u};
+ ::neurun::model::operand::Index index10{10u};
+ ::neurun::model::operand::Index index11{11u};
+ ::neurun::model::operand::Index index12{12u};
graph.addOutput({index10});
graph.addOutput({index11});
@@ -39,9 +39,9 @@ TEST(Graph, inputs_and_outputs)
ASSERT_EQ(graph.getInputs().size(), 2);
ASSERT_EQ(graph.getOutputs().size(), 3);
- ::neurun::graph::operand::IO::Index io_index0{0};
- ::neurun::graph::operand::IO::Index io_index1{1};
- ::neurun::graph::operand::IO::Index io_index2{2};
+ ::neurun::model::operand::IO::Index io_index0{0};
+ ::neurun::model::operand::IO::Index io_index1{1};
+ ::neurun::model::operand::IO::Index io_index2{2};
ASSERT_EQ(graph.getInputs().at(io_index0), 0);
ASSERT_EQ(graph.getInputs().at(io_index1), 1);
diff --git a/runtimes/neurun/test/graph/operation/MockNode.h b/runtimes/neurun/test/graph/MockNode.h
index 9456b97be..46a6274dd 100644
--- a/runtimes/neurun/test/graph/operation/MockNode.h
+++ b/runtimes/neurun/test/graph/MockNode.h
@@ -14,35 +14,34 @@
* limitations under the License.
*/
-#ifndef __NEURUN_TEST_GRAPH_OPERATION_MOCK_NODE_H__
-#define __NEURUN_TEST_GRAPH_OPERATION_MOCK_NODE_H__
+#ifndef __NEURUN_TEST_GRAPH_MOCK_NODE_H__
+#define __NEURUN_TEST_GRAPH_MOCK_NODE_H__
-#include "graph/operation/Node.h"
-#include "graph/operand/IndexSet.h"
+#include "model/operation/Node.h"
+#include "model/operand/IndexSet.h"
namespace neurun_test
{
namespace graph
{
-namespace operation
-{
-class SimpleMockNode : public neurun::graph::operation::Node
+class SimpleMockNode : public neurun::model::operation::Node
{
public:
- SimpleMockNode(const neurun::graph::operand::IndexSet &inputs,
- const neurun::graph::operand::IndexSet &outputs)
+ SimpleMockNode(const neurun::model::operand::IndexSet &inputs,
+ const neurun::model::operand::IndexSet &outputs)
+ : neurun::model::operation::Node{neurun::model::operation::OperandConstraint::createAny()}
{
setInputs(inputs);
setOutputs(outputs);
}
public:
- virtual void accept(neurun::graph::operation::NodeVisitor &&) const override {}
+ virtual void accept(neurun::model::operation::NodeVisitor &&) const override {}
+ virtual std::string getName() const override { return "SimpleMockNode"; }
};
-} // namespace operation
} // namespace graph
} // namespace neurun_test
-#endif // __NEURUN_TEST_GRAPH_OPERATION_MOCK_NODE_H__
+#endif // __NEURUN_TEST_GRAPH_MOCK_NODE_H__
diff --git a/runtimes/neurun/test/graph/operand/IndexSet.cc b/runtimes/neurun/test/graph/operand/IndexSet.cc
index eeb4cef97..de4768cda 100644
--- a/runtimes/neurun/test/graph/operand/IndexSet.cc
+++ b/runtimes/neurun/test/graph/operand/IndexSet.cc
@@ -16,12 +16,12 @@
#include <gtest/gtest.h>
-#include "graph/operand/IndexSet.h"
+#include "model/operand/IndexSet.h"
-using neurun::graph::operand::Index;
-using neurun::graph::operand::IndexSet;
+using neurun::model::operand::Index;
+using neurun::model::operand::IndexSet;
-TEST(graph_operand_IndexSet, index_set_test)
+TEST(graph_operand_IndexSet, append)
{
IndexSet iset{0, 2, 4, 8};
@@ -31,8 +31,8 @@ TEST(graph_operand_IndexSet, index_set_test)
ASSERT_EQ(iset.size(), 5);
- neurun::graph::operand::IO::Index index1{1};
- neurun::graph::operand::IO::Index index2{4};
+ neurun::model::operand::IO::Index index1{1};
+ neurun::model::operand::IO::Index index2{4};
ASSERT_EQ(iset.at(index1), 2);
ASSERT_EQ(iset.at(index2), 10);
@@ -41,3 +41,12 @@ TEST(graph_operand_IndexSet, index_set_test)
ASSERT_TRUE(iset.contains(Index{10}));
ASSERT_FALSE(iset.contains(Index{11}));
}
+
+TEST(graph_operand_IndexSet, replace)
+{
+ IndexSet iset{0, 1, 2, 3};
+
+ iset.replace(Index{1}, Index{9});
+ ASSERT_FALSE(iset.contains(Index{1}));
+ ASSERT_TRUE(iset.contains(Index{9}));
+}
diff --git a/runtimes/neurun/test/graph/operand/LayoutSet.cc b/runtimes/neurun/test/graph/operand/LayoutSet.cc
index 6ff21cb60..f83e76e30 100644
--- a/runtimes/neurun/test/graph/operand/LayoutSet.cc
+++ b/runtimes/neurun/test/graph/operand/LayoutSet.cc
@@ -1,3 +1,19 @@
+/*
+ * 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 <gtest/gtest.h>
#include "graph/operand/LayoutSet.h"
diff --git a/runtimes/neurun/test/graph/operand/Set.cc b/runtimes/neurun/test/graph/operand/Set.cc
index 176cedc38..00b6a7222 100644
--- a/runtimes/neurun/test/graph/operand/Set.cc
+++ b/runtimes/neurun/test/graph/operand/Set.cc
@@ -16,33 +16,33 @@
#include <gtest/gtest.h>
-#include "graph/operand/Set.h"
+#include "model/operand/Set.h"
TEST(graph_operand_Set, set_test)
{
- neurun::graph::operand::Set set;
+ neurun::model::operand::Set set;
- ::neurun::graph::operand::Shape shape0{3};
+ ::neurun::model::operand::Shape shape0{3};
shape0.dim(0) = 1;
shape0.dim(1) = 2;
shape0.dim(2) = 3;
- ::neurun::graph::operand::Shape shape1{4};
+ ::neurun::model::operand::Shape shape1{4};
shape1.dim(0) = 10;
shape1.dim(1) = 20;
shape1.dim(2) = 30;
shape1.dim(3) = 40;
- ::neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
+ ::neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
set.append(shape0, type);
set.append(shape1, type);
- ASSERT_EQ(set.exist(neurun::graph::operand::Index{0u}), true);
- ASSERT_EQ(set.exist(neurun::graph::operand::Index{1u}), true);
- ASSERT_EQ(set.exist(neurun::graph::operand::Index{2u}), false);
+ ASSERT_EQ(set.exist(neurun::model::operand::Index{0u}), true);
+ ASSERT_EQ(set.exist(neurun::model::operand::Index{1u}), true);
+ ASSERT_EQ(set.exist(neurun::model::operand::Index{2u}), false);
- ASSERT_EQ(set.at(neurun::graph::operand::Index{0u}).shape().dim(0), 1);
- ASSERT_EQ(set.at(neurun::graph::operand::Index{0u}).shape().dim(1), 2);
- ASSERT_EQ(set.at(neurun::graph::operand::Index{0u}).shape().dim(2), 3);
+ ASSERT_EQ(set.at(neurun::model::operand::Index{0u}).shape().dim(0), 1);
+ ASSERT_EQ(set.at(neurun::model::operand::Index{0u}).shape().dim(1), 2);
+ ASSERT_EQ(set.at(neurun::model::operand::Index{0u}).shape().dim(2), 3);
}
diff --git a/runtimes/neurun/test/graph/operand/UseDef.cc b/runtimes/neurun/test/graph/operand/UseDef.cc
index caaea1f6a..e3792f746 100644
--- a/runtimes/neurun/test/graph/operand/UseDef.cc
+++ b/runtimes/neurun/test/graph/operand/UseDef.cc
@@ -17,17 +17,17 @@
#include <gtest/gtest.h>
#include "graph/Graph.h"
-#include "graph/verifier/IVerifier.h"
-#include "nnfw/std/memory.h"
-#include "../operation/MockNode.h"
+#include "graph/verifier/Verifier.h"
+#include "cpp14/memory.h"
+#include "../MockNode.h"
#include <typeindex>
namespace
{
-using IndexSet = neurun::graph::operand::IndexSet;
-using MockNode = neurun_test::graph::operation::SimpleMockNode;
+using IndexSet = neurun::model::operand::IndexSet;
+using MockNode = neurun_test::graph::SimpleMockNode;
} // namespace anonymous
@@ -36,8 +36,8 @@ TEST(graph_operand_usedef, usedef_test)
neurun::graph::Graph graph;
neurun::graph::verifier::DAGChecker verifier;
- neurun::graph::operand::Shape shape{1u};
- neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
+ neurun::model::operand::Shape shape{1u};
+ neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
shape.dim(0) = 3;
// Model Input/Output
@@ -53,16 +53,16 @@ TEST(graph_operand_usedef, usedef_test)
auto operand_index1 = graph.addOperand(shape, type);
graph.operands().at(operand_index1).setAsOperationOutput();
auto mocknode_index1 = graph.addOperation(
- nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index1}));
+ nnfw::cpp14::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index1}));
// MockNode2
auto operand_index2 = graph.addOperand(shape, type);
graph.operands().at(operand_index2).setAsOperationOutput();
auto mocknode_index2 = graph.addOperation(
- nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index2}));
+ nnfw::cpp14::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index2}));
// MockNode3(two input)
- auto multiinput_index = graph.addOperation(nnfw::make_unique<MockNode>(
+ auto multiinput_index = graph.addOperation(nnfw::cpp14::make_unique<MockNode>(
IndexSet{operand_index1, operand_index2}, IndexSet{output_operand}));
graph.finishBuilding();
@@ -89,85 +89,3 @@ TEST(graph_operand_usedef, usedef_test)
ASSERT_EQ(graph.operands().at(operand_index1).getUses().size(), 1);
ASSERT_EQ(graph.operands().at(output_operand).getUses().size(), 0);
}
-
-TEST(graph_operand_usedef, usedef_test_insertion)
-{
- neurun::graph::Graph graph;
- neurun::graph::verifier::DAGChecker verifier;
-
- neurun::graph::operand::Shape shape{1u};
- neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
- shape.dim(0) = 3;
-
- // Model Input/Output
- auto input_operand = graph.addOperand(shape, type);
- auto output_operand = graph.addOperand(shape, type);
-
- graph.addInput(input_operand);
- graph.operands().at(input_operand).setAsModelInput();
- graph.addOutput(output_operand);
- graph.operands().at(output_operand).setAsOperationOutput();
-
- // MockNode1
- auto operand_index1 = graph.addOperand(shape, type);
- graph.operands().at(operand_index1).setAsOperationOutput();
- auto mocknode_index1 = graph.addOperation(
- nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index1}));
-
- // MockNode2
- auto operand_index2 = graph.addOperand(shape, type);
- graph.operands().at(operand_index2).setAsOperationOutput();
- auto mocknode_index2 = graph.addOperation(
- nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand_index2}));
-
- // MockNode3(two input)
- auto multiinput_index = graph.addOperation(nnfw::make_unique<MockNode>(
- IndexSet{operand_index1, operand_index2}, IndexSet{output_operand}));
-
- graph.finishBuilding();
-
- // Insert node1 (between 1 and 2)
- auto inserted_operand1 = graph.addOperand(shape, type);
- graph.operands().at(inserted_operand1).setAsOperationOutput();
- auto inserted_index1 =
- graph.insertOperation(input_operand, mocknode_index2,
- nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand1}));
-
- ASSERT_EQ(inserted_index1.asInt(), 3);
-
- // Insert node2 (between 2 and 3)
- auto inserted_operand2 = graph.addOperand(shape, type);
- graph.operands().at(inserted_operand2).setAsOperationOutput();
- auto inserted_index2 =
- graph.insertOperation(operand_index2, multiinput_index,
- nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand2}));
-
- ASSERT_EQ(inserted_index2.asInt(), 4);
-
- ASSERT_EQ(verifier.verify(graph), true);
-
- // Check def
- ASSERT_EQ(graph.operands().at(input_operand).getDef().size(), 0);
- ASSERT_EQ(graph.operands().at(operand_index1).getDef().contains(mocknode_index1), true);
- ASSERT_EQ(graph.operands().at(inserted_operand1).getDef().contains(inserted_index1), true);
- ASSERT_EQ(graph.operands().at(operand_index2).getDef().contains(mocknode_index2), true);
- ASSERT_EQ(graph.operands().at(inserted_operand2).getDef().contains(inserted_index2), true);
- ASSERT_EQ(graph.operands().at(output_operand).getDef().contains(multiinput_index), true);
-
- // Check use
- ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(mocknode_index1), true);
- ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(inserted_index1), true);
- ASSERT_EQ(graph.operands().at(input_operand).getUses().contains(mocknode_index2), false);
- ASSERT_EQ(graph.operands().at(inserted_operand1).getUses().contains(mocknode_index2), true);
- ASSERT_EQ(graph.operands().at(operand_index1).getUses().contains(multiinput_index), true);
- ASSERT_EQ(graph.operands().at(operand_index2).getUses().contains(inserted_index2), true);
- ASSERT_EQ(graph.operands().at(operand_index2).getUses().contains(multiinput_index), false);
- ASSERT_EQ(graph.operands().at(inserted_operand2).getUses().contains(multiinput_index), true);
-
- ASSERT_EQ(graph.operands().at(input_operand).getUses().size(), 2);
- ASSERT_EQ(graph.operands().at(inserted_operand1).getUses().size(), 1);
- ASSERT_EQ(graph.operands().at(operand_index1).getUses().size(), 1);
- ASSERT_EQ(graph.operands().at(inserted_operand2).getUses().size(), 1);
- ASSERT_EQ(graph.operands().at(operand_index2).getUses().size(), 1);
- ASSERT_EQ(graph.operands().at(output_operand).getUses().size(), 0);
-}
diff --git a/runtimes/neurun/test/graph/operation/Insert.cc b/runtimes/neurun/test/graph/operation/Insert.cc
deleted file mode 100644
index dab89c2a6..000000000
--- a/runtimes/neurun/test/graph/operation/Insert.cc
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * 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 <gtest/gtest.h>
-
-#include "graph/Graph.h"
-#include "graph/verifier/IVerifier.h"
-#include "nnfw/std/memory.h"
-#include "graph/operand/Index.h"
-#include "MockNode.h"
-
-#include <typeindex>
-
-using IOIndex = neurun::graph::operand::IO::Index;
-using Index = neurun::graph::operand::Index;
-using IndexSet = neurun::graph::operand::IndexSet;
-using MockNode = neurun_test::graph::operation::SimpleMockNode;
-
-TEST(graph_operation_manipulation, operation_insertion)
-{
- neurun::graph::Graph graph;
- neurun::graph::verifier::DAGChecker verifier;
-
- neurun::graph::operand::Shape shape{1u};
- neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
- shape.dim(0) = 3;
-
- // Model Input/Output
- auto input_operand = graph.addOperand(shape, type);
- auto output_operand = graph.addOperand(shape, type);
-
- graph.addInput(input_operand);
- graph.operands().at(input_operand).setAsModelInput();
- graph.addOutput(output_operand);
- graph.operands().at(output_operand).setAsOperationOutput();
-
- // MockNode1
- auto operand1 = graph.addOperand(shape, type);
- graph.operands().at(operand1).setAsOperationOutput();
- auto mocknode_index1 =
- graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand1}));
- // MockNode2
- auto operand2 = graph.addOperand(shape, type);
- graph.operands().at(operand2).setAsOperationOutput();
- auto mocknode_index2 =
- graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{operand1}, IndexSet{operand2}));
- // MockNode3
- auto mocknode_index3 =
- graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{operand2}, IndexSet{output_operand}));
-
- graph.finishBuilding();
-
- ASSERT_EQ(verifier.verify(graph), true);
-
- // Insert node1 (between 1 and 2)
- auto inserted_operand1 = graph.addOperand(shape, type);
- graph.operands().at(inserted_operand1).setAsOperationOutput();
- auto inserted_index1 =
- graph.insertOperation(operand1, mocknode_index2,
- nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand1}));
-
- ASSERT_EQ(inserted_index1.asInt(), 3);
-
- // Insert node2 (between 2 and 3)
- auto inserted_operand2 = graph.addOperand(shape, type);
- graph.operands().at(inserted_operand2).setAsOperationOutput();
- auto inserted_index2 =
- graph.insertOperation(operand2, mocknode_index3,
- nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand2}));
-
- ASSERT_EQ(inserted_index2.asInt(), 4);
-
- // Check tensor indexes
- const auto &operations = graph.operations();
- ASSERT_EQ(operations.at(mocknode_index1).getOutputs().at(Index{0}),
- operations.at(inserted_index1).getInputs().at(Index{0}));
- ASSERT_EQ(operations.at(inserted_index1).getOutputs().at(Index{0}),
- operations.at(mocknode_index2).getInputs().at(Index{0}));
- ASSERT_EQ(operations.at(mocknode_index2).getOutputs().at(Index{0}),
- operations.at(inserted_index2).getInputs().at(Index{0}));
- ASSERT_EQ(operations.at(inserted_index2).getOutputs().at(Index{0}),
- operations.at(mocknode_index3).getInputs().at(Index{0}));
-
- ASSERT_EQ(verifier.verify(graph), true);
-}
-
-TEST(graph_operation_manipulation, operation_insertion_multi_input)
-{
- neurun::graph::Graph graph;
- neurun::graph::verifier::DAGChecker verifier;
-
- neurun::graph::operand::Shape shape{1u};
- neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
- shape.dim(0) = 3;
-
- // Model Input/Output
- auto input_operand = graph.addOperand(shape, type);
- auto output_operand = graph.addOperand(shape, type);
-
- graph.addInput(input_operand);
- graph.operands().at(input_operand).setAsModelInput();
- graph.addOutput(output_operand);
- graph.operands().at(output_operand).setAsOperationOutput();
-
- // MockNode1
- auto operand1 = graph.addOperand(shape, type);
- graph.operands().at(operand1).setAsOperationOutput();
- auto mocknode_index1 =
- graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand1}));
- // MockNode2
- auto operand2 = graph.addOperand(shape, type);
- graph.operands().at(operand2).setAsOperationOutput();
- auto mocknode_index2 =
- graph.addOperation(nnfw::make_unique<MockNode>(IndexSet{input_operand}, IndexSet{operand2}));
- // MultiInputMockNode
- auto multiinput_index = graph.addOperation(
- nnfw::make_unique<MockNode>(IndexSet{operand1, operand2}, IndexSet{output_operand}));
-
- graph.finishBuilding();
-
- ASSERT_EQ(verifier.verify(graph), true);
-
- // Insert node1 (between 1 and multi)
- auto inserted_operand1 = graph.addOperand(shape, type);
- graph.operands().at(inserted_operand1).setAsOperationOutput();
- auto inserted_index1 =
- graph.insertOperation(operand1, multiinput_index,
- nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand1}));
-
- ASSERT_EQ(inserted_index1.asInt(), 3);
-
- // Insert node2 (between 2 and multi)
- auto inserted_operand2 = graph.addOperand(shape, type);
- graph.operands().at(inserted_operand2).setAsOperationOutput();
- auto inserted_index2 =
- graph.insertOperation(operand2, multiinput_index,
- nnfw::make_unique<MockNode>(IndexSet{}, IndexSet{inserted_operand2}));
-
- ASSERT_EQ(inserted_index2.asInt(), 4);
-
- // Check tensor indexes
- const auto &operations = graph.operations();
- ASSERT_EQ(operations.at(mocknode_index1).getOutputs().at(Index{0}),
- operations.at(inserted_index1).getInputs().at(Index{0}));
- ASSERT_EQ(operations.at(inserted_index1).getOutputs().at(Index{0}),
- operations.at(multiinput_index).getInputs().at(Index{0}));
- ASSERT_EQ(operations.at(mocknode_index2).getOutputs().at(Index{0}),
- operations.at(inserted_index2).getInputs().at(Index{0}));
- ASSERT_EQ(operations.at(inserted_index2).getOutputs().at(Index{0}),
- operations.at(multiinput_index).getInputs().at(Index{1}));
-
- ASSERT_EQ(verifier.verify(graph), true);
-}
diff --git a/runtimes/neurun/test/graph/operation/Set.cc b/runtimes/neurun/test/graph/operation/Set.cc
index df680ff48..3560482ee 100644
--- a/runtimes/neurun/test/graph/operation/Set.cc
+++ b/runtimes/neurun/test/graph/operation/Set.cc
@@ -16,18 +16,18 @@
#include <gtest/gtest.h>
-#include "MockNode.h"
-#include "graph/operation/Set.h"
+#include "../MockNode.h"
+#include "model/operation/Set.h"
-using neurun::graph::operation::Set;
-using neurun::graph::operation::Node;
-using neurun::graph::operation::Index;
+using neurun::model::operation::Set;
+using neurun::model::operation::Node;
+using neurun::model::operation::Index;
TEST(graph_operation_Set, operation_test)
{
Set set;
- set.append(std::unique_ptr<Node>(
- new neurun_test::graph::operation::SimpleMockNode({1, 2, 3, 4}, {5, 6, 7})));
+ set.append(
+ std::unique_ptr<Node>(new neurun_test::graph::SimpleMockNode({1, 2, 3, 4}, {5, 6, 7})));
Index idx{0u};
ASSERT_EQ(set.at(idx).getInputs().size(), 4);
ASSERT_EQ(set.at(idx).getOutputs().size(), 3);
diff --git a/runtimes/neurun/test/graph/operation/SetIO.cc b/runtimes/neurun/test/graph/operation/SetIO.cc
index c0a0c9099..a475bdcc9 100644
--- a/runtimes/neurun/test/graph/operation/SetIO.cc
+++ b/runtimes/neurun/test/graph/operation/SetIO.cc
@@ -17,24 +17,24 @@
#include <gtest/gtest.h>
#include "graph/Graph.h"
-#include "nnfw/std/memory.h"
-#include "graph/operation/Conv2D.h"
-#include "graph/operation/Concat.h"
-#include "graph/operand/Index.h"
-#include "graph/operand/IndexSet.h"
+#include "cpp14/memory.h"
+#include "model/operation/Conv2DNode.h"
+#include "model/operation/ConcatNode.h"
+#include "model/operand/Index.h"
+#include "model/operand/IndexSet.h"
#include <stdexcept>
-using Index = neurun::graph::operand::IO::Index;
-using IndexSet = neurun::graph::operand::IndexSet;
-using GraphNodeInitParam = neurun::graph::operation::Node::InitParam;
+using Index = neurun::model::operand::IO::Index;
+using IndexSet = neurun::model::operand::IndexSet;
+using GraphNodeInitParam = neurun::model::operation::Node::InitParam;
TEST(graph_operation_setIO, operation_setIO_conv)
{
neurun::graph::Graph graph;
- neurun::graph::operand::Shape shape{1u};
- neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
+ neurun::model::operand::Shape shape{1u};
+ neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
shape.dim(0) = 3;
// Add Conv
@@ -45,9 +45,10 @@ TEST(graph_operation_setIO, operation_setIO_conv)
}
uint32_t outoperand = graph.addOperand(shape, type).asInt();
- using GraphNode = neurun::graph::operation::Conv2D::Implicit::Node;
+ using GraphNode = neurun::model::operation::Conv2DNode;
- auto conv = nnfw::make_unique<GraphNode>(GraphNodeInitParam{7, params.data(), 1, &outoperand});
+ auto conv =
+ nnfw::cpp14::make_unique<GraphNode>(GraphNodeInitParam{7, params.data(), 1, &outoperand});
ASSERT_EQ(conv->getInputs().at(Index{0}).asInt(), params[0]);
conv->setInputs({8, 9, 10});
ASSERT_NE(conv->getInputs().at(Index{0}).asInt(), params[0]);
@@ -58,8 +59,8 @@ TEST(graph_operation_setIO, operation_setIO_concat)
{
neurun::graph::Graph graph;
- neurun::graph::operand::Shape shape{1u};
- neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
+ neurun::model::operand::Shape shape{1u};
+ neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
shape.dim(0) = 3;
// Add Concat
@@ -70,9 +71,10 @@ TEST(graph_operation_setIO, operation_setIO_concat)
}
uint32_t outoperand = graph.addOperand(shape, type).asInt();
- using GraphNode = neurun::graph::operation::Concat::Node;
+ using GraphNode = neurun::model::operation::ConcatNode;
- auto concat = nnfw::make_unique<GraphNode>(GraphNodeInitParam{7, params.data(), 1, &outoperand});
+ auto concat =
+ nnfw::cpp14::make_unique<GraphNode>(GraphNodeInitParam{7, params.data(), 1, &outoperand});
ASSERT_EQ(concat->getInputs().size(), 6);
ASSERT_EQ(concat->getInputs().at(Index{0}).asInt(), params[0]);
diff --git a/runtimes/neurun/test/graph/verifier/Verifier.cc b/runtimes/neurun/test/graph/verifier/Verifier.cc
index 68c8e8ec8..a37b0ac1f 100644
--- a/runtimes/neurun/test/graph/verifier/Verifier.cc
+++ b/runtimes/neurun/test/graph/verifier/Verifier.cc
@@ -16,32 +16,23 @@
#include <gtest/gtest.h>
-#include "graph/operation/Node.h"
+#include "model/operation/Node.h"
#include "graph/Graph.h"
-#include "graph/verifier/IVerifier.h"
-#include "nnfw/std/memory.h"
-#include "graph/operand/Object.h"
+#include "graph/verifier/Verifier.h"
+#include "cpp14/memory.h"
+#include "model/operand/Object.h"
+#include "../MockNode.h"
-class MockNode : public neurun::graph::operation::Node
-{
-public:
- MockNode(const neurun::graph::operand::Index &input, const neurun::graph::operand::Index &output)
- {
- setInputs({input});
- setOutputs({output});
- }
-
-public:
- virtual void accept(neurun::graph::operation::NodeVisitor &&) const override {}
-};
+using IndexSet = neurun::model::operand::IndexSet;
+using MockNode = neurun_test::graph::SimpleMockNode;
TEST(Verifier, dag_checker)
{
neurun::graph::Graph graph;
neurun::graph::verifier::DAGChecker verifier;
- ::neurun::graph::operand::Shape shape{1u};
- ::neurun::graph::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
+ ::neurun::model::operand::Shape shape{1u};
+ ::neurun::model::operand::TypeInfo type{ANEURALNETWORKS_TENSOR_INT32, 0, 0};
shape.dim(0) = 3;
auto operand1 = graph.addOperand(shape, type);
@@ -52,13 +43,9 @@ TEST(Verifier, dag_checker)
graph.addOutput(operand2);
graph.operands().at(operand2).setAsOperationOutput();
- graph.addOperation(nnfw::make_unique<MockNode>(operand1, operand2));
+ graph.addOperation(nnfw::cpp14::make_unique<MockNode>(IndexSet{operand1}, IndexSet{operand2}));
- ASSERT_EQ(verifier.verify(graph), true);
+ graph.finishBuilding();
- // Create cycle
- graph.operands().at(operand1).setAsOperationOutput();
- graph.addOperation(nnfw::make_unique<MockNode>(operand2, operand1));
-
- ASSERT_EQ(verifier.verify(graph), false);
+ ASSERT_EQ(verifier.verify(graph), true);
}