From 16dddd2af57a71ca10d62a4412d014f859720d2c Mon Sep 17 00:00:00 2001 From: Sheri Zhang Date: Wed, 27 May 2020 15:03:48 +0100 Subject: COMPMID-3381: Implement graph example for YoLo v3 output detector Add sub/exp/splitv support in graph api Signed-off-by: Sheri Zhang Change-Id: I4e08cc19a46655717068b12c93d67e619a595d9a Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/3309 Reviewed-by: Georgios Pinitas Tested-by: Arm Jenkins Comments-Addressed: Arm Jenkins --- arm_compute/graph/LayerDescriptors.h | 25 + arm_compute/graph/TypePrinter.h | 3 + arm_compute/graph/Types.h | 9 +- arm_compute/graph/backends/FunctionHelpers.h | 48 ++ arm_compute/graph/backends/ValidateHelpers.h | 73 +++ arm_compute/graph/nodes/EltwiseLayerNode.h | 40 ++ arm_compute/graph/nodes/SplitLayerNode.h | 20 +- examples/graph_yolov3_output_detector.cpp | 613 ++++++++++++++++++++++ src/graph/backends/CL/CLFunctionsFactory.cpp | 8 + src/graph/backends/CL/CLNodeValidator.cpp | 18 + src/graph/backends/NEON/NEFunctionFactory.cpp | 12 +- src/graph/backends/NEON/NENodeValidator.cpp | 18 + src/graph/mutators/NodeFusionMutator.cpp | 6 + src/graph/mutators/SplitLayerSubTensorMutator.cpp | 6 +- src/graph/nodes/EltwiseLayerNode.cpp | 62 +++ src/graph/nodes/SplitLayerNode.cpp | 71 ++- 16 files changed, 1003 insertions(+), 29 deletions(-) create mode 100644 examples/graph_yolov3_output_detector.cpp diff --git a/arm_compute/graph/LayerDescriptors.h b/arm_compute/graph/LayerDescriptors.h index d8e6a6a87b..ba53622298 100644 --- a/arm_compute/graph/LayerDescriptors.h +++ b/arm_compute/graph/LayerDescriptors.h @@ -89,6 +89,31 @@ struct EltwiseLayerDescriptor ActivationLayerInfo fused_activation; /**< Fused activation info */ }; +/** Unary Elementwise layer descriptor */ +struct UnaryEltwiseLayerDescriptor +{ + /** Constructor + * + * @param[in] op Unary element-wise operation to perform + * @param[in] out_quant_info (Optional) Output quantization information. Defaults to empty @ref QuantizationInfo + * @param[in] c_policy (Optional) Convert policy used for the operation. Defaults to @ref ConvertPolicy::SATURATE + * @param[in] r_policy (Optional) Rounding policy used for the operation. Defaults to @ref RoundingPolicy::TO_ZERO + * @param[in] fused_activation (Optional) Fused activation information. Defaults to empty (identity) @ref ActivationLayerInfo + */ + UnaryEltwiseLayerDescriptor(UnaryEltwiseOperation op, QuantizationInfo out_quant_info = QuantizationInfo(), ConvertPolicy c_policy = ConvertPolicy::SATURATE, + RoundingPolicy r_policy = RoundingPolicy::TO_ZERO, + ActivationLayerInfo fused_activation = ActivationLayerInfo()) + : op(op), out_quant_info(out_quant_info), c_policy(c_policy), r_policy(r_policy), fused_activation(fused_activation) + { + } + + UnaryEltwiseOperation op; /**< Unary element-wise operation to perform */ + QuantizationInfo out_quant_info; /**< Output quantization information */ + ConvertPolicy c_policy; /**< Convert policy */ + RoundingPolicy r_policy; /**< Rounding policy */ + ActivationLayerInfo fused_activation; /**< Fused activation info */ +}; + /** Deconvolution layer descriptor */ struct DeconvolutionLayerDescriptor { diff --git a/arm_compute/graph/TypePrinter.h b/arm_compute/graph/TypePrinter.h index d56407b52b..dea055a83b 100644 --- a/arm_compute/graph/TypePrinter.h +++ b/arm_compute/graph/TypePrinter.h @@ -98,6 +98,9 @@ inline ::std::ostream &operator<<(::std::ostream &os, const NodeType &node_type) case NodeType::EltwiseLayer: os << "EltwiseLayer"; break; + case NodeType::UnaryEltwiseLayer: + os << "UnaryEltwiseLayer"; + break; case NodeType::FlattenLayer: os << "FlattenLayer"; break; diff --git a/arm_compute/graph/Types.h b/arm_compute/graph/Types.h index 296f757c9b..422069238d 100644 --- a/arm_compute/graph/Types.h +++ b/arm_compute/graph/Types.h @@ -103,7 +103,13 @@ enum class EltwiseOperation { Add, /**< Arithmetic addition */ Sub, /**< Arithmetic subtraction */ - Mul /**< Arithmetic multiplication */ + Mul, /**< Arithmetic multiplication */ +}; + +/** Supported Unary Element-wise operations */ +enum class UnaryEltwiseOperation +{ + Exp /**< Exp */ }; /** Supported Convolution layer methods */ @@ -168,6 +174,7 @@ enum class NodeType SplitLayer, StackLayer, UpsampleLayer, + UnaryEltwiseLayer, YOLOLayer, Input, diff --git a/arm_compute/graph/backends/FunctionHelpers.h b/arm_compute/graph/backends/FunctionHelpers.h index 975e5fe55e..e21b8ed288 100644 --- a/arm_compute/graph/backends/FunctionHelpers.h +++ b/arm_compute/graph/backends/FunctionHelpers.h @@ -816,6 +816,54 @@ std::unique_ptr create_eltwise_layer(EltwiseLayerNode &node) return RETURN_UNIQUE_PTR(func); } +/** Create a backend unary element-wise operation layer function + * + * @tparam UnaryEltwiseFunctions Backend unary element-wise function + * @tparam TargetInfo Target-specific information + * + * @param[in] node Node to create the backend function for + * + * @return Backend unary element-wise operation layer function + */ +template +std::unique_ptr create_unary_eltwise_layer(UnaryEltwiseLayerNode &node) +{ + validate_node(node, 1 /* expected inputs */, 1 /* expected outputs */); + + // Extract IO and info + typename TargetInfo::TensorType *input = get_backing_tensor(node.input(0)); + typename TargetInfo::TensorType *output = get_backing_tensor(node.output(0)); + const UnaryEltwiseOperation eltwise_op = node.eltwise_descriptor().op; + + ARM_COMPUTE_ERROR_ON(input == nullptr); + ARM_COMPUTE_ERROR_ON(output == nullptr); + + std::unique_ptr func = nullptr; + std::string func_name; + if(eltwise_op == UnaryEltwiseOperation::Exp) + { + std::tie(func, func_name) = create_named_function( + std::string("Exp"), + input, output); + } + else + { + ARM_COMPUTE_ERROR("Unsupported unary element-wise operation!"); + } + + // Log info + ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " + << node.name() + << " Type: " << node.type() + << " Target: " << TargetInfo::TargetType + << " Operation: " << func_name + << " Data Type: " << input->info()->data_type() + << " Shape: " << input->info()->tensor_shape() + << std::endl); + + return RETURN_UNIQUE_PTR(func); +} + /** Create a backend flatten layer function * * @tparam FlattenLayerFunction Backend flatten function diff --git a/arm_compute/graph/backends/ValidateHelpers.h b/arm_compute/graph/backends/ValidateHelpers.h index 673caf9eac..d689c1f89d 100644 --- a/arm_compute/graph/backends/ValidateHelpers.h +++ b/arm_compute/graph/backends/ValidateHelpers.h @@ -579,6 +579,79 @@ Status validate_yolo_layer(YOLOLayerNode &node) // Validate function return YOLOLayer::validate(input, output, node.activation_info(), node.num_classes()); } +/** Validates a element-wise layer node + * + * @param[in] node Node to validate + * + * @return Status + */ +template +Status validate_eltwise_Layer(EltwiseLayerNode &node) +{ + ARM_COMPUTE_LOG_GRAPH_VERBOSE("Validating EltwiseLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl); + ARM_COMPUTE_RETURN_ERROR_ON(node.num_inputs() != 2); + ARM_COMPUTE_RETURN_ERROR_ON(node.num_outputs() != 1); + + // Extract input and output + const arm_compute::ITensorInfo *input1 = detail::get_backing_tensor_info(node.input(0)); + const arm_compute::ITensorInfo *input2 = detail::get_backing_tensor_info(node.input(1)); + const arm_compute::ITensorInfo *output = get_backing_tensor_info(node.output(0)); + const EltwiseOperation eltwise_op = node.eltwise_operation(); + const ConvertPolicy convert_policy = node.convert_policy(); + const RoundingPolicy round_policy = node.rounding_policy(); + const ActivationLayerInfo act_info = node.fused_activation(); + const QuantizationInfo quant_info = node.output_quant_info(); + const float scale = (quant_info.scale().empty()) ? 1.0f : quant_info.scale()[0]; + + // Validate function + if(eltwise_op == EltwiseOperation::Add) + { + return EltwiseLayerFunctions::ArithmeticAddition::validate(input1, input2, output, convert_policy, act_info); + } + else if(eltwise_op == EltwiseOperation::Sub) + { + return EltwiseLayerFunctions::ArithmeticSubtraction::validate(input1, input2, output, convert_policy, act_info); + } + else if(eltwise_op == EltwiseOperation::Mul) + { + return EltwiseLayerFunctions::PixelWiseMultiplication::validate(input1, input2, output, scale, convert_policy, round_policy, act_info); + } + else + { + ARM_COMPUTE_ERROR("Unsupported element-wise operation!"); + } + return Status{}; +} +/** Validates a unary element-wise layer node + * + * @param[in] node Node to validate + * + * @return Status + */ +template +Status validate_unary_eltwise_layer(UnaryEltwiseLayerNode &node) +{ + ARM_COMPUTE_LOG_GRAPH_VERBOSE("Validating EltwiseLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl); + ARM_COMPUTE_RETURN_ERROR_ON(node.num_inputs() != 1); + ARM_COMPUTE_RETURN_ERROR_ON(node.num_outputs() != 1); + + // Extract input and output + arm_compute::ITensorInfo *input = detail::get_backing_tensor_info(node.input(0)); + arm_compute::ITensorInfo *output = get_backing_tensor_info(node.output(0)); + const UnaryEltwiseOperation eltwise_op = node.eltwise_descriptor().op; + + // Validate function + if(eltwise_op == UnaryEltwiseOperation::Exp) + { + return UnaryEltwiseLayerFunctions::ExpLayer::validate(input, output); + } + else + { + ARM_COMPUTE_ERROR("Unsupported unary element-wise operation!"); + } + + return Status{}; +} } // namespace detail } // namespace backends } // namespace graph diff --git a/arm_compute/graph/nodes/EltwiseLayerNode.h b/arm_compute/graph/nodes/EltwiseLayerNode.h index d619ad2588..9ea5d69ac9 100644 --- a/arm_compute/graph/nodes/EltwiseLayerNode.h +++ b/arm_compute/graph/nodes/EltwiseLayerNode.h @@ -63,6 +63,12 @@ public: */ ActivationLayerInfo fused_activation() const; + /** Returns output quantization info + * + * @return Output quantization info + */ + QuantizationInfo output_quant_info() const; + /** Sets fused activation * * @param[in] fused_activation Fused activation to set @@ -80,6 +86,40 @@ public: private: descriptors::EltwiseLayerDescriptor descriptor; }; + +/** Unary Eltwise Layer node */ +class UnaryEltwiseLayerNode final : public INode +{ +public: + /** Constructor + * + * @param[in] descriptor Containing information for the node described in @ref descriptors::EltwiseLayerDescriptor + */ + UnaryEltwiseLayerNode(const descriptors::UnaryEltwiseLayerDescriptor &descriptor); + /** Unary eltwise layer descriptor + * + * @return Unary eltwise layer descriptor which containing information + */ + descriptors::UnaryEltwiseLayerDescriptor eltwise_descriptor() const; + + /** Sets fused activation + * + * @param[in] fused_activation Fused activation to set + */ + void set_fused_activation(ActivationLayerInfo fused_activation); + + // Inherited overridden methods: + NodeType type() const override; + bool forward_descriptors() override; + TensorDescriptor configure_output(size_t idx) const override; + void accept(INodeVisitor &v) override; + + static constexpr NodeType node_type = NodeType::UnaryEltwiseLayer; + +private: + descriptors::UnaryEltwiseLayerDescriptor descriptor; +}; + } // namespace graph } // namespace arm_compute #endif /* ARM_COMPUTE_GRAPH_ELTWISE_LAYER_NODE_H */ diff --git a/arm_compute/graph/nodes/SplitLayerNode.h b/arm_compute/graph/nodes/SplitLayerNode.h index 345260ab84..b5dea7f8c5 100644 --- a/arm_compute/graph/nodes/SplitLayerNode.h +++ b/arm_compute/graph/nodes/SplitLayerNode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 ARM Limited. + * Copyright (c) 2018-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -38,10 +38,13 @@ class SplitLayerNode final : public INode public: /** Default Constructor * - * @param[in] num_splits Number of splits - * @param[in] axis (Optional) Axis to split on. Supported axis >= 2. Defaults to 0 + * @param[in] num_splits Number of splits + * @param[in] axis (Optional) Axis to split on. Defaults to 0 + * @param[in] size_splits (Optional) The sizes of each output tensor along the split dimension. + * Must sum to the dimension of value along split_dim. + * Can contain one -1 indicating that dimension is to be inferred. */ - SplitLayerNode(unsigned int num_splits, unsigned int axis = 0); + SplitLayerNode(unsigned int num_splits, int axis = 0, std::vector size_splits = std::vector()); /** Computes split layer output descriptor * * @param[in] input_descriptor Descriptor of the input tensor @@ -51,8 +54,8 @@ public: * * @return A pair with the descriptor of the split and the starting coordinates */ - static std::pair compute_output_descriptor(const TensorDescriptor &input_descriptor, - unsigned int num_splits, unsigned int axis, unsigned int idx); + std::pair compute_output_descriptor(const TensorDescriptor &input_descriptor, + unsigned int num_splits, int axis, unsigned int idx); /** Number of splits accessor * * @return Number of splits @@ -72,8 +75,9 @@ public: void accept(INodeVisitor &v) override; private: - unsigned int _num_splits; - unsigned int _axis; + unsigned int _num_splits; + int _axis; + std::vector _size_splits; }; } // namespace graph } // namespace arm_compute diff --git a/examples/graph_yolov3_output_detector.cpp b/examples/graph_yolov3_output_detector.cpp new file mode 100644 index 0000000000..d803206eb8 --- /dev/null +++ b/examples/graph_yolov3_output_detector.cpp @@ -0,0 +1,613 @@ +/* + * Copyright (c) 2020 ARM Limited. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "arm_compute/graph.h" +#include "arm_compute/graph/Utils.h" + +#include "support/ToolchainSupport.h" +#include "utils/CommonGraphOptions.h" +#include "utils/GraphUtils.h" +#include "utils/Utils.h" + +using namespace arm_compute::graph; +using namespace arm_compute::utils; + +class GraphYoloV3OutputDetector +{ +public: + GraphYoloV3OutputDetector() + : _graph(0, "GraphYoloV3OutputDetector") + { + } + + bool setup(const std::string &data_path, Target target) + { + using namespace arm_compute; + using namespace graph_utils; + + NodeID id_ConstantFolding_truediv_1_recip = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 1, 1 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_ConstantFolding_truediv_1_recip = _graph.node(id_ConstantFolding_truediv_1_recip); + node_ConstantFolding_truediv_1_recip->set_common_node_parameters(NodeParams{ "ConstantFolding_truediv_1_recip", target }); + node_ConstantFolding_truediv_1_recip->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/ConstantFolding_truediv_1_recip.npy", DataLayout::NHWC)); + + NodeID id_ConstantFolding_truediv_recip = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 1, 1 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_ConstantFolding_truediv_recip = _graph.node(id_ConstantFolding_truediv_recip); + node_ConstantFolding_truediv_recip->set_common_node_parameters(NodeParams{ "ConstantFolding_truediv_recip", target }); + node_ConstantFolding_truediv_recip->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/ConstantFolding_truediv_recip.npy", DataLayout::NHWC)); + + NodeID id_detector_yolo_v3_mul_6_y = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 1, 2 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_detector_yolo_v3_mul_6_y = _graph.node(id_detector_yolo_v3_mul_6_y); + node_detector_yolo_v3_mul_6_y->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_6_y", target }); + node_detector_yolo_v3_mul_6_y->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/detector_yolo_v3_mul_6_y.npy", DataLayout::NHWC)); + + NodeID id_detector_yolo_v3_mul_3_y = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 1, 2 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_detector_yolo_v3_mul_3_y = _graph.node(id_detector_yolo_v3_mul_3_y); + node_detector_yolo_v3_mul_3_y->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_3_y", target }); + node_detector_yolo_v3_mul_3_y->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/detector_yolo_v3_mul_3_y.npy", DataLayout::NHWC)); + + NodeID id_detector_yolo_v3_mul_y = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 1, 2 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_detector_yolo_v3_mul_y = _graph.node(id_detector_yolo_v3_mul_y); + node_detector_yolo_v3_mul_y->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_y", target }); + node_detector_yolo_v3_mul_y->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/detector_yolo_v3_mul_y.npy", DataLayout::NHWC)); + + NodeID id_detector_yolo_v3_mul_7 = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 8112, 2 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_detector_yolo_v3_mul_7 = _graph.node(id_detector_yolo_v3_mul_7); + node_detector_yolo_v3_mul_7->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_7", target }); + node_detector_yolo_v3_mul_7->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/detector_yolo_v3_mul_7.npy", DataLayout::NHWC)); + + NodeID id_detector_yolo_v3_Reshape_11 = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 8112, 2 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_detector_yolo_v3_Reshape_11 = _graph.node(id_detector_yolo_v3_Reshape_11); + node_detector_yolo_v3_Reshape_11->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Reshape_11", target }); + node_detector_yolo_v3_Reshape_11->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/detector_yolo_v3_Reshape_11.npy", DataLayout::NHWC)); + + NodeID id_detector_yolo_v3_mul_4 = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 2028, 2 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_detector_yolo_v3_mul_4 = _graph.node(id_detector_yolo_v3_mul_4); + node_detector_yolo_v3_mul_4->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_4", target }); + node_detector_yolo_v3_mul_4->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/detector_yolo_v3_mul_4.npy", DataLayout::NHWC)); + + NodeID id_detector_yolo_v3_Reshape_7 = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 2028, 2 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_detector_yolo_v3_Reshape_7 = _graph.node(id_detector_yolo_v3_Reshape_7); + node_detector_yolo_v3_Reshape_7->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Reshape_7", target }); + node_detector_yolo_v3_Reshape_7->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/detector_yolo_v3_Reshape_7.npy", DataLayout::NHWC)); + + NodeID id_detector_yolo_v3_mul_1 = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 507, 2 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_detector_yolo_v3_mul_1 = _graph.node(id_detector_yolo_v3_mul_1); + node_detector_yolo_v3_mul_1->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_1", target }); + node_detector_yolo_v3_mul_1->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/detector_yolo_v3_mul_1.npy", DataLayout::NHWC)); + + NodeID id_detector_yolo_v3_Reshape_3 = _graph.add_node( + TensorDescriptor + { + TensorShape{ 1, 507, 2 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_detector_yolo_v3_Reshape_3 = _graph.node(id_detector_yolo_v3_Reshape_3); + node_detector_yolo_v3_Reshape_3->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Reshape_3", target }); + node_detector_yolo_v3_Reshape_3->output(0)->set_accessor(get_weights_accessor(data_path, "/cnn_data/yolov3_output_detector/detector_yolo_v3_Reshape_3.npy", DataLayout::NHWC)); + + NodeID id_input_to_detector_3 = _graph.add_node( + TensorDescriptor + { + TensorShape{ 255, 52, 52, 1 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_input_to_detector_3 = _graph.node(id_input_to_detector_3); + node_input_to_detector_3->set_common_node_parameters(NodeParams{ "input_to_detector_3", target }); + node_input_to_detector_3->output(0)->set_accessor(support::cpp14::make_unique()); + + NodeID id_detector_yolo_v3_Reshape_10 = _graph.add_node( + TensorShape{ 1, 8112, 85 }); + INode *node_detector_yolo_v3_Reshape_10 = _graph.node(id_detector_yolo_v3_Reshape_10); + node_detector_yolo_v3_Reshape_10->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Reshape_10", target }); + _graph.add_connection(id_input_to_detector_3, 0, id_detector_yolo_v3_Reshape_10, 0); + + NodeID id_detector_yolo_v3_split_2 = _graph.add_node( + 4, + -1, + std::vector { 2, 2, 1, 80 }); + INode *node_detector_yolo_v3_split_2 = _graph.node(id_detector_yolo_v3_split_2); + node_detector_yolo_v3_split_2->set_common_node_parameters(NodeParams{ "detector_yolo_v3_split_2", target }); + _graph.add_connection(id_detector_yolo_v3_Reshape_10, 0, id_detector_yolo_v3_split_2, 0); + + NodeID id_detector_yolo_v3_Sigmoid_6 = _graph.add_node( + ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::LOGISTIC, 0, 0 }); + INode *node_detector_yolo_v3_Sigmoid_6 = _graph.node(id_detector_yolo_v3_Sigmoid_6); + node_detector_yolo_v3_Sigmoid_6->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Sigmoid_6", target }); + _graph.add_connection(id_detector_yolo_v3_split_2, 0, id_detector_yolo_v3_Sigmoid_6, 0); + + NodeID id_detector_yolo_v3_add_2 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Add, + QuantizationInfo() }); + INode *node_detector_yolo_v3_add_2 = _graph.node(id_detector_yolo_v3_add_2); + node_detector_yolo_v3_add_2->set_common_node_parameters(NodeParams{ "detector_yolo_v3_add_2", target }); + _graph.add_connection(id_detector_yolo_v3_Sigmoid_6, 0, id_detector_yolo_v3_add_2, 0); + _graph.add_connection(id_detector_yolo_v3_Reshape_11, 0, id_detector_yolo_v3_add_2, 1); + + NodeID id_detector_yolo_v3_mul_6 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Mul, + QuantizationInfo() }); + INode *node_detector_yolo_v3_mul_6 = _graph.node(id_detector_yolo_v3_mul_6); + node_detector_yolo_v3_mul_6->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_6", target }); + _graph.add_connection(id_detector_yolo_v3_add_2, 0, id_detector_yolo_v3_mul_6, 0); + _graph.add_connection(id_detector_yolo_v3_mul_6_y, 0, id_detector_yolo_v3_mul_6, 1); + + NodeID id_detector_yolo_v3_Sigmoid_7 = _graph.add_node( + ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::LOGISTIC, 0, 0 }); + INode *node_detector_yolo_v3_Sigmoid_7 = _graph.node(id_detector_yolo_v3_Sigmoid_7); + node_detector_yolo_v3_Sigmoid_7->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Sigmoid_7", target }); + _graph.add_connection(id_detector_yolo_v3_split_2, 2, id_detector_yolo_v3_Sigmoid_7, 0); + + NodeID id_detector_yolo_v3_Exp_2 = _graph.add_node( + descriptors::UnaryEltwiseLayerDescriptor + { + UnaryEltwiseOperation::Exp, + QuantizationInfo() }); + INode *node_detector_yolo_v3_Exp_2 = _graph.node(id_detector_yolo_v3_Exp_2); + node_detector_yolo_v3_Exp_2->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Exp_2", target }); + _graph.add_connection(id_detector_yolo_v3_split_2, 1, id_detector_yolo_v3_Exp_2, 0); + + NodeID id_detector_yolo_v3_mul_8 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Mul, + QuantizationInfo() }); + INode *node_detector_yolo_v3_mul_8 = _graph.node(id_detector_yolo_v3_mul_8); + node_detector_yolo_v3_mul_8->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_8", target }); + _graph.add_connection(id_detector_yolo_v3_Exp_2, 0, id_detector_yolo_v3_mul_8, 0); + _graph.add_connection(id_detector_yolo_v3_mul_7, 0, id_detector_yolo_v3_mul_8, 1); + + NodeID id_detector_yolo_v3_Sigmoid_8 = _graph.add_node( + ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::LOGISTIC, 0, 0 }); + INode *node_detector_yolo_v3_Sigmoid_8 = _graph.node(id_detector_yolo_v3_Sigmoid_8); + node_detector_yolo_v3_Sigmoid_8->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Sigmoid_8", target }); + _graph.add_connection(id_detector_yolo_v3_split_2, 3, id_detector_yolo_v3_Sigmoid_8, 0); + + NodeID id_detector_yolo_v3_concat_8 = _graph.add_node( + 4, + descriptors::ConcatLayerDescriptor{ DataLayoutDimension::HEIGHT }); + INode *node_detector_yolo_v3_concat_8 = _graph.node(id_detector_yolo_v3_concat_8); + node_detector_yolo_v3_concat_8->set_common_node_parameters(NodeParams{ "detector_yolo_v3_concat_8", target }); + _graph.add_connection(id_detector_yolo_v3_mul_6, 0, id_detector_yolo_v3_concat_8, 0); + _graph.add_connection(id_detector_yolo_v3_mul_8, 0, id_detector_yolo_v3_concat_8, 1); + _graph.add_connection(id_detector_yolo_v3_Sigmoid_7, 0, id_detector_yolo_v3_concat_8, 2); + _graph.add_connection(id_detector_yolo_v3_Sigmoid_8, 0, id_detector_yolo_v3_concat_8, 3); + + NodeID id_input_to_detector_2 = _graph.add_node( + TensorDescriptor + { + TensorShape{ 255, 26, 26, 1 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_input_to_detector_2 = _graph.node(id_input_to_detector_2); + node_input_to_detector_2->set_common_node_parameters(NodeParams{ "input_to_detector_2", target }); + node_input_to_detector_2->output(0)->set_accessor(support::cpp14::make_unique()); + + NodeID id_detector_yolo_v3_Reshape_6 = _graph.add_node( + TensorShape{ 1, 2028, 85 }); + INode *node_detector_yolo_v3_Reshape_6 = _graph.node(id_detector_yolo_v3_Reshape_6); + node_detector_yolo_v3_Reshape_6->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Reshape_6", target }); + _graph.add_connection(id_input_to_detector_2, 0, id_detector_yolo_v3_Reshape_6, 0); + + NodeID id_detector_yolo_v3_split_1 = _graph.add_node( + 4, + -1, + std::vector { 2, 2, 1, 80 }); + INode *node_detector_yolo_v3_split_1 = _graph.node(id_detector_yolo_v3_split_1); + node_detector_yolo_v3_split_1->set_common_node_parameters(NodeParams{ "detector_yolo_v3_split_1", target }); + _graph.add_connection(id_detector_yolo_v3_Reshape_6, 0, id_detector_yolo_v3_split_1, 0); + + NodeID id_detector_yolo_v3_Sigmoid_3 = _graph.add_node( + ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::LOGISTIC, 0, 0 }); + INode *node_detector_yolo_v3_Sigmoid_3 = _graph.node(id_detector_yolo_v3_Sigmoid_3); + node_detector_yolo_v3_Sigmoid_3->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Sigmoid_3", target }); + _graph.add_connection(id_detector_yolo_v3_split_1, 0, id_detector_yolo_v3_Sigmoid_3, 0); + + NodeID id_detector_yolo_v3_add_1 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Add, + QuantizationInfo() }); + INode *node_detector_yolo_v3_add_1 = _graph.node(id_detector_yolo_v3_add_1); + node_detector_yolo_v3_add_1->set_common_node_parameters(NodeParams{ "detector_yolo_v3_add_1", target }); + _graph.add_connection(id_detector_yolo_v3_Sigmoid_3, 0, id_detector_yolo_v3_add_1, 0); + _graph.add_connection(id_detector_yolo_v3_Reshape_7, 0, id_detector_yolo_v3_add_1, 1); + + NodeID id_detector_yolo_v3_mul_3 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Mul, + QuantizationInfo() }); + INode *node_detector_yolo_v3_mul_3 = _graph.node(id_detector_yolo_v3_mul_3); + node_detector_yolo_v3_mul_3->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_3", target }); + _graph.add_connection(id_detector_yolo_v3_add_1, 0, id_detector_yolo_v3_mul_3, 0); + _graph.add_connection(id_detector_yolo_v3_mul_3_y, 0, id_detector_yolo_v3_mul_3, 1); + + NodeID id_detector_yolo_v3_Sigmoid_4 = _graph.add_node( + ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::LOGISTIC, 0, 0 }); + INode *node_detector_yolo_v3_Sigmoid_4 = _graph.node(id_detector_yolo_v3_Sigmoid_4); + node_detector_yolo_v3_Sigmoid_4->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Sigmoid_4", target }); + _graph.add_connection(id_detector_yolo_v3_split_1, 2, id_detector_yolo_v3_Sigmoid_4, 0); + + NodeID id_detector_yolo_v3_Exp_1 = _graph.add_node( + descriptors::UnaryEltwiseLayerDescriptor + { + UnaryEltwiseOperation::Exp, + QuantizationInfo() }); + INode *node_detector_yolo_v3_Exp_1 = _graph.node(id_detector_yolo_v3_Exp_1); + node_detector_yolo_v3_Exp_1->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Exp_1", target }); + _graph.add_connection(id_detector_yolo_v3_split_1, 1, id_detector_yolo_v3_Exp_1, 0); + + NodeID id_detector_yolo_v3_mul_5 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Mul, + QuantizationInfo() }); + INode *node_detector_yolo_v3_mul_5 = _graph.node(id_detector_yolo_v3_mul_5); + node_detector_yolo_v3_mul_5->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_5", target }); + _graph.add_connection(id_detector_yolo_v3_Exp_1, 0, id_detector_yolo_v3_mul_5, 0); + _graph.add_connection(id_detector_yolo_v3_mul_4, 0, id_detector_yolo_v3_mul_5, 1); + + NodeID id_detector_yolo_v3_Sigmoid_5 = _graph.add_node( + ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::LOGISTIC, 0, 0 }); + INode *node_detector_yolo_v3_Sigmoid_5 = _graph.node(id_detector_yolo_v3_Sigmoid_5); + node_detector_yolo_v3_Sigmoid_5->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Sigmoid_5", target }); + _graph.add_connection(id_detector_yolo_v3_split_1, 3, id_detector_yolo_v3_Sigmoid_5, 0); + + NodeID id_detector_yolo_v3_concat_5 = _graph.add_node( + 4, + descriptors::ConcatLayerDescriptor{ DataLayoutDimension::HEIGHT }); + INode *node_detector_yolo_v3_concat_5 = _graph.node(id_detector_yolo_v3_concat_5); + node_detector_yolo_v3_concat_5->set_common_node_parameters(NodeParams{ "detector_yolo_v3_concat_5", target }); + _graph.add_connection(id_detector_yolo_v3_mul_3, 0, id_detector_yolo_v3_concat_5, 0); + _graph.add_connection(id_detector_yolo_v3_mul_5, 0, id_detector_yolo_v3_concat_5, 1); + _graph.add_connection(id_detector_yolo_v3_Sigmoid_4, 0, id_detector_yolo_v3_concat_5, 2); + _graph.add_connection(id_detector_yolo_v3_Sigmoid_5, 0, id_detector_yolo_v3_concat_5, 3); + + NodeID id_input_to_detector_1 = _graph.add_node( + TensorDescriptor + { + TensorShape{ 255, 13, 13, 1 }, + DataType::F32, + QuantizationInfo(), + DataLayout::NHWC }); + INode *node_input_to_detector_1 = _graph.node(id_input_to_detector_1); + node_input_to_detector_1->set_common_node_parameters(NodeParams{ "input_to_detector_1", target }); + node_input_to_detector_1->output(0)->set_accessor(support::cpp14::make_unique()); + + NodeID id_detector_yolo_v3_Reshape_2 = _graph.add_node( + TensorShape{ 1, 507, 85 }); + INode *node_detector_yolo_v3_Reshape_2 = _graph.node(id_detector_yolo_v3_Reshape_2); + node_detector_yolo_v3_Reshape_2->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Reshape_2", target }); + _graph.add_connection(id_input_to_detector_1, 0, id_detector_yolo_v3_Reshape_2, 0); + + NodeID id_detector_yolo_v3_split = _graph.add_node( + 4, + -1, + std::vector { 2, 2, 1, 80 }); + INode *node_detector_yolo_v3_split = _graph.node(id_detector_yolo_v3_split); + node_detector_yolo_v3_split->set_common_node_parameters(NodeParams{ "detector_yolo_v3_split", target }); + _graph.add_connection(id_detector_yolo_v3_Reshape_2, 0, id_detector_yolo_v3_split, 0); + + NodeID id_detector_yolo_v3_Sigmoid = _graph.add_node( + ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::LOGISTIC, 0, 0 }); + INode *node_detector_yolo_v3_Sigmoid = _graph.node(id_detector_yolo_v3_Sigmoid); + node_detector_yolo_v3_Sigmoid->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Sigmoid", target }); + _graph.add_connection(id_detector_yolo_v3_split, 0, id_detector_yolo_v3_Sigmoid, 0); + + NodeID id_detector_yolo_v3_add = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Add, + QuantizationInfo() }); + INode *node_detector_yolo_v3_add = _graph.node(id_detector_yolo_v3_add); + node_detector_yolo_v3_add->set_common_node_parameters(NodeParams{ "detector_yolo_v3_add", target }); + _graph.add_connection(id_detector_yolo_v3_Sigmoid, 0, id_detector_yolo_v3_add, 0); + _graph.add_connection(id_detector_yolo_v3_Reshape_3, 0, id_detector_yolo_v3_add, 1); + + NodeID id_detector_yolo_v3_mul = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Mul, + QuantizationInfo() }); + INode *node_detector_yolo_v3_mul = _graph.node(id_detector_yolo_v3_mul); + node_detector_yolo_v3_mul->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul", target }); + _graph.add_connection(id_detector_yolo_v3_add, 0, id_detector_yolo_v3_mul, 0); + _graph.add_connection(id_detector_yolo_v3_mul_y, 0, id_detector_yolo_v3_mul, 1); + + NodeID id_detector_yolo_v3_Sigmoid_1 = _graph.add_node( + ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::LOGISTIC, 0, 0 }); + INode *node_detector_yolo_v3_Sigmoid_1 = _graph.node(id_detector_yolo_v3_Sigmoid_1); + node_detector_yolo_v3_Sigmoid_1->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Sigmoid_1", target }); + _graph.add_connection(id_detector_yolo_v3_split, 2, id_detector_yolo_v3_Sigmoid_1, 0); + + NodeID id_detector_yolo_v3_Exp = _graph.add_node( + descriptors::UnaryEltwiseLayerDescriptor + { + UnaryEltwiseOperation::Exp, + QuantizationInfo() }); + INode *node_detector_yolo_v3_Exp = _graph.node(id_detector_yolo_v3_Exp); + node_detector_yolo_v3_Exp->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Exp", target }); + _graph.add_connection(id_detector_yolo_v3_split, 1, id_detector_yolo_v3_Exp, 0); + + NodeID id_detector_yolo_v3_mul_2 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Mul, + QuantizationInfo() }); + INode *node_detector_yolo_v3_mul_2 = _graph.node(id_detector_yolo_v3_mul_2); + node_detector_yolo_v3_mul_2->set_common_node_parameters(NodeParams{ "detector_yolo_v3_mul_2", target }); + _graph.add_connection(id_detector_yolo_v3_Exp, 0, id_detector_yolo_v3_mul_2, 0); + _graph.add_connection(id_detector_yolo_v3_mul_1, 0, id_detector_yolo_v3_mul_2, 1); + + NodeID id_detector_yolo_v3_Sigmoid_2 = _graph.add_node( + ActivationLayerInfo{ ActivationLayerInfo::ActivationFunction::LOGISTIC, 0, 0 }); + INode *node_detector_yolo_v3_Sigmoid_2 = _graph.node(id_detector_yolo_v3_Sigmoid_2); + node_detector_yolo_v3_Sigmoid_2->set_common_node_parameters(NodeParams{ "detector_yolo_v3_Sigmoid_2", target }); + _graph.add_connection(id_detector_yolo_v3_split, 3, id_detector_yolo_v3_Sigmoid_2, 0); + + NodeID id_detector_yolo_v3_concat_2 = _graph.add_node( + 4, + descriptors::ConcatLayerDescriptor{ DataLayoutDimension::HEIGHT }); + INode *node_detector_yolo_v3_concat_2 = _graph.node(id_detector_yolo_v3_concat_2); + node_detector_yolo_v3_concat_2->set_common_node_parameters(NodeParams{ "detector_yolo_v3_concat_2", target }); + _graph.add_connection(id_detector_yolo_v3_mul, 0, id_detector_yolo_v3_concat_2, 0); + _graph.add_connection(id_detector_yolo_v3_mul_2, 0, id_detector_yolo_v3_concat_2, 1); + _graph.add_connection(id_detector_yolo_v3_Sigmoid_1, 0, id_detector_yolo_v3_concat_2, 2); + _graph.add_connection(id_detector_yolo_v3_Sigmoid_2, 0, id_detector_yolo_v3_concat_2, 3); + + NodeID id_detector_yolo_v3_concat_9 = _graph.add_node( + 3, + descriptors::ConcatLayerDescriptor{ DataLayoutDimension::WIDTH }); + INode *node_detector_yolo_v3_concat_9 = _graph.node(id_detector_yolo_v3_concat_9); + node_detector_yolo_v3_concat_9->set_common_node_parameters(NodeParams{ "detector_yolo_v3_concat_9", target }); + _graph.add_connection(id_detector_yolo_v3_concat_2, 0, id_detector_yolo_v3_concat_9, 0); + _graph.add_connection(id_detector_yolo_v3_concat_5, 0, id_detector_yolo_v3_concat_9, 1); + _graph.add_connection(id_detector_yolo_v3_concat_8, 0, id_detector_yolo_v3_concat_9, 2); + + NodeID id_split = _graph.add_node( + 5, + -1, + std::vector { 1, 1, 1, 1, -1 }); + INode *node_split = _graph.node(id_split); + node_split->set_common_node_parameters(NodeParams{ "split", target }); + _graph.add_connection(id_detector_yolo_v3_concat_9, 0, id_split, 0); + + NodeID id_truediv = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Mul, + QuantizationInfo() }); + INode *node_truediv = _graph.node(id_truediv); + node_truediv->set_common_node_parameters(NodeParams{ "truediv", target }); + _graph.add_connection(id_split, 2, id_truediv, 0); + _graph.add_connection(id_ConstantFolding_truediv_recip, 0, id_truediv, 1); + + NodeID id_sub = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Sub, + QuantizationInfo() }); + INode *node_sub = _graph.node(id_sub); + node_sub->set_common_node_parameters(NodeParams{ "sub", target }); + _graph.add_connection(id_split, 0, id_sub, 0); + _graph.add_connection(id_truediv, 0, id_sub, 1); + + NodeID id_add = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Add, + QuantizationInfo() }); + INode *node_add = _graph.node(id_add); + node_add->set_common_node_parameters(NodeParams{ "add", target }); + _graph.add_connection(id_split, 0, id_add, 0); + _graph.add_connection(id_truediv, 0, id_add, 1); + + NodeID id_truediv_1 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Mul, + QuantizationInfo() }); + INode *node_truediv_1 = _graph.node(id_truediv_1); + node_truediv_1->set_common_node_parameters(NodeParams{ "truediv_1", target }); + _graph.add_connection(id_split, 3, id_truediv_1, 0); + _graph.add_connection(id_ConstantFolding_truediv_1_recip, 0, id_truediv_1, 1); + + NodeID id_sub_1 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Sub, + QuantizationInfo() }); + INode *node_sub_1 = _graph.node(id_sub_1); + node_sub_1->set_common_node_parameters(NodeParams{ "sub_1", target }); + _graph.add_connection(id_split, 1, id_sub_1, 0); + _graph.add_connection(id_truediv_1, 0, id_sub_1, 1); + + NodeID id_add_1 = _graph.add_node( + descriptors::EltwiseLayerDescriptor + { + EltwiseOperation::Add, + QuantizationInfo() }); + INode *node_add_1 = _graph.node(id_add_1); + node_add_1->set_common_node_parameters(NodeParams{ "add_1", target }); + _graph.add_connection(id_split, 1, id_add_1, 0); + _graph.add_connection(id_truediv_1, 0, id_add_1, 1); + + NodeID id_output_boxes = _graph.add_node( + 5, + descriptors::ConcatLayerDescriptor{ DataLayoutDimension::HEIGHT }); + INode *node_output_boxes = _graph.node(id_output_boxes); + node_output_boxes->set_common_node_parameters(NodeParams{ "output_boxes", target }); + _graph.add_connection(id_sub, 0, id_output_boxes, 0); + _graph.add_connection(id_sub_1, 0, id_output_boxes, 1); + _graph.add_connection(id_add, 0, id_output_boxes, 2); + _graph.add_connection(id_add_1, 0, id_output_boxes, 3); + _graph.add_connection(id_split, 4, id_output_boxes, 4); + + NodeID id_output_140640247016360 = _graph.add_node(); + INode *node_output_140640247016360 = _graph.node(id_output_140640247016360); + node_output_140640247016360->set_common_node_parameters(NodeParams{ "output_140640247016360", target }); + _graph.add_connection(id_output_boxes, 0, id_output_140640247016360, 0); + node_output_140640247016360->input(0)->set_accessor(support::cpp14::make_unique(0)); + + return true; + } + + Graph &graph() + { + return _graph; + } + +private: + Graph _graph; +}; +class GraphYoloV3OutputDetectorExample : public Example +{ +public: + GraphYoloV3OutputDetectorExample() + : cmd_parser(), common_opts(cmd_parser), common_params() + { + } + + bool do_setup(int argc, char **argv) override + { + // Parse arguments + cmd_parser.parse(argc, argv); + cmd_parser.validate(); + + // Consume common parameters + common_params = consume_common_graph_parameters(common_opts); + + // Return when help menu is requested + if(common_params.help) + { + cmd_parser.print_help(argv[0]); + return false; + } + + // Print parameter values + std::cout << common_params << std::endl; + + model.setup(common_params.data_path, common_params.target); + + GraphConfig config; + config.num_threads = common_params.threads; + config.use_tuner = common_params.enable_tuner; + config.tuner_mode = common_params.tuner_mode; + config.tuner_file = common_params.tuner_file; + + context.set_config(config); + + auto pass_manager = create_default_pass_manager(common_params.target, config); + manager.finalize_graph(model.graph(), context, pass_manager, common_params.target); + + return true; + } + + void do_run() override + { + manager.execute_graph(model.graph()); + } + +private: + CommandLineParser cmd_parser; + CommonGraphOptions common_opts; + CommonGraphParams common_params; + + GraphContext context{}; + GraphManager manager{}; + + GraphYoloV3OutputDetector model{}; +}; + +int main(int argc, char **argv) +{ + return run_example(argc, argv); +} diff --git a/src/graph/backends/CL/CLFunctionsFactory.cpp b/src/graph/backends/CL/CLFunctionsFactory.cpp index 312e09a49a..cf494e9a67 100644 --- a/src/graph/backends/CL/CLFunctionsFactory.cpp +++ b/src/graph/backends/CL/CLFunctionsFactory.cpp @@ -65,6 +65,12 @@ struct CLEltwiseFunctions using Multiplication = CLPixelWiseMultiplication; }; +/** Collection of CL unary element-wise functions */ +struct CLUnaryEltwiseFunctions +{ + using Exp = CLExpLayer; +}; + /** Function and tensor types to be used inside a CL fused convolution/batch normalization layer */ struct CLFusedLayerTypes { @@ -252,6 +258,8 @@ std::unique_ptr CLFunctionFactory::create(INode *node, GraphContext & return detail::create_detection_post_process_layer(*polymorphic_downcast(node)); case NodeType::EltwiseLayer: return detail::create_eltwise_layer(*polymorphic_downcast(node)); + case NodeType::UnaryEltwiseLayer: + return detail::create_unary_eltwise_layer(*polymorphic_downcast(node)); case NodeType::FlattenLayer: return detail::create_flatten_layer(*polymorphic_downcast(node)); case NodeType::FullyConnectedLayer: diff --git a/src/graph/backends/CL/CLNodeValidator.cpp b/src/graph/backends/CL/CLNodeValidator.cpp index ddb8e3d1ac..15b54aedee 100644 --- a/src/graph/backends/CL/CLNodeValidator.cpp +++ b/src/graph/backends/CL/CLNodeValidator.cpp @@ -38,6 +38,20 @@ namespace graph { namespace backends { +/** Collection of CL element-wise functions */ +struct CLEltwiseLayerFunctions +{ + using ArithmeticAddition = CLArithmeticAddition; + using ArithmeticSubtraction = CLArithmeticSubtraction; + using PixelWiseMultiplication = CLPixelWiseMultiplication; +}; + +/** Collection of CL unary element-wise functions */ +struct CLUnaryEltwiseLayerFunctions +{ + using ExpLayer = CLExpLayer; +}; + Status CLNodeValidator::validate(INode *node) { if(node == nullptr) @@ -91,6 +105,10 @@ Status CLNodeValidator::validate(INode *node) return detail::validate_upsample_layer(*polymorphic_downcast(node)); case NodeType::YOLOLayer: return detail::validate_yolo_layer(*polymorphic_downcast(node)); + case NodeType::EltwiseLayer: + return detail::validate_eltwise_Layer(*polymorphic_downcast(node)); + case NodeType::UnaryEltwiseLayer: + return detail::validate_unary_eltwise_layer(*polymorphic_downcast(node)); default: return Status{}; } diff --git a/src/graph/backends/NEON/NEFunctionFactory.cpp b/src/graph/backends/NEON/NEFunctionFactory.cpp index 454215e7ec..0b3036cb4e 100644 --- a/src/graph/backends/NEON/NEFunctionFactory.cpp +++ b/src/graph/backends/NEON/NEFunctionFactory.cpp @@ -53,7 +53,7 @@ struct NETargetInfo Target NETargetInfo::TargetType = Target::NEON; -/** Collection of CL convolution functions */ +/** Collection of NEON convolution functions */ struct NEConvolutionLayerFunctions { using GenericConvolutionLayer = NEConvolutionLayer; @@ -62,7 +62,7 @@ struct NEConvolutionLayerFunctions using WinogradConvolutionLayer = NEWinogradConvolutionLayer; }; -/** Collection of CL element-wise functions */ +/** Collection of NEON element-wise functions */ struct NEEltwiseFunctions { using Addition = NEArithmeticAddition; @@ -70,6 +70,12 @@ struct NEEltwiseFunctions using Multiplication = NEPixelWiseMultiplication; }; +/** Collection of NEON unary element-wise functions */ +struct NEUnaryEltwiseFunctions +{ + using Exp = NEExpLayer; +}; + /** Function and tensor types to be used inside a NEON fused convolution/batch normalization layer */ struct NEFusedLayerTypes { @@ -143,6 +149,8 @@ std::unique_ptr NEFunctionFactory::create(INode *node, GraphContext & return detail::create_detection_post_process_layer(*polymorphic_downcast(node)); case NodeType::EltwiseLayer: return detail::create_eltwise_layer(*polymorphic_downcast(node)); + case NodeType::UnaryEltwiseLayer: + return detail::create_unary_eltwise_layer(*polymorphic_downcast(node)); case NodeType::FlattenLayer: return detail::create_flatten_layer(*polymorphic_downcast(node)); case NodeType::FullyConnectedLayer: diff --git a/src/graph/backends/NEON/NENodeValidator.cpp b/src/graph/backends/NEON/NENodeValidator.cpp index 0a3107292b..d4af3133be 100644 --- a/src/graph/backends/NEON/NENodeValidator.cpp +++ b/src/graph/backends/NEON/NENodeValidator.cpp @@ -38,6 +38,20 @@ namespace graph { namespace backends { +/** Collection of NEON element-wise functions */ +struct NEEltwiseLayerFunctions +{ + using ArithmeticAddition = NEArithmeticAddition; + using ArithmeticSubtraction = NEArithmeticSubtraction; + using PixelWiseMultiplication = NEPixelWiseMultiplication; +}; + +/** Collection of NEON unary element-wise functions */ +struct NEUnaryEltwiseLayerFunctions +{ + using ExpLayer = NEExpLayer; +}; + Status NENodeValidator::validate(INode *node) { if(node == nullptr) @@ -91,6 +105,10 @@ Status NENodeValidator::validate(INode *node) return detail::validate_upsample_layer(*polymorphic_downcast(node)); case NodeType::YOLOLayer: return detail::validate_yolo_layer(*polymorphic_downcast(node)); + case NodeType::EltwiseLayer: + return detail::validate_eltwise_Layer(*polymorphic_downcast(node)); + case NodeType::UnaryEltwiseLayer: + return detail::validate_unary_eltwise_layer(*polymorphic_downcast(node)); default: return Status{}; } diff --git a/src/graph/mutators/NodeFusionMutator.cpp b/src/graph/mutators/NodeFusionMutator.cpp index ae53b8ff75..7528520cc7 100644 --- a/src/graph/mutators/NodeFusionMutator.cpp +++ b/src/graph/mutators/NodeFusionMutator.cpp @@ -226,6 +226,12 @@ void fuse_node_with_activation(Graph &g, const Edge *output_edge, const std::set return; } + // EltwiseLayerNode can only be fused when dataype is float + if(n_node->type() == NodeType::EltwiseLayer && !is_data_type_float(n_node->output(0)->desc().data_type)) + { + return; + } + ARM_COMPUTE_LOG_GRAPH_VERBOSE("Fusing node with ID : " << output_edge->producer_id() << " with Activation Layer node with ID : " << output_edge->consumer_id() << std::endl); diff --git a/src/graph/mutators/SplitLayerSubTensorMutator.cpp b/src/graph/mutators/SplitLayerSubTensorMutator.cpp index 3ba73071ed..76180856c3 100644 --- a/src/graph/mutators/SplitLayerSubTensorMutator.cpp +++ b/src/graph/mutators/SplitLayerSubTensorMutator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2019 ARM Limited. + * Copyright (c) 2018-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -82,7 +82,7 @@ void SplitLayerSubTensorMutator::mutate(Graph &g) auto *split_node = arm_compute::utils::cast::polymorphic_downcast(node); - const unsigned int axis = split_node->axis(); + const int axis = split_node->axis(); const unsigned int num_splits = split_node->num_splits(); const bool extend_parent = (axis < 2); @@ -92,7 +92,7 @@ void SplitLayerSubTensorMutator::mutate(Graph &g) Tensor *output_tensor = node->output(i); const TensorShape output_shape = output_tensor->desc().shape; Coordinates coords; - std::tie(std::ignore, coords) = SplitLayerNode::compute_output_descriptor(input_tensor->desc(), num_splits, axis, i); + std::tie(std::ignore, coords) = split_node->compute_output_descriptor(input_tensor->desc(), num_splits, axis, i); backends::IDeviceBackend &backend = backends::BackendRegistry::get().get_backend(output_tensor->desc().target); std::unique_ptr handle = backend.create_subtensor(input_tensor->handle(), output_shape, coords, extend_parent); diff --git a/src/graph/nodes/EltwiseLayerNode.cpp b/src/graph/nodes/EltwiseLayerNode.cpp index 92d183e693..40dcef13fb 100644 --- a/src/graph/nodes/EltwiseLayerNode.cpp +++ b/src/graph/nodes/EltwiseLayerNode.cpp @@ -57,6 +57,11 @@ ActivationLayerInfo EltwiseLayerNode::fused_activation() const return descriptor.fused_activation; } +QuantizationInfo EltwiseLayerNode::output_quant_info() const +{ + return descriptor.out_quant_info; +} + void EltwiseLayerNode::set_fused_activation(ActivationLayerInfo fused_activation) { descriptor.fused_activation = fused_activation; @@ -100,5 +105,62 @@ void EltwiseLayerNode::accept(INodeVisitor &v) { v.visit(*this); } + +UnaryEltwiseLayerNode::UnaryEltwiseLayerNode(const descriptors::UnaryEltwiseLayerDescriptor &descriptor) + : descriptor(descriptor) +{ + _input_edges.resize(1, EmptyEdgeID); + _outputs.resize(1, NullTensorID); +} + +descriptors::UnaryEltwiseLayerDescriptor UnaryEltwiseLayerNode::eltwise_descriptor() const +{ + return descriptor; +} + +void UnaryEltwiseLayerNode::set_fused_activation(ActivationLayerInfo fused_activation) +{ + descriptor.fused_activation = fused_activation; +} + +bool UnaryEltwiseLayerNode::forward_descriptors() +{ + if((input_id(0) != NullTensorID) && (output_id(0) != NullTensorID)) + { + Tensor *dst = output(0); + ARM_COMPUTE_ERROR_ON(dst == nullptr); + dst->desc() = configure_output(0); + return true; + } + return false; +} + +TensorDescriptor UnaryEltwiseLayerNode::configure_output(size_t idx) const +{ + ARM_COMPUTE_UNUSED(idx); + + const Tensor *src = input(0); + ARM_COMPUTE_ERROR_ON(src == nullptr); + + auto output_info = src->desc(); + + if(!descriptor.out_quant_info.empty()) + { + output_info.set_quantization_info(descriptor.out_quant_info); + } + + return output_info; +} + +NodeType UnaryEltwiseLayerNode::type() const +{ + return NodeType::UnaryEltwiseLayer; +} + +void UnaryEltwiseLayerNode::accept(INodeVisitor &v) +{ + v.visit(*this); +} + } // namespace graph } // namespace arm_compute diff --git a/src/graph/nodes/SplitLayerNode.cpp b/src/graph/nodes/SplitLayerNode.cpp index 5d46c9dcc9..7bc69c4667 100644 --- a/src/graph/nodes/SplitLayerNode.cpp +++ b/src/graph/nodes/SplitLayerNode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 ARM Limited. + * Copyright (c) 2018-2020 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -23,6 +23,7 @@ */ #include "arm_compute/graph/nodes/SplitLayerNode.h" +#include "arm_compute/core/Helpers.h" #include "arm_compute/core/Utils.h" #include "arm_compute/graph/Graph.h" #include "arm_compute/graph/INodeVisitor.h" @@ -31,8 +32,8 @@ namespace arm_compute { namespace graph { -SplitLayerNode::SplitLayerNode(unsigned int num_splits, unsigned int axis) - : _num_splits(num_splits), _axis(axis) +SplitLayerNode::SplitLayerNode(unsigned int num_splits, int axis, std::vector size_splits) + : _num_splits(num_splits), _axis(axis), _size_splits(size_splits) { _input_edges.resize(1, EmptyEdgeID); _outputs.resize(num_splits, NullTensorID); @@ -49,15 +50,34 @@ unsigned int SplitLayerNode::axis() const } std::pair SplitLayerNode::compute_output_descriptor(const TensorDescriptor &input_descriptor, - unsigned int num_splits, unsigned int axis, unsigned int idx) + unsigned int num_splits, int axis, unsigned int idx) { - const unsigned int split_size = input_descriptor.shape[axis] / num_splits; - + // Handle negative axis, negative index is used to specify axis from the end (e.g. -1 for the last axis). + int num_dimension = static_cast(input_descriptor.shape.num_dimensions()); + int tmp_axis = wrap_around(axis, num_dimension); + Coordinates coords; TensorDescriptor output_descriptor = input_descriptor; - output_descriptor.shape.set(axis, split_size); - - Coordinates coords; - coords.set(axis, idx * split_size); + int split_size = input_descriptor.shape[tmp_axis] / num_splits; + if(_size_splits.empty()) + { + output_descriptor.shape.set(tmp_axis, split_size); + coords.set(tmp_axis, idx * split_size); + } + else + { + int split_size = _size_splits[idx]; + if(split_size == -1) + { + split_size = input_descriptor.shape[tmp_axis]; + for(unsigned int i = 0; i < _size_splits.size() - 1; ++i) + split_size -= _size_splits[i]; + } + output_descriptor.shape.set(tmp_axis, split_size); + int coord_value = 0; + for(unsigned int i = 0; i < idx; ++i) + coord_value += _size_splits[i]; + coords.set(tmp_axis, coord_value); + } return std::make_pair(output_descriptor, coords); } @@ -89,18 +109,39 @@ TensorDescriptor SplitLayerNode::configure_output(size_t idx) const const Tensor *src = input(0); ARM_COMPUTE_ERROR_ON(src == nullptr); - TensorDescriptor output_info; - std::tie(output_info, std::ignore) = compute_output_descriptor(src->desc(), _num_splits, _axis, idx); + TensorDescriptor input_descriptor = src->desc(); + TensorDescriptor output_descriptor = input_descriptor; - return output_info; + // Handle negative axis, negative index is used to specify axis from the end (e.g. -1 for the last axis). + int num_dimension = static_cast(src->desc().shape.num_dimensions()); + int tmp_axis = wrap_around(_axis, num_dimension); + + int split_size = (_size_splits.empty()) ? (input_descriptor.shape[tmp_axis] / _num_splits) : _size_splits[idx]; + if(split_size == -1) + { + split_size = input_descriptor.shape[tmp_axis]; + for(unsigned int i = 0; i < _size_splits.size() - 1; ++i) + split_size -= _size_splits[i]; + } + output_descriptor.shape.set(tmp_axis, split_size); + + return output_descriptor; } Status SplitLayerNode::validate() const { const Tensor *src = input(0); ARM_COMPUTE_RETURN_ERROR_ON(src == nullptr); - ARM_COMPUTE_RETURN_ERROR_ON(_axis >= src->desc().shape.num_dimensions()); - ARM_COMPUTE_RETURN_ERROR_ON_MSG(src->desc().shape[_axis] % _num_splits, "Split should be exact"); + int num_dimension = static_cast(src->desc().shape.num_dimensions()); + ARM_COMPUTE_RETURN_ERROR_ON(_axis < (-num_dimension) || _axis >= num_dimension); + + // Handle negative axis, negative index is used to specify axis from the end (e.g. -1 for the last axis). + int tmp_axis = wrap_around(_axis, num_dimension); + + if(_size_splits.empty()) + { + ARM_COMPUTE_RETURN_ERROR_ON_MSG(src->desc().shape[tmp_axis] % _num_splits, "Split should be exact"); + } return Status{}; } -- cgit v1.2.1