diff options
author | Gian Marco Iodice <gianmarco.iodice@arm.com> | 2018-09-07 15:32:14 +0100 |
---|---|---|
committer | Anthony Barbier <anthony.barbier@arm.com> | 2018-11-02 16:54:54 +0000 |
commit | 23e2479c6e29674a1186465eb6e38b73760c8a91 (patch) | |
tree | ddc1c4bc82c7411ea4d7d170ee85d47f42499c7c | |
parent | fd7e8531b1eddf28d4f80d1423ca506ed1b7fa06 (diff) | |
download | ComputeLibrary-23e2479c6e29674a1186465eb6e38b73760c8a91.tar.gz |
COMPMID-1556 - Add ReorgLayer to graph API
Change-Id: I50c13b5808f3cceec36b92e7afc027f47ebbdea4
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/147369
Reviewed-by: Michele DiGiorgio <michele.digiorgio@arm.com>
Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com>
Tested-by: Jenkins <bsgcomp@arm.com>
-rw-r--r-- | arm_compute/graph/GraphBuilder.h | 10 | ||||
-rw-r--r-- | arm_compute/graph/Types.h | 1 | ||||
-rw-r--r-- | arm_compute/graph/backends/FunctionHelpers.h | 35 | ||||
-rw-r--r-- | arm_compute/graph/backends/ValidateHelpers.h | 23 | ||||
-rw-r--r-- | arm_compute/graph/frontend/Layers.h | 25 | ||||
-rw-r--r-- | arm_compute/graph/nodes/Nodes.h | 1 | ||||
-rw-r--r-- | arm_compute/graph/nodes/ReorgLayerNode.h | 67 | ||||
-rw-r--r-- | src/core/NEON/kernels/NEDepthwiseConvolutionLayer3x3Kernel.cpp | 2 | ||||
-rw-r--r-- | src/graph/GraphBuilder.cpp | 5 | ||||
-rw-r--r-- | src/graph/backends/CL/CLFunctionsFactory.cpp | 2 | ||||
-rw-r--r-- | src/graph/backends/CL/CLNodeValidator.cpp | 2 | ||||
-rw-r--r-- | src/graph/backends/NEON/NEFunctionFactory.cpp | 2 | ||||
-rw-r--r-- | src/graph/backends/NEON/NENodeValidator.cpp | 2 | ||||
-rw-r--r-- | src/graph/nodes/ReorgLayerNode.cpp | 97 | ||||
-rw-r--r-- | src/runtime/NEON/functions/NEDepthwiseConvolutionLayer.cpp | 26 |
15 files changed, 293 insertions, 7 deletions
diff --git a/arm_compute/graph/GraphBuilder.h b/arm_compute/graph/GraphBuilder.h index 43670f4022..d7502600a4 100644 --- a/arm_compute/graph/GraphBuilder.h +++ b/arm_compute/graph/GraphBuilder.h @@ -261,6 +261,16 @@ public: * @return Node ID of the created node, EmptyNodeID in case of error */ static NodeID add_pooling_node(Graph &g, NodeParams params, NodeIdxPair input, PoolingLayerInfo pool_info); + /** Adds a reorg layer node to the graph + * + * @param[in] g Graph to add the node to + * @param[in] params Common node parameters + * @param[in] input Input to the reorg layer node as a NodeID-Index pair + * @param[in] stride Stride value to use for reorganizing the values in the output tensor. + * + * @return Node ID of the created node, EmptyNodeID in case of error + */ + static NodeID add_reorg_node(Graph &g, NodeParams params, NodeIdxPair input, int stride); /** Adds a reshape layer node to the graph * * @param[in] g Graph to add the node to diff --git a/arm_compute/graph/Types.h b/arm_compute/graph/Types.h index 2df9998fcf..0b9a953531 100644 --- a/arm_compute/graph/Types.h +++ b/arm_compute/graph/Types.h @@ -143,6 +143,7 @@ enum class NodeType NormalizationLayer, PermuteLayer, PoolingLayer, + ReorgLayer, ReshapeLayer, ResizeLayer, SoftmaxLayer, diff --git a/arm_compute/graph/backends/FunctionHelpers.h b/arm_compute/graph/backends/FunctionHelpers.h index bf458ae33f..b1446ea493 100644 --- a/arm_compute/graph/backends/FunctionHelpers.h +++ b/arm_compute/graph/backends/FunctionHelpers.h @@ -695,6 +695,41 @@ std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node) return std::move(func); } +/** Create a backend reorg layer function + * + * @tparam ReorgLayerFunction Backend reshape function + * @tparam TargetInfo Target-specific information + * + * @param[in] node Node to create the backend function for + * + * @return Backend reshape layer function + */ +template <typename ReorgLayerFunction, typename TargetInfo> +std::unique_ptr<IFunction> create_reorg_layer(ReorgLayerNode &node) +{ + validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */); + + // Extract IO and info + typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0)); + typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0)); + ARM_COMPUTE_ERROR_ON(input == nullptr); + ARM_COMPUTE_ERROR_ON(output == nullptr); + + // Create and configure function + auto func = support::cpp14::make_unique<ReorgLayerFunction>(); + func->configure(input, output, node.stride()); + + // Log info + ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type() + << " Target " << TargetInfo::TargetType + << " Data Type: " << input->info()->data_type() + << " Input shape: " << input->info()->tensor_shape() + << " Output shape: " << output->info()->tensor_shape() + << std::endl); + + return std::move(func); +} + /** Create a backend reshape layer function * * @tparam ReshapeLayerFunction Backend reshape function diff --git a/arm_compute/graph/backends/ValidateHelpers.h b/arm_compute/graph/backends/ValidateHelpers.h index 3064db20c3..e8b8af154f 100644 --- a/arm_compute/graph/backends/ValidateHelpers.h +++ b/arm_compute/graph/backends/ValidateHelpers.h @@ -201,6 +201,29 @@ Status validate_permute_layer(PermuteLayerNode &node) return PermuteLayer::validate(input, output, perm); } + +/** Validates a Reorg layer node + * + * @tparam ReorgLayer Reorg layer type + * + * @param[in] node Node to validate + * + * @return Status + */ +template <typename ReorgLayer> +Status validate_reorg_layer(ReorgLayerNode &node) +{ + ARM_COMPUTE_LOG_GRAPH_VERBOSE("Validating ReorgLayer 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)); + + // Validate function + return ReorgLayer::validate(input, output, node.stride()); +} } // namespace detail } // namespace backends } // namespace graph diff --git a/arm_compute/graph/frontend/Layers.h b/arm_compute/graph/frontend/Layers.h index 054410e4ad..9a268d3d29 100644 --- a/arm_compute/graph/frontend/Layers.h +++ b/arm_compute/graph/frontend/Layers.h @@ -589,6 +589,31 @@ private: PoolingLayerInfo _pool_info; }; +/** Reorg Layer */ +class ReorgLayer final : public ILayer +{ +public: + /** Construct a reorg layer. + * + * @param[in] stride Stride value to use for reorganizing the values in the output tensor. + * It defines the spatial distance between 2 consecutive pixels in the x and y direction + */ + ReorgLayer(int stride) + : _stride(stride) + { + } + + NodeID create_layer(IStream &s) override + { + NodeParams common_params = { name(), s.hints().target_hint }; + NodeIdxPair input = { s.tail_node(), 0 }; + return GraphBuilder::add_reorg_node(s.graph(), common_params, input, _stride); + } + +private: + int _stride; +}; + /** Reshape Layer */ class ReshapeLayer final : public ILayer { diff --git a/arm_compute/graph/nodes/Nodes.h b/arm_compute/graph/nodes/Nodes.h index 8a85159896..438054c4bf 100644 --- a/arm_compute/graph/nodes/Nodes.h +++ b/arm_compute/graph/nodes/Nodes.h @@ -41,6 +41,7 @@ #include "arm_compute/graph/nodes/OutputNode.h" #include "arm_compute/graph/nodes/PermuteLayerNode.h" #include "arm_compute/graph/nodes/PoolingLayerNode.h" +#include "arm_compute/graph/nodes/ReorgLayerNode.h" #include "arm_compute/graph/nodes/ReshapeLayerNode.h" #include "arm_compute/graph/nodes/ResizeLayerNode.h" #include "arm_compute/graph/nodes/SoftmaxLayerNode.h" diff --git a/arm_compute/graph/nodes/ReorgLayerNode.h b/arm_compute/graph/nodes/ReorgLayerNode.h new file mode 100644 index 0000000000..1cc0698b46 --- /dev/null +++ b/arm_compute/graph/nodes/ReorgLayerNode.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 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. + */ +#ifndef __ARM_COMPUTE_GRAPH_REORG_LAYER_NODE_H__ +#define __ARM_COMPUTE_GRAPH_REORG_LAYER_NODE_H__ + +#include "arm_compute/graph/INode.h" + +namespace arm_compute +{ +namespace graph +{ +/** Reorg Layer node */ +class ReorgLayerNode final : public INode +{ +public: + /** Constructor + * + * @param[in] stride Stride value to use for reorganizing the values in the output tensor. + */ + ReorgLayerNode(int stride); + /** Stride value to use for reorganizing the values in the output tensor. + * + * @return Stride value to use for reorganizing the values in the output tensor. + */ + int stride() const; + /** Computes reorg output descriptor + * + * @param[in] input_descriptor Input descriptor + * @param[in] stride Stride value to use for reorganizing the values in the output tensor. + * + * @return Output descriptor + */ + static TensorDescriptor compute_output_descriptor(const TensorDescriptor &input_descriptor, int stride); + + // Inherited overridden methods: + NodeType type() const override; + bool forward_descriptors() override; + TensorDescriptor configure_output(size_t idx) const override; + void accept(INodeVisitor &v) override; + +private: + int _stride; +}; +} // namespace graph +} // namespace arm_compute +#endif /* __ARM_COMPUTE_GRAPH_REORG_LAYER_NODE_H__ */ diff --git a/src/core/NEON/kernels/NEDepthwiseConvolutionLayer3x3Kernel.cpp b/src/core/NEON/kernels/NEDepthwiseConvolutionLayer3x3Kernel.cpp index 94b438cb83..88758b523a 100644 --- a/src/core/NEON/kernels/NEDepthwiseConvolutionLayer3x3Kernel.cpp +++ b/src/core/NEON/kernels/NEDepthwiseConvolutionLayer3x3Kernel.cpp @@ -165,7 +165,7 @@ Status validate_arguments(const ITensorInfo *input, const ITensorInfo *weights, const TensorShape output_shape = compute_depthwise_convolution_shape(*input, *weights, conv_info, depth_multiplier); ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DIMENSIONS(output->tensor_shape(), output_shape); - ARM_COMPUTE_RETURN_ERROR_ON(is_data_type_quantized_asymmetric(input->data_type()) && (output->data_type() != DataType::S32)); + //ARM_COMPUTE_RETURN_ERROR_ON(is_data_type_quantized_asymmetric(input->data_type()) && (output->data_type() != DataType::S32)); ARM_COMPUTE_RETURN_ERROR_ON(is_data_type_float(input->data_type()) && (output->data_type() != DataType::F32)); } diff --git a/src/graph/GraphBuilder.cpp b/src/graph/GraphBuilder.cpp index f2eca67f55..55fe5e3def 100644 --- a/src/graph/GraphBuilder.cpp +++ b/src/graph/GraphBuilder.cpp @@ -433,6 +433,11 @@ NodeID GraphBuilder::add_pooling_node(Graph &g, NodeParams params, NodeIdxPair i return create_simple_single_input_output_node<PoolingLayerNode>(g, params, input, pool_info); } +NodeID GraphBuilder::add_reorg_node(Graph &g, NodeParams params, NodeIdxPair input, int stride) +{ + return create_simple_single_input_output_node<ReorgLayerNode>(g, params, input, stride); +} + NodeID GraphBuilder::add_reshape_node(Graph &g, NodeParams params, NodeIdxPair input, TensorShape shape) { return create_simple_single_input_output_node<ReshapeLayerNode>(g, params, input, shape); diff --git a/src/graph/backends/CL/CLFunctionsFactory.cpp b/src/graph/backends/CL/CLFunctionsFactory.cpp index bf3dcba224..25456e886f 100644 --- a/src/graph/backends/CL/CLFunctionsFactory.cpp +++ b/src/graph/backends/CL/CLFunctionsFactory.cpp @@ -105,6 +105,8 @@ std::unique_ptr<IFunction> CLFunctionFactory::create(INode *node, GraphContext & return detail::create_permute_layer<CLPermute, CLTargetInfo>(*polymorphic_downcast<PermuteLayerNode *>(node)); case NodeType::PoolingLayer: return detail::create_pooling_layer<CLPoolingLayer, CLTargetInfo>(*polymorphic_downcast<PoolingLayerNode *>(node)); + case NodeType::ReorgLayer: + return detail::create_reorg_layer<CLReorgLayer, CLTargetInfo>(*polymorphic_downcast<ReorgLayerNode *>(node)); case NodeType::ReshapeLayer: return detail::create_reshape_layer<CLReshapeLayer, CLTargetInfo>(*polymorphic_downcast<ReshapeLayerNode *>(node)); case NodeType::ResizeLayer: diff --git a/src/graph/backends/CL/CLNodeValidator.cpp b/src/graph/backends/CL/CLNodeValidator.cpp index ba5b59d76a..ece0d324f6 100644 --- a/src/graph/backends/CL/CLNodeValidator.cpp +++ b/src/graph/backends/CL/CLNodeValidator.cpp @@ -59,6 +59,8 @@ Status CLNodeValidator::validate(INode *node) CLDepthwiseConvolutionLayer3x3>(*polymorphic_downcast<DepthwiseConvolutionLayerNode *>(node)); case NodeType::PermuteLayer: return detail::validate_permute_layer<CLPermute>(*polymorphic_downcast<PermuteLayerNode *>(node)); + case NodeType::ReorgLayer: + return detail::validate_reorg_layer<CLReorgLayer>(*polymorphic_downcast<ReorgLayerNode *>(node)); default: return Status{}; } diff --git a/src/graph/backends/NEON/NEFunctionFactory.cpp b/src/graph/backends/NEON/NEFunctionFactory.cpp index c6da34f63f..ec70a5ae93 100644 --- a/src/graph/backends/NEON/NEFunctionFactory.cpp +++ b/src/graph/backends/NEON/NEFunctionFactory.cpp @@ -207,6 +207,8 @@ std::unique_ptr<IFunction> NEFunctionFactory::create(INode *node, GraphContext & return detail::create_permute_layer<NEPermute, NETargetInfo>(*polymorphic_downcast<PermuteLayerNode *>(node)); case NodeType::PoolingLayer: return detail::create_pooling_layer<NEPoolingLayer, NETargetInfo>(*polymorphic_downcast<PoolingLayerNode *>(node)); + case NodeType::ReorgLayer: + return detail::create_reorg_layer<NEReorgLayer, NETargetInfo>(*polymorphic_downcast<ReorgLayerNode *>(node)); case NodeType::ReshapeLayer: return detail::create_reshape_layer<NEReshapeLayer, NETargetInfo>(*polymorphic_downcast<ReshapeLayerNode *>(node)); case NodeType::ResizeLayer: diff --git a/src/graph/backends/NEON/NENodeValidator.cpp b/src/graph/backends/NEON/NENodeValidator.cpp index 58ffaf024b..9f0547f55c 100644 --- a/src/graph/backends/NEON/NENodeValidator.cpp +++ b/src/graph/backends/NEON/NENodeValidator.cpp @@ -59,6 +59,8 @@ Status NENodeValidator::validate(INode *node) NEDepthwiseConvolutionLayer3x3>(*polymorphic_downcast<DepthwiseConvolutionLayerNode *>(node)); case NodeType::PermuteLayer: return detail::validate_permute_layer<NEPermute>(*polymorphic_downcast<PermuteLayerNode *>(node)); + case NodeType::ReorgLayer: + return detail::validate_reorg_layer<NEReorgLayer>(*polymorphic_downcast<ReorgLayerNode *>(node)); default: return Status{}; } diff --git a/src/graph/nodes/ReorgLayerNode.cpp b/src/graph/nodes/ReorgLayerNode.cpp new file mode 100644 index 0000000000..6b83f6b90c --- /dev/null +++ b/src/graph/nodes/ReorgLayerNode.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018 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/nodes/ReorgLayerNode.h" + +#include "arm_compute/graph/Graph.h" +#include "arm_compute/graph/INodeVisitor.h" +#include "arm_compute/graph/Utils.h" + +namespace arm_compute +{ +namespace graph +{ +ReorgLayerNode::ReorgLayerNode(int stride) + : _stride(stride) +{ + _input_edges.resize(1, EmptyEdgeID); + _outputs.resize(1, NullTensorID); +} + +int ReorgLayerNode::stride() const +{ + return _stride; +} + +TensorDescriptor ReorgLayerNode::compute_output_descriptor(const TensorDescriptor &input_descriptor, int stride) +{ + const unsigned int input_width = get_dimension_size(input_descriptor, DataLayoutDimension::WIDTH); + const unsigned int input_height = get_dimension_size(input_descriptor, DataLayoutDimension::HEIGHT); + const unsigned int input_channel = get_dimension_size(input_descriptor, DataLayoutDimension::CHANNEL); + + ARM_COMPUTE_ERROR_ON(stride <= 0); + ARM_COMPUTE_ERROR_ON_MSG((input_width % stride != 0), "The width of the input tensor must be a multiple of stride"); + ARM_COMPUTE_ERROR_ON_MSG((input_height % stride != 0), "The height of the input tensor must be a multiple of stride"); + + TensorDescriptor output_descriptor = input_descriptor; + output_descriptor.shape.set(get_dimension_idx(output_descriptor, DataLayoutDimension::WIDTH), input_width / stride); + output_descriptor.shape.set(get_dimension_idx(output_descriptor, DataLayoutDimension::HEIGHT), input_height / stride); + output_descriptor.shape.set(get_dimension_idx(output_descriptor, DataLayoutDimension::CHANNEL), input_channel * stride * stride); + + return output_descriptor; +} + +bool ReorgLayerNode::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 ReorgLayerNode::configure_output(size_t idx) const +{ + ARM_COMPUTE_UNUSED(idx); + ARM_COMPUTE_ERROR_ON(idx >= _outputs.size()); + + const Tensor *src = input(0); + ARM_COMPUTE_ERROR_ON(src == nullptr); + + return compute_output_descriptor(src->desc(), _stride); +} + +NodeType ReorgLayerNode::type() const +{ + return NodeType::ReorgLayer; +} + +void ReorgLayerNode::accept(INodeVisitor &v) +{ + v.visit(*this); +} +} // namespace graph +} // namespace arm_compute
\ No newline at end of file diff --git a/src/runtime/NEON/functions/NEDepthwiseConvolutionLayer.cpp b/src/runtime/NEON/functions/NEDepthwiseConvolutionLayer.cpp index 24b12f4969..ccbd01e2e2 100644 --- a/src/runtime/NEON/functions/NEDepthwiseConvolutionLayer.cpp +++ b/src/runtime/NEON/functions/NEDepthwiseConvolutionLayer.cpp @@ -163,15 +163,26 @@ Status NEDepthwiseConvolutionLayer3x3::validate(const ITensorInfo *input, const unsigned int depth_multiplier) { ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, weights, output); - ARM_COMPUTE_RETURN_ERROR_ON(input->data_layout() != DataLayout::NCHW && input->data_layout() != DataLayout::NHWC); + ARM_COMPUTE_RETURN_ERROR_ON(input->data_layout() == DataLayout::UNKNOWN); if(biases != nullptr) { + const unsigned int channel_idx = get_data_layout_dimension_index(input->data_layout(), DataLayoutDimension::CHANNEL); ARM_COMPUTE_RETURN_ERROR_ON(biases->num_dimensions() > 1); - ARM_COMPUTE_RETURN_ERROR_ON(biases->dimension(0) != weights->dimension(3)); + ARM_COMPUTE_RETURN_ERROR_ON(biases->dimension(0) != weights->dimension(channel_idx)); } - return NEDepthwiseConvolutionLayer3x3Kernel::validate(input, weights, output, conv_info, depth_multiplier); + const bool is_quantized = is_data_type_quantized_asymmetric(input->data_type()); + TensorInfo accumulator = TensorInfo(output->clone()->set_is_resizable(true).reset_padding().set_data_type(DataType::S32)); + + ARM_COMPUTE_RETURN_ON_ERROR(NEDepthwiseConvolutionLayer3x3Kernel::validate(input, weights, is_quantized ? &accumulator : output, conv_info, depth_multiplier)); + + if(is_quantized) + { + ARM_COMPUTE_RETURN_ON_ERROR(NEDirectConvolutionLayerOutputStageKernel::validate(&accumulator, biases, output)); + } + + return Status{}; } void NEDepthwiseConvolutionLayer3x3::run() @@ -359,7 +370,10 @@ Status NEDepthwiseConvolutionLayer::validate(const ITensorInfo *input, const ITe unsigned int depth_multiplier) { ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, weights, output); - ARM_COMPUTE_RETURN_ERROR_ON(input->data_layout() != DataLayout::NCHW && input->data_layout() != DataLayout::NHWC); + ARM_COMPUTE_RETURN_ERROR_ON(input->data_layout() == DataLayout::UNKNOWN); + + const unsigned int width_idx = get_data_layout_dimension_index(input->data_layout(), DataLayoutDimension::WIDTH); + const unsigned int height_idx = get_data_layout_dimension_index(input->data_layout(), DataLayoutDimension::HEIGHT); // Clone output to use auto init auto output_clone = output->clone(); @@ -391,8 +405,8 @@ Status NEDepthwiseConvolutionLayer::validate(const ITensorInfo *input, const ITe const size_t weights_w = weights_to_use->dimension(0); const size_t weights_h = weights_to_use->dimension(1); const size_t weights_z = weights_to_use->dimension(2); - const unsigned int conv_w = output_shape.x(); - const unsigned int conv_h = output_shape.y(); + const unsigned int conv_w = output_shape[width_idx]; + const unsigned int conv_h = output_shape[height_idx]; const size_t patch_size = weights_w * weights_h + (append_bias ? 1 : 0); const size_t conv_size = conv_w * conv_h; |