aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gilday <alexander.gilday@arm.com>2018-03-05 16:22:48 +0000
committerAnthony Barbier <anthony.barbier@arm.com>2018-11-02 16:49:16 +0000
commit60954c671ffdc3422bbdb728fc022eb6896c1e17 (patch)
tree67f57a6683562bf6611d46cfc409edf32e891ac7
parentf47bfb97fa8bc928a7860b84b7b227f716f65e58 (diff)
downloadComputeLibrary-60954c671ffdc3422bbdb728fc022eb6896c1e17.tar.gz
COMPMID-754: Add validation to (De)QuantizationLayers
Change-Id: If8fa1277e8dc5b8e28a8bcad4ff9fc672b00ce9a Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/123275 Reviewed-by: Anthony Barbier <anthony.barbier@arm.com> Tested-by: Jenkins <bsgcomp@arm.com> Reviewed-by: Michalis Spyrou <michalis.spyrou@arm.com>
-rw-r--r--arm_compute/core/CL/kernels/CLDequantizationLayerKernel.h12
-rw-r--r--arm_compute/core/CL/kernels/CLMinMaxLayerKernel.h13
-rw-r--r--arm_compute/core/CL/kernels/CLQuantizationLayerKernel.h10
-rw-r--r--arm_compute/core/NEON/kernels/NEDequantizationLayerKernel.h10
-rw-r--r--arm_compute/core/NEON/kernels/NEMinMaxLayerKernel.h9
-rw-r--r--arm_compute/core/NEON/kernels/NEQuantizationLayerKernel.h10
-rw-r--r--arm_compute/core/utils/misc/ShapeCalculator.h11
-rw-r--r--arm_compute/runtime/CL/functions/CLDequantizationLayer.h12
-rw-r--r--arm_compute/runtime/CL/functions/CLQuantizationLayer.h10
-rw-r--r--arm_compute/runtime/NEON/functions/NEDequantizationLayer.h12
-rw-r--r--arm_compute/runtime/NEON/functions/NEQuantizationLayer.h10
-rw-r--r--src/core/CL/kernels/CLDequantizationLayerKernel.cpp73
-rw-r--r--src/core/CL/kernels/CLMinMaxLayerKernel.cpp80
-rw-r--r--src/core/CL/kernels/CLQuantizationLayerKernel.cpp73
-rw-r--r--src/core/NEON/kernels/NEDequantizationLayerKernel.cpp73
-rw-r--r--src/core/NEON/kernels/NEMinMaxLayerKernel.cpp79
-rw-r--r--src/core/NEON/kernels/NEQuantizationLayerKernel.cpp72
-rw-r--r--src/runtime/CL/functions/CLDequantizationLayer.cpp13
-rw-r--r--src/runtime/CL/functions/CLQuantizationLayer.cpp16
-rw-r--r--src/runtime/NEON/functions/NEDequantizationLayer.cpp13
-rw-r--r--src/runtime/NEON/functions/NEQuantizationLayer.cpp16
21 files changed, 492 insertions, 135 deletions
diff --git a/arm_compute/core/CL/kernels/CLDequantizationLayerKernel.h b/arm_compute/core/CL/kernels/CLDequantizationLayerKernel.h
index 03112d282a..38aa63e98f 100644
--- a/arm_compute/core/CL/kernels/CLDequantizationLayerKernel.h
+++ b/arm_compute/core/CL/kernels/CLDequantizationLayerKernel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -58,6 +58,16 @@ public:
* The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32.
*/
void configure(const ICLTensor *input, ICLTensor *output, const ICLTensor *min_max);
+ /** Static function to check if given info will lead to a valid configuration of @ref CLDequantizationLayerKernel
+ *
+ * @param[in] input Input tensor info. Data types supported: U8.
+ * @param[in] output Output tensor info. Data types supported: F32.
+ * @param[in] min_max Info for the tensor with shape [2, batches] which stores the minimum and maximum value for each 3D input tensor.
+ * The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32.
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max);
// Inherited methods overridden:
void run(const Window &window, cl::CommandQueue &queue) override;
diff --git a/arm_compute/core/CL/kernels/CLMinMaxLayerKernel.h b/arm_compute/core/CL/kernels/CLMinMaxLayerKernel.h
index a0eba4879b..0faa5c0bde 100644
--- a/arm_compute/core/CL/kernels/CLMinMaxLayerKernel.h
+++ b/arm_compute/core/CL/kernels/CLMinMaxLayerKernel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -49,9 +49,18 @@ public:
*
* @param[in] input Input tensor with at least 3 dimensions. The dimensions over the third will be interpreted as batches.Data types supported: F32.
* @param[out] output Output tensor with shape [2, batches, ...] which stores the minimum and maximum values for each 3D input tensor.
- * The dimensions over the second must match the batched dimensions of the input tensor. Data types supported: F32.
+ * The dimensions over the second must match the batched dimensions of the input tensor. Data types supported: F32.
*/
void configure(const ICLTensor *input, ICLTensor *output);
+ /** Static function to check if given info will lead to a valid configuration of @ref CLMinMaxLayerKernel
+ *
+ * @param[in] input Input tensor info. Data types supported: F32.
+ * @param[in] output Output tensor info with shape [2, batches, ...] which stores the minimum and maximum values for each 3D input tensor.
+ * The dimensions over the second must match the batched dimensions of the input tensor. Data types supported: F32.
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output);
/** Resets global minimum and maximum
*
diff --git a/arm_compute/core/CL/kernels/CLQuantizationLayerKernel.h b/arm_compute/core/CL/kernels/CLQuantizationLayerKernel.h
index a24ddb1a3a..49d76087b5 100644
--- a/arm_compute/core/CL/kernels/CLQuantizationLayerKernel.h
+++ b/arm_compute/core/CL/kernels/CLQuantizationLayerKernel.h
@@ -57,6 +57,16 @@ public:
* The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32.
*/
void configure(const ICLTensor *input, ICLTensor *output, ICLTensor *min_max);
+ /** Static function to check if given info will lead to a valid configuration of @ref CLQuantizationLayerKernel
+ *
+ * @param[in] input Input tensor info. Data types supported: F32.
+ * @param[in] output Output tensor info. Output data type must be U8.
+ * @param[in] min_max Info for the tensor with shape [2, batches] which stores the minimum and maximum value for each 3D input tensor.
+ * The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32.
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max);
// Inherited methods overridden:
void run(const Window &window, cl::CommandQueue &queue) override;
diff --git a/arm_compute/core/NEON/kernels/NEDequantizationLayerKernel.h b/arm_compute/core/NEON/kernels/NEDequantizationLayerKernel.h
index 25383aa7dc..7ee2078e9e 100644
--- a/arm_compute/core/NEON/kernels/NEDequantizationLayerKernel.h
+++ b/arm_compute/core/NEON/kernels/NEDequantizationLayerKernel.h
@@ -62,6 +62,16 @@ public:
* The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32
*/
void configure(const ITensor *input, ITensor *output, const ITensor *min_max);
+ /** Static function to check if given info will lead to a valid configuration of @ref NEDequantizationLayerKernel
+ *
+ * @param[in] input Input tensor info. Data types supported: U8.
+ * @param[in] output Output tensor info. Data types supported: F32.
+ * @param[in] min_max Info for the tensor with shape [2, batches] which stores the minimum and maximum value for each 3D input tensor.
+ * The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32.
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max);
// Inherited methods overridden:
void run(const Window &window, const ThreadInfo &info) override;
diff --git a/arm_compute/core/NEON/kernels/NEMinMaxLayerKernel.h b/arm_compute/core/NEON/kernels/NEMinMaxLayerKernel.h
index 592b5941b5..cfc3ee5290 100644
--- a/arm_compute/core/NEON/kernels/NEMinMaxLayerKernel.h
+++ b/arm_compute/core/NEON/kernels/NEMinMaxLayerKernel.h
@@ -65,6 +65,15 @@ public:
* The dimensions over the second must match the batched dimensions of the input tensor. Data types supported: F32
*/
void configure(const ITensor *input, ITensor *output);
+ /** Static function to check if given info will lead to a valid configuration of @ref CLMinMaxLayerKernel
+ *
+ * @param[in] input Input tensor info. Data types supported: F32.
+ * @param[in] output Output tensor info with shape [2, batches, ...] which stores the minimum and maximum values for each 3D input tensor.
+ * The dimensions over the second must match the batched dimensions of the input tensor. Data types supported: F32.
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output);
/** Resets global minimum and maximum. */
void reset();
diff --git a/arm_compute/core/NEON/kernels/NEQuantizationLayerKernel.h b/arm_compute/core/NEON/kernels/NEQuantizationLayerKernel.h
index 9642ac52a7..e7cf0a8ca4 100644
--- a/arm_compute/core/NEON/kernels/NEQuantizationLayerKernel.h
+++ b/arm_compute/core/NEON/kernels/NEQuantizationLayerKernel.h
@@ -62,6 +62,16 @@ public:
* The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32
*/
void configure(const ITensor *input, ITensor *output, const ITensor *min_max);
+ /** Static function to check if given info will lead to a valid configuration of @ref NEQuantizationLayerKernel
+ *
+ * @param[in] input Input tensor info. Data types supported: F32.
+ * @param[in] output Output tensor info. Data types supported: U8.
+ * @param[in] min_max Info for the tensor with shape [2, batches] which stores the minimum and maximum value for each 3D input tensor.
+ * The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32.
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max);
// Inherited methods overridden:
void run(const Window &window, const ThreadInfo &info) override;
diff --git a/arm_compute/core/utils/misc/ShapeCalculator.h b/arm_compute/core/utils/misc/ShapeCalculator.h
index 9cb8023463..1e90927a93 100644
--- a/arm_compute/core/utils/misc/ShapeCalculator.h
+++ b/arm_compute/core/utils/misc/ShapeCalculator.h
@@ -249,6 +249,17 @@ inline TensorShape compute_deep_convolution_shape(const ITensorInfo &input, cons
return output_shape;
}
+
+inline TensorShape compute_min_max_shape(const ITensorInfo *input)
+{
+ TensorShape output_shape{ input->tensor_shape() };
+ output_shape.set(Window::DimX, 2);
+ output_shape.remove_dimension(1);
+ output_shape.remove_dimension(1);
+
+ return output_shape;
+}
+
} // namespace shape_calculator
} // namespace misc
} // namespace arm_compute
diff --git a/arm_compute/runtime/CL/functions/CLDequantizationLayer.h b/arm_compute/runtime/CL/functions/CLDequantizationLayer.h
index 0ba182b475..efd28fc819 100644
--- a/arm_compute/runtime/CL/functions/CLDequantizationLayer.h
+++ b/arm_compute/runtime/CL/functions/CLDequantizationLayer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -57,6 +57,16 @@ public:
* The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32.
*/
void configure(const ICLTensor *input, ICLTensor *output, const ICLTensor *min_max);
+ /** Static function to check if given info will lead to a valid configuration of @ref CLDequantizationLayer
+ *
+ * @param[in] input Input tensor info. Data types supported: U8.
+ * @param[in] output Output tensor info. Data type supported: F32.
+ * @param[in] min_max Info for the tensor with shape [2, batches] which stores the minimum and maximum value for each 3D input tensor.
+ * The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32.
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max);
// Inherited methods overridden:
void run() override;
diff --git a/arm_compute/runtime/CL/functions/CLQuantizationLayer.h b/arm_compute/runtime/CL/functions/CLQuantizationLayer.h
index b3c4da05d4..738187dfe7 100644
--- a/arm_compute/runtime/CL/functions/CLQuantizationLayer.h
+++ b/arm_compute/runtime/CL/functions/CLQuantizationLayer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -53,6 +53,14 @@ public:
* @param[out] output Destination tensor with the same dimensions of input. Output data type must be U8.
*/
void configure(const ICLTensor *input, ICLTensor *output);
+ /** Static function to check if given info will lead to a valid configuration of @ref CLQuantizationLayer
+ *
+ * @param[in] input Input tensor info. The dimensions over the third will be interpreted as batches. Data types supported: F32.
+ * @param[in] output Output tensor info. Output data type must be U8.
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output);
// Inherited methods overridden:
void run() override;
diff --git a/arm_compute/runtime/NEON/functions/NEDequantizationLayer.h b/arm_compute/runtime/NEON/functions/NEDequantizationLayer.h
index 898586190e..90c454ef3e 100644
--- a/arm_compute/runtime/NEON/functions/NEDequantizationLayer.h
+++ b/arm_compute/runtime/NEON/functions/NEDequantizationLayer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -54,6 +54,16 @@ public:
* The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32
*/
void configure(const ITensor *input, ITensor *output, const ITensor *min_max);
+ /** Static function to check if given info will lead to a valid configuration of @ref NEDequantizationLayer
+ *
+ * @param[in] input Input tensor info. Data types supported: U8.
+ * @param[in] output Output tensor info. Data type supported: F32.
+ * @param[in] min_max Info for the tensor with shape [2, batches] which stores the minimum and maximum value for each 3D input tensor.
+ * The dimensions over the second must match the batched dimensions of the input tensor. Data type supported: F32.
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max);
// Inherited methods overridden:
void run() override;
diff --git a/arm_compute/runtime/NEON/functions/NEQuantizationLayer.h b/arm_compute/runtime/NEON/functions/NEQuantizationLayer.h
index d91b4ad1ad..9cc1666b4c 100644
--- a/arm_compute/runtime/NEON/functions/NEQuantizationLayer.h
+++ b/arm_compute/runtime/NEON/functions/NEQuantizationLayer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -55,6 +55,14 @@ public:
* @param[out] output Destination tensor with the same dimensions of input. Data types supported: U8
*/
void configure(const ITensor *input, ITensor *output);
+ /** Static function to check if given info will lead to a valid configuration of @ref NEQuantizationLayer
+ *
+ * @param[in] input Input tensor info. The dimensions over the third will be interpreted as batches. Data types supported: F32.
+ * @param[in] output Output tensor info. Data types supported: U8
+ *
+ * @return a status
+ */
+ static Status validate(const ITensorInfo *input, const ITensorInfo *output);
// Inherited methods overridden:
void run() override;
diff --git a/src/core/CL/kernels/CLDequantizationLayerKernel.cpp b/src/core/CL/kernels/CLDequantizationLayerKernel.cpp
index 4efdb764bd..fa982d6cf2 100644
--- a/src/core/CL/kernels/CLDequantizationLayerKernel.cpp
+++ b/src/core/CL/kernels/CLDequantizationLayerKernel.cpp
@@ -34,6 +34,46 @@
using namespace arm_compute;
+namespace
+{
+Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8);
+ ARM_COMPUTE_RETURN_ERROR_ON(input->num_dimensions() < 3);
+
+ if(output->tensor_shape().total_size() > 0)
+ {
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::F32);
+ ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_SHAPES(input, output);
+ }
+
+ return Status{};
+}
+
+std::tuple<Status, Window> validate_and_configure_window(ITensorInfo *input, ITensorInfo *output, ITensorInfo *min_max)
+{
+ // Output tensor auto initialization if not yet initialized
+ auto_init_if_empty(*output, input->tensor_shape(), 1, DataType::F32, 0);
+
+ constexpr unsigned int num_elems_processed_per_iteration = 4;
+
+ // Configure window
+ Window win = calculate_max_window(*input, Steps(num_elems_processed_per_iteration));
+ AccessWindowHorizontal input_access(input, 0, num_elems_processed_per_iteration);
+ AccessWindowHorizontal output_access(output, 0, num_elems_processed_per_iteration);
+ AccessWindowStatic min_max_access(min_max, 0, 0, 2, min_max->dimension(1));
+
+ // Update window and padding
+ bool window_changed = update_window_and_padding(win, input_access, output_access, min_max_access);
+
+ output_access.set_valid_region(win, input->valid_region());
+
+ Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
+ return std::make_tuple(err, win);
+}
+} // namespace
+
CLDequantizationLayerKernel::CLDequantizationLayerKernel()
: _input(nullptr), _output(nullptr), _min_max(nullptr)
{
@@ -41,37 +81,30 @@ CLDequantizationLayerKernel::CLDequantizationLayerKernel()
void CLDequantizationLayerKernel::configure(const ICLTensor *input, ICLTensor *output, const ICLTensor *min_max)
{
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8);
- ARM_COMPUTE_ERROR_ON_NULLPTR(output, min_max);
- ARM_COMPUTE_ERROR_ON(input->info()->num_dimensions() < 3);
-
- // Output tensor auto initialization if not yet initialized
- auto_init_if_empty(*output->info(), input->info()->tensor_shape(), 1, DataType::F32, 0);
-
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::F32);
- ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output);
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info(), min_max->info()));
_input = input;
_output = output;
_min_max = min_max;
- constexpr unsigned int num_elems_processed_per_iteration = 4;
-
// Create kernel
_kernel = static_cast<cl::Kernel>(CLKernelLibrary::get().create_kernel("dequantization_layer"));
- // Configure window
- Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
- AccessWindowHorizontal input_access(input->info(), 0, num_elems_processed_per_iteration);
- AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
- AccessWindowStatic min_max_access(min_max->info(), 0, 0, 2, min_max->info()->dimension(1));
+ // Configure kernel window
+ auto win_config = validate_and_configure_window(input->info(), output->info(), min_max->info());
- // Update window and padding
- update_window_and_padding(win, input_access, output_access, min_max_access);
+ ARM_COMPUTE_ERROR_THROW_ON(std::get<0>(win_config));
- output_access.set_valid_region(win, input->info()->valid_region());
+ ICLKernel::configure(std::get<1>(win_config));
+}
+
+Status CLDequantizationLayerKernel::validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output, min_max));
+ ARM_COMPUTE_RETURN_ON_ERROR(std::get<0>(validate_and_configure_window(input->clone().get(), output->clone().get(), min_max->clone().get())));
- ICLKernel::configure(win);
+ return Status{};
}
void CLDequantizationLayerKernel::run(const Window &window, cl::CommandQueue &queue)
diff --git a/src/core/CL/kernels/CLMinMaxLayerKernel.cpp b/src/core/CL/kernels/CLMinMaxLayerKernel.cpp
index 8ba1f776a1..60dd5e7de3 100644
--- a/src/core/CL/kernels/CLMinMaxLayerKernel.cpp
+++ b/src/core/CL/kernels/CLMinMaxLayerKernel.cpp
@@ -30,38 +30,69 @@
#include "arm_compute/core/Helpers.h"
#include "arm_compute/core/Validate.h"
#include "arm_compute/core/Window.h"
+#include "arm_compute/core/utils/misc/ShapeCalculator.h"
#include <climits>
using namespace arm_compute;
+using namespace arm_compute::misc::shape_calculator;
-CLMinMaxLayerKernel::CLMinMaxLayerKernel()
- : _input(nullptr), _output(nullptr)
+namespace
{
+Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output);
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32);
+ ARM_COMPUTE_RETURN_ERROR_ON(input->num_dimensions() < 3);
+
+ if(output->tensor_shape().total_size() > 0)
+ {
+ ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
+
+ TensorShape output_shape = compute_min_max_shape(input);
+
+ ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DIMENSIONS(output->tensor_shape(), output_shape);
+ }
+
+ return Status{};
}
-void CLMinMaxLayerKernel::configure(const ICLTensor *input, ICLTensor *output)
+std::tuple<Status, Window> validate_and_configure_window(ITensorInfo *input, ITensorInfo *output)
{
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32);
- ARM_COMPUTE_ERROR_ON(input->info()->num_dimensions() < 3);
- ARM_COMPUTE_ERROR_ON_NULLPTR(output);
-
- TensorShape output_shape{ input->info()->tensor_shape() };
- output_shape.set(Window::DimX, 2);
- output_shape.remove_dimension(1);
- output_shape.remove_dimension(1);
+ TensorShape output_shape = compute_min_max_shape(input);
// Output auto initialization if not yet initialized
- auto_init_if_empty(*output->info(), output_shape, 1, input->info()->data_type(), input->info()->fixed_point_position());
+ auto_init_if_empty(*output, output_shape, 1, input->data_type(), input->fixed_point_position());
+
+ const unsigned int num_elems_processed_per_iteration = 1;
+
+ // Configure kernel window
+ Window win = calculate_max_window(*input, Steps(num_elems_processed_per_iteration));
+ AccessWindowHorizontal input_access(input, 0, num_elems_processed_per_iteration);
+ AccessWindowStatic output_access(output, 0, 0, 2, output->dimension(1));
+
+ bool window_changed = update_window_and_padding(win, input_access, output_access);
- ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
- ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(output->info()->tensor_shape(), output_shape);
+ output_access.set_valid_region(win, ValidRegion(Coordinates(), output->tensor_shape()));
+
+ Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
+ return std::make_tuple(err, win);
+}
+} // namespace
+
+CLMinMaxLayerKernel::CLMinMaxLayerKernel()
+ : _input(nullptr), _output(nullptr)
+{
+}
+
+void CLMinMaxLayerKernel::configure(const ICLTensor *input, ICLTensor *output)
+{
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
+ ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info()));
_input = input;
_output = output;
- const unsigned int num_elems_processed_per_iteration = 1;
-
std::set<std::string> build_opts;
build_opts.emplace("-DWIDTH=" + support::cpp11::to_string(input->info()->dimension(0)));
build_opts.emplace("-DHEIGHT=" + support::cpp11::to_string(input->info()->dimension(1)));
@@ -70,16 +101,19 @@ void CLMinMaxLayerKernel::configure(const ICLTensor *input, ICLTensor *output)
// Create kernel
_kernel = static_cast<cl::Kernel>(CLKernelLibrary::get().create_kernel("minmax_layer", build_opts));
- // Configure kernel window
- Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
- AccessWindowHorizontal input_access(input->info(), 0, num_elems_processed_per_iteration);
- AccessWindowStatic output_access(output->info(), 0, 0, 2, output->info()->dimension(1));
+ auto win_config = validate_and_configure_window(input->info(), output->info());
+
+ ARM_COMPUTE_ERROR_THROW_ON(std::get<0>(win_config));
- update_window_and_padding(win, input_access, output_access);
+ ICLKernel::configure(std::get<1>(win_config));
+}
- output_access.set_valid_region(win, ValidRegion(Coordinates(), output->info()->tensor_shape()));
+Status CLMinMaxLayerKernel::validate(const ITensorInfo *input, const ITensorInfo *output)
+{
+ ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output));
+ ARM_COMPUTE_RETURN_ON_ERROR(std::get<0>(validate_and_configure_window(input->clone().get(), output->clone().get())));
- ICLKernel::configure(win);
+ return Status{};
}
void CLMinMaxLayerKernel::reset(cl::CommandQueue &queue)
diff --git a/src/core/CL/kernels/CLQuantizationLayerKernel.cpp b/src/core/CL/kernels/CLQuantizationLayerKernel.cpp
index 8b082a8704..028e50821f 100644
--- a/src/core/CL/kernels/CLQuantizationLayerKernel.cpp
+++ b/src/core/CL/kernels/CLQuantizationLayerKernel.cpp
@@ -34,6 +34,46 @@
using namespace arm_compute;
+namespace
+{
+Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32);
+ ARM_COMPUTE_RETURN_ERROR_ON(input->num_dimensions() < 3);
+
+ if(output->tensor_shape().total_size() > 0)
+ {
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::U8);
+ ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_SHAPES(input, output);
+ }
+
+ return Status{};
+}
+
+std::tuple<Status, Window> validate_and_configure_window(ITensorInfo *input, ITensorInfo *output, ITensorInfo *min_max)
+{
+ // Output tensor auto initialization if not yet initialized
+ auto_init_if_empty(*output, input->tensor_shape(), 1, DataType::U8, 0);
+
+ constexpr unsigned int num_elems_processed_per_iteration = 4;
+
+ // Configure window
+ Window win = calculate_max_window(*input, Steps(num_elems_processed_per_iteration));
+ AccessWindowHorizontal input_access(input, 0, num_elems_processed_per_iteration);
+ AccessWindowHorizontal output_access(output, 0, num_elems_processed_per_iteration);
+ AccessWindowStatic min_max_access(min_max, 0, 0, 2, min_max->dimension(1));
+
+ // Update window and padding
+ bool window_changed = update_window_and_padding(win, input_access, output_access, min_max_access);
+
+ output_access.set_valid_region(win, input->valid_region());
+
+ Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
+ return std::make_tuple(err, win);
+}
+} // namespace
+
CLQuantizationLayerKernel::CLQuantizationLayerKernel()
: _input(nullptr), _output(nullptr), _min_max(nullptr)
{
@@ -41,37 +81,30 @@ CLQuantizationLayerKernel::CLQuantizationLayerKernel()
void CLQuantizationLayerKernel::configure(const ICLTensor *input, ICLTensor *output, ICLTensor *min_max)
{
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32);
- ARM_COMPUTE_ERROR_ON_NULLPTR(output, min_max);
- ARM_COMPUTE_ERROR_ON(input->info()->num_dimensions() < 3);
-
- // Output tensor auto initialization if not yet initialized
- auto_init_if_empty(*output->info(), input->info()->tensor_shape(), 1, DataType::U8, 0);
-
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::U8);
- ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output);
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info(), min_max->info()));
_input = input;
_output = output;
_min_max = min_max;
- constexpr unsigned int num_elems_processed_per_iteration = 4;
-
// Create kernel
_kernel = static_cast<cl::Kernel>(CLKernelLibrary::get().create_kernel("quantization_layer"));
- // Configure window
- Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
- AccessWindowHorizontal input_access(input->info(), 0, num_elems_processed_per_iteration);
- AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
- AccessWindowStatic min_max_access(min_max->info(), 0, 0, 2, min_max->info()->dimension(1));
+ // Configure kernel window
+ auto win_config = validate_and_configure_window(input->info(), output->info(), min_max->info());
- // Update window and padding
- update_window_and_padding(win, input_access, output_access, min_max_access);
+ ARM_COMPUTE_ERROR_THROW_ON(std::get<0>(win_config));
- output_access.set_valid_region(win, input->info()->valid_region());
+ ICLKernel::configure(std::get<1>(win_config));
+}
+
+Status CLQuantizationLayerKernel::validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output, min_max));
+ ARM_COMPUTE_RETURN_ON_ERROR(std::get<0>(validate_and_configure_window(input->clone().get(), output->clone().get(), min_max->clone().get())));
- ICLKernel::configure(win);
+ return Status{};
}
void CLQuantizationLayerKernel::run(const Window &window, cl::CommandQueue &queue)
diff --git a/src/core/NEON/kernels/NEDequantizationLayerKernel.cpp b/src/core/NEON/kernels/NEDequantizationLayerKernel.cpp
index be211b2cb2..4120e5f87a 100644
--- a/src/core/NEON/kernels/NEDequantizationLayerKernel.cpp
+++ b/src/core/NEON/kernels/NEDequantizationLayerKernel.cpp
@@ -34,6 +34,46 @@
using namespace arm_compute;
+namespace
+{
+Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8);
+ ARM_COMPUTE_RETURN_ERROR_ON(input->num_dimensions() < 3);
+
+ if(output->tensor_shape().total_size() > 0)
+ {
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::F32);
+ ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_SHAPES(input, output);
+ }
+
+ return Status{};
+}
+
+std::tuple<Status, Window> validate_and_configure_window(ITensorInfo *input, ITensorInfo *output, ITensorInfo *min_max)
+{
+ // Output tensor auto initialization if not yet initialized
+ auto_init_if_empty(*output, input->tensor_shape(), 1, DataType::F32, 0);
+
+ constexpr unsigned int num_elems_processed_per_iteration = 8;
+
+ // Configure window
+ Window win = calculate_max_window(*input, Steps(num_elems_processed_per_iteration));
+ AccessWindowHorizontal input_access(input, 0, num_elems_processed_per_iteration);
+ AccessWindowHorizontal output_access(output, 0, num_elems_processed_per_iteration);
+ AccessWindowStatic min_max_access(min_max, 0, 0, 2, min_max->dimension(1));
+
+ // Update window and padding
+ bool window_changed = update_window_and_padding(win, input_access, output_access, min_max_access);
+
+ output_access.set_valid_region(win, input->valid_region());
+
+ Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
+ return std::make_tuple(err, win);
+}
+} // namespace
+
NEDequantizationLayerKernel::NEDequantizationLayerKernel()
: _input(nullptr), _output(nullptr), _min_max(nullptr)
{
@@ -41,34 +81,27 @@ NEDequantizationLayerKernel::NEDequantizationLayerKernel()
void NEDequantizationLayerKernel::configure(const ITensor *input, ITensor *output, const ITensor *min_max)
{
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8);
- ARM_COMPUTE_ERROR_ON_NULLPTR(output);
- ARM_COMPUTE_ERROR_ON_NULLPTR(min_max);
- ARM_COMPUTE_ERROR_ON(input->info()->num_dimensions() < 3);
-
- // Output tensor auto initialization if not yet initialized
- auto_init_if_empty(*output->info(), input->info()->tensor_shape(), 1, DataType::F32, 0);
-
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::F32);
- ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output);
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info(), min_max->info()));
_input = input;
_output = output;
_min_max = min_max;
- constexpr unsigned int num_elems_processed_per_iteration = 8;
+ // Configure kernel window
+ auto win_config = validate_and_configure_window(input->info(), output->info(), min_max->info());
- // Configure window
- Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
- AccessWindowHorizontal input_access(input->info(), 0, num_elems_processed_per_iteration);
- AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
- AccessWindowStatic min_max_access(min_max->info(), 0, 0, 2, min_max->info()->dimension(1));
+ ARM_COMPUTE_ERROR_THROW_ON(std::get<0>(win_config));
- // Update window and padding
- update_window_and_padding(win, input_access, output_access, min_max_access);
- output_access.set_valid_region(win, input->info()->valid_region());
+ INEKernel::configure(std::get<1>(win_config));
+}
+
+Status NEDequantizationLayerKernel::validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output, min_max));
+ ARM_COMPUTE_RETURN_ON_ERROR(std::get<0>(validate_and_configure_window(input->clone().get(), output->clone().get(), min_max->clone().get())));
- INEKernel::configure(win);
+ return Status{};
}
void NEDequantizationLayerKernel::run(const Window &window, const ThreadInfo &info)
diff --git a/src/core/NEON/kernels/NEMinMaxLayerKernel.cpp b/src/core/NEON/kernels/NEMinMaxLayerKernel.cpp
index cc03a517bd..434f4eb3e9 100644
--- a/src/core/NEON/kernels/NEMinMaxLayerKernel.cpp
+++ b/src/core/NEON/kernels/NEMinMaxLayerKernel.cpp
@@ -32,51 +32,86 @@
#include "arm_compute/core/Types.h"
#include "arm_compute/core/Validate.h"
#include "arm_compute/core/Window.h"
+#include "arm_compute/core/utils/misc/ShapeCalculator.h"
#include <algorithm>
#include <arm_neon.h>
#include <climits>
#include <cstddef>
+using namespace arm_compute::misc::shape_calculator;
+
namespace arm_compute
{
-NEMinMaxLayerKernel::NEMinMaxLayerKernel()
- : _input(nullptr), _output(nullptr), _mtx()
+namespace
+{
+Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output)
{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output);
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32);
+ ARM_COMPUTE_RETURN_ERROR_ON(input->num_dimensions() < 3);
+
+ if(output->tensor_shape().total_size() > 0)
+ {
+ ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
+
+ TensorShape output_shape = compute_min_max_shape(input);
+
+ ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DIMENSIONS(output->tensor_shape(), output_shape);
+ }
+
+ return Status{};
}
-void NEMinMaxLayerKernel::configure(const ITensor *input, ITensor *output)
+std::tuple<Status, Window> validate_and_configure_window(ITensorInfo *input, ITensorInfo *output)
{
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32);
- ARM_COMPUTE_ERROR_ON(input->info()->num_dimensions() < 3);
- ARM_COMPUTE_ERROR_ON(output == nullptr);
-
- TensorShape output_shape{ input->info()->tensor_shape() };
- output_shape.set(Window::DimX, 2);
- output_shape.remove_dimension(1);
- output_shape.remove_dimension(1);
+ TensorShape output_shape = compute_min_max_shape(input);
// Output auto initialization if not yet initialized
- auto_init_if_empty(*output->info(), output_shape, 1, input->info()->data_type(), input->info()->fixed_point_position());
+ auto_init_if_empty(*output, output_shape, 1, input->data_type(), input->fixed_point_position());
+
+ constexpr unsigned int num_elems_processed_per_iteration = 1;
+
+ // Configure kernel window
+ Window win = calculate_max_window(*input, Steps(num_elems_processed_per_iteration));
+ AccessWindowHorizontal input_access(input, 0, num_elems_processed_per_iteration);
+ AccessWindowHorizontal output_access(output, 0, 2);
- ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_TYPES(input, output);
- ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(output->info()->tensor_shape(), output_shape);
+ bool window_changed = update_window_and_padding(win, input_access, output_access);
+
+ output_access.set_valid_region(win, ValidRegion(Coordinates(), output->tensor_shape()));
+
+ Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
+ return std::make_tuple(err, win);
+}
+} // namespace
+
+NEMinMaxLayerKernel::NEMinMaxLayerKernel()
+ : _input(nullptr), _output(nullptr), _mtx()
+{
+}
+
+void NEMinMaxLayerKernel::configure(const ITensor *input, ITensor *output)
+{
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
+ ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info()));
_input = input;
_output = output;
- // Configure kernel window
- constexpr unsigned int num_elems_processed_per_iteration = 1;
+ auto win_config = validate_and_configure_window(input->info(), output->info());
- Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
- AccessWindowHorizontal input_access(input->info(), 0, num_elems_processed_per_iteration);
- AccessWindowHorizontal output_access(output->info(), 0, 2);
+ ARM_COMPUTE_ERROR_THROW_ON(std::get<0>(win_config));
- update_window_and_padding(win, input_access, output_access);
+ INEKernel::configure(std::get<1>(win_config));
+}
- output_access.set_valid_region(win, ValidRegion(Coordinates(), output->info()->tensor_shape()));
+Status NEMinMaxLayerKernel::validate(const ITensorInfo *input, const ITensorInfo *output)
+{
+ ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output));
+ ARM_COMPUTE_RETURN_ON_ERROR(std::get<0>(validate_and_configure_window(input->clone().get(), output->clone().get())));
- INEKernel::configure(win);
+ return Status{};
}
void NEMinMaxLayerKernel::run(const Window &window, const ThreadInfo &info)
diff --git a/src/core/NEON/kernels/NEQuantizationLayerKernel.cpp b/src/core/NEON/kernels/NEQuantizationLayerKernel.cpp
index 767af08d0d..ee23e76c5c 100644
--- a/src/core/NEON/kernels/NEQuantizationLayerKernel.cpp
+++ b/src/core/NEON/kernels/NEQuantizationLayerKernel.cpp
@@ -34,6 +34,46 @@
using namespace arm_compute;
+namespace
+{
+Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32);
+ ARM_COMPUTE_RETURN_ERROR_ON(input->num_dimensions() < 3);
+
+ if(output->tensor_shape().total_size() > 0)
+ {
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::U8);
+ ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_SHAPES(input, output);
+ }
+
+ return Status{};
+}
+
+std::tuple<Status, Window> validate_and_configure_window(ITensorInfo *input, ITensorInfo *output, ITensorInfo *min_max)
+{
+ // Output tensor auto initialization if not yet initialized
+ auto_init_if_empty(*output, input->tensor_shape(), 1, DataType::U8, 0);
+
+ constexpr unsigned int num_elems_processed_per_iteration = 8;
+
+ // Configure window
+ Window win = calculate_max_window(*input, Steps(num_elems_processed_per_iteration));
+ AccessWindowHorizontal input_access(input, 0, num_elems_processed_per_iteration);
+ AccessWindowHorizontal output_access(output, 0, num_elems_processed_per_iteration);
+ AccessWindowStatic min_max_access(min_max, 0, 0, 2, min_max->dimension(1));
+
+ // Update window and padding
+ bool window_changed = update_window_and_padding(win, input_access, output_access, min_max_access);
+
+ output_access.set_valid_region(win, input->valid_region());
+
+ Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
+ return std::make_tuple(err, win);
+}
+} // namespace
+
NEQuantizationLayerKernel::NEQuantizationLayerKernel()
: _input(nullptr), _output(nullptr), _min_max(nullptr)
{
@@ -41,33 +81,27 @@ NEQuantizationLayerKernel::NEQuantizationLayerKernel()
void NEQuantizationLayerKernel::configure(const ITensor *input, ITensor *output, const ITensor *min_max)
{
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32);
- ARM_COMPUTE_ERROR_ON_NULLPTR(output);
- ARM_COMPUTE_ERROR_ON(input->info()->num_dimensions() < 3);
-
- // Output tensor auto initialization if not yet initialized
- auto_init_if_empty(*output->info(), input->info()->tensor_shape(), 1, DataType::U8, 0);
-
- ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::U8);
- ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output);
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info(), min_max->info()));
_input = input;
_output = output;
_min_max = min_max;
- constexpr unsigned int num_elems_processed_per_iteration = 8;
+ // Configure kernel window
+ auto win_config = validate_and_configure_window(input->info(), output->info(), min_max->info());
- // Configure window
- Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
- AccessWindowHorizontal input_access(input->info(), 0, num_elems_processed_per_iteration);
- AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
- AccessWindowStatic min_max_access(min_max->info(), 0, 0, 2, min_max->info()->dimension(1));
+ ARM_COMPUTE_ERROR_THROW_ON(std::get<0>(win_config));
- // Update window and padding
- update_window_and_padding(win, input_access, output_access, min_max_access);
- output_access.set_valid_region(win, input->info()->valid_region());
+ INEKernel::configure(std::get<1>(win_config));
+}
+
+Status NEQuantizationLayerKernel::validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output, min_max));
+ ARM_COMPUTE_RETURN_ON_ERROR(std::get<0>(validate_and_configure_window(input->clone().get(), output->clone().get(), min_max->clone().get())));
- INEKernel::configure(win);
+ return Status{};
}
void NEQuantizationLayerKernel::run(const Window &window, const ThreadInfo &info)
diff --git a/src/runtime/CL/functions/CLDequantizationLayer.cpp b/src/runtime/CL/functions/CLDequantizationLayer.cpp
index 5559d42c7f..6f33b2efa9 100644
--- a/src/runtime/CL/functions/CLDequantizationLayer.cpp
+++ b/src/runtime/CL/functions/CLDequantizationLayer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -24,6 +24,7 @@
#include "arm_compute/runtime/CL/functions/CLDequantizationLayer.h"
+#include "arm_compute/core/CL/ICLTensor.h"
#include "arm_compute/runtime/CL/CLScheduler.h"
using namespace arm_compute;
@@ -33,8 +34,18 @@ CLDequantizationLayer::CLDequantizationLayer()
{
}
+Status CLDequantizationLayer::validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_RETURN_ON_ERROR(CLDequantizationLayerKernel::validate(input, output, min_max));
+
+ return Status{};
+}
+
void CLDequantizationLayer::configure(const ICLTensor *input, ICLTensor *output, const ICLTensor *min_max)
{
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output, min_max);
+
_dequantize_kernel.configure(input, output, min_max);
}
diff --git a/src/runtime/CL/functions/CLQuantizationLayer.cpp b/src/runtime/CL/functions/CLQuantizationLayer.cpp
index ed1f51c714..a13859cda3 100644
--- a/src/runtime/CL/functions/CLQuantizationLayer.cpp
+++ b/src/runtime/CL/functions/CLQuantizationLayer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -24,6 +24,7 @@
#include "arm_compute/runtime/CL/functions/CLQuantizationLayer.h"
+#include "arm_compute/core/Error.h"
#include "arm_compute/runtime/CL/CLScheduler.h"
using namespace arm_compute;
@@ -33,8 +34,21 @@ CLQuantizationLayer::CLQuantizationLayer()
{
}
+Status CLQuantizationLayer::validate(const ITensorInfo *input, const ITensorInfo *output)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output);
+
+ TensorInfo min_max{ input->num_channels(), input->data_type() };
+ ARM_COMPUTE_RETURN_ON_ERROR(CLMinMaxLayerKernel::validate(input, &min_max));
+ ARM_COMPUTE_RETURN_ON_ERROR(CLQuantizationLayerKernel::validate(input, output, &min_max));
+
+ return Status{};
+}
+
void CLQuantizationLayer::configure(const ICLTensor *input, ICLTensor *output)
{
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
+
// Configure min-max kernel. _min_max tensor will be auto-configured within the kernel.
_min_max_kernel.configure(input, &_min_max);
diff --git a/src/runtime/NEON/functions/NEDequantizationLayer.cpp b/src/runtime/NEON/functions/NEDequantizationLayer.cpp
index a58b6e4007..0627977686 100644
--- a/src/runtime/NEON/functions/NEDequantizationLayer.cpp
+++ b/src/runtime/NEON/functions/NEDequantizationLayer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -25,6 +25,7 @@
#include "arm_compute/runtime/NEON/functions/NEDequantizationLayer.h"
#include "arm_compute/core/Types.h"
+#include "arm_compute/core/Validate.h"
#include "arm_compute/runtime/NEON/NEScheduler.h"
using namespace arm_compute;
@@ -34,8 +35,18 @@ NEDequantizationLayer::NEDequantizationLayer()
{
}
+Status NEDequantizationLayer::validate(const ITensorInfo *input, const ITensorInfo *output, const ITensorInfo *min_max)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output, min_max);
+ ARM_COMPUTE_RETURN_ON_ERROR(NEDequantizationLayerKernel::validate(input, output, min_max));
+
+ return Status{};
+}
+
void NEDequantizationLayer::configure(const ITensor *input, ITensor *output, const ITensor *min_max)
{
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output, min_max);
+
// Configure kernel
_dequantize_kernel.configure(input, output, min_max);
}
diff --git a/src/runtime/NEON/functions/NEQuantizationLayer.cpp b/src/runtime/NEON/functions/NEQuantizationLayer.cpp
index a131c4839b..8f7db96de8 100644
--- a/src/runtime/NEON/functions/NEQuantizationLayer.cpp
+++ b/src/runtime/NEON/functions/NEQuantizationLayer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017 ARM Limited.
+ * Copyright (c) 2017-2018 ARM Limited.
*
* SPDX-License-Identifier: MIT
*
@@ -25,6 +25,7 @@
#include "arm_compute/runtime/NEON/functions/NEQuantizationLayer.h"
#include "arm_compute/core/Types.h"
+#include "arm_compute/core/Validate.h"
#include "arm_compute/runtime/NEON/NEScheduler.h"
using namespace arm_compute;
@@ -34,8 +35,21 @@ NEQuantizationLayer::NEQuantizationLayer()
{
}
+Status NEQuantizationLayer::validate(const ITensorInfo *input, const ITensorInfo *output)
+{
+ ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, output);
+
+ TensorInfo min_max{ input->num_channels(), input->data_type() };
+ ARM_COMPUTE_RETURN_ON_ERROR(NEMinMaxLayerKernel::validate(input, &min_max));
+ ARM_COMPUTE_RETURN_ON_ERROR(NEQuantizationLayerKernel::validate(input, output, &min_max));
+
+ return Status{};
+}
+
void NEQuantizationLayer::configure(const ITensor *input, ITensor *output)
{
+ ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
+
// Configure min-max kernel. _min_max tensor will be auto-configured within the kernel
_min_max_kernel.configure(input, &_min_max);