From cecb0a75a9de0a12d30f8fabbe16a656c722afa1 Mon Sep 17 00:00:00 2001 From: Sang-Hoon Park Date: Tue, 17 Sep 2019 08:59:09 +0100 Subject: COMPMID-2637 [CL] fix broadcast pixel-wise multiplication with 5D tensors Broadcast pixel-wise multiplication with 5D tensors is fixed by adding information whether a dimension has been broadcasted to compute correct start offset when adding 3D tensor argument. The testcase that failed is added to the validation test suite. Change-Id: I320876f507012c27b39daae1316f9b69138ed204 Signed-off-by: Sang-Hoon Park Reviewed-on: https://review.mlplatform.org/c/1994 Tested-by: Arm Jenkins Comments-Addressed: Arm Jenkins Reviewed-by: Georgios Pinitas --- arm_compute/core/Window.h | 17 ++++++++++++++++- arm_compute/core/Window.inl | 18 ++++++++++++++++-- arm_compute/core/utils/misc/Utility.h | 16 +++++++++++++++- src/core/CL/ICLKernel.cpp | 2 +- tests/datasets/ShapeDatasets.h | 12 ++++++++---- 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/arm_compute/core/Window.h b/arm_compute/core/Window.h index a56227996b..be42fe9a87 100644 --- a/arm_compute/core/Window.h +++ b/arm_compute/core/Window.h @@ -48,7 +48,7 @@ public: /** Default constructor: create a window containing a single element. */ constexpr Window() - : _dims() + : _dims(), _is_broadcasted(utility::generate_array::value) { } /** Copy constructor @@ -170,6 +170,20 @@ public: */ void set(size_t dimension, const Dimension &dim); + /** Set the dimension as broadcasted dimension + * + * @param[in] dimension The dimension to set + */ + void set_broadcasted(size_t dimension); + + /** Return whether a dimension has been broadcasted + * + * @param[in] dimension The requested dimension + * + * @return true if the dimension has been broadcasted + */ + bool is_broadcasted(size_t dimension) const; + /** Use the tensor's dimensions to fill the window dimensions. * * @param[in] shape @ref TensorShape to copy the dimensions from. @@ -419,6 +433,7 @@ private: private: std::array _dims; + std::array _is_broadcasted; }; } // namespace arm_compute #include "Window.inl" diff --git a/arm_compute/core/Window.inl b/arm_compute/core/Window.inl index eeef3df7b0..589d6bfafc 100644 --- a/arm_compute/core/Window.inl +++ b/arm_compute/core/Window.inl @@ -24,11 +24,12 @@ namespace arm_compute { inline Window::Window(const Window &src) - : _dims() + : _dims(), _is_broadcasted(utility::generate_array::value) { for(size_t i = 0; i < Coordinates::num_max_dimensions; ++i) { set(i, src[i]); + _is_broadcasted[i] = src.is_broadcasted(i); } } @@ -51,6 +52,19 @@ inline void Window::set(size_t dimension, const Window::Dimension &dim) _dims[dimension] = dim; } +inline void Window::set_broadcasted(size_t dimension) +{ + ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions); + set(dimension, Dimension(0, 0, 0)); + _is_broadcasted[dimension] = true; +} + +inline bool Window::is_broadcasted(size_t dimension) const +{ + ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions); + return _is_broadcasted[dimension]; +} + inline Window Window::collapse_if_possible(const Window &full_window, const size_t first, const size_t last, bool *has_collapsed) const { @@ -110,7 +124,7 @@ inline Window Window::broadcast_if_dimension_le_one(const TensorShape &shape) co { if(shape[d] <= 1) { - broadcastWin.set(d, Dimension(0, 0, 0)); + broadcastWin.set_broadcasted(d); } } return broadcastWin; diff --git a/arm_compute/core/utils/misc/Utility.h b/arm_compute/core/utils/misc/Utility.h index 8dd9afd5cd..2325644e72 100644 --- a/arm_compute/core/utils/misc/Utility.h +++ b/arm_compute/core/utils/misc/Utility.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -53,6 +53,20 @@ struct index_sequence_generator<0u, S...> : index_sequence template using index_sequence_t = typename index_sequence_generator::type; + +template +struct generate_array : generate_array < T, N - 1, val, val, vals... > +{ +}; + +template +struct generate_array +{ + static constexpr std::array value{ vals... }; +}; + +template +constexpr std::array generate_array::value; /** @endcond */ namespace detail diff --git a/src/core/CL/ICLKernel.cpp b/src/core/CL/ICLKernel.cpp index 2d28a496c9..d81ad46b29 100644 --- a/src/core/CL/ICLKernel.cpp +++ b/src/core/CL/ICLKernel.cpp @@ -98,7 +98,7 @@ void ICLKernel::add_tensor_argument(unsigned &idx, const ICLTensor *tensor, cons for(unsigned int n = 0; n < info->num_dimensions(); ++n) { - offset_first_element += window[n].start() * strides[n]; + offset_first_element += (window.is_broadcasted(n) ? 0 : window[n].start()) * strides[n]; } unsigned int idx_start = idx; diff --git a/tests/datasets/ShapeDatasets.h b/tests/datasets/ShapeDatasets.h index 07ecf45d81..b479eb4953 100644 --- a/tests/datasets/ShapeDatasets.h +++ b/tests/datasets/ShapeDatasets.h @@ -203,7 +203,9 @@ public: TensorShape{ 128U, 1U, 5U, 3U }, TensorShape{ 9U, 9U, 3U, 4U }, TensorShape{ 27U, 13U, 2U, 4U }, - TensorShape{ 1U, 1U, 1U, 5U } + TensorShape{ 1U, 1U, 1U, 5U }, + TensorShape{ 1U, 16U, 10U, 2U, 128U }, + TensorShape{ 1U, 16U, 10U, 2U, 128U } }), ShapeDataset("Shape1", { @@ -212,7 +214,9 @@ public: TensorShape{ 128U, 64U, 1U, 3U }, TensorShape{ 9U, 1U, 3U }, TensorShape{ 1U }, - TensorShape{ 9U, 9U, 3U, 5U } + TensorShape{ 9U, 9U, 3U, 5U }, + TensorShape{ 1U, 1U, 1U, 1U, 128U }, + TensorShape{ 128U } })) { } @@ -686,7 +690,7 @@ public: : ShapeDataset("InputShape", { // Batch size 1 - TensorShape{ 32U, 37U, 3U }, + TensorShape{ 32U, 37U, 3U }, // Batch size 4 TensorShape{ 32U, 37U, 3U, 4U }, }) @@ -702,7 +706,7 @@ public: : ShapeDataset("InputShape", { // Batch size 1 - TensorShape{ 32U, 37U, 3U }, + TensorShape{ 32U, 37U, 3U }, // Batch size 4 TensorShape{ 32U, 37U, 3U, 4U }, // Arbitrary batch size -- cgit v1.2.1