aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSheri Zhang <sheri.zhang@arm.com>2020-09-22 15:51:37 +0100
committerGeorgios Pinitas <georgios.pinitas@arm.com>2020-11-09 20:14:13 +0000
commit3327def321af49040ae1fbd6026234a0980e3289 (patch)
treee8e9932216d37b068609884c7e552d8142382948
parent532ac33cdfbe19b08d2c5028bb8627ae2732b049 (diff)
downloadComputeLibrary-3327def321af49040ae1fbd6026234a0980e3289.tar.gz
COMPMID-2808: Add support for QASYMM8_SIGNED in NEROIAlignLayer
Signed-off-by: Sheri Zhang <sheri.zhang@arm.com> Change-Id: Id4f4c96e1823a4b27886fee9baf70847172e619c Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/4335 Tested-by: Arm Jenkins <bsgcomp@arm.com> Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com> Comments-Addressed: Arm Jenkins <bsgcomp@arm.com>
-rw-r--r--arm_compute/runtime/NEON/functions/NEROIAlignLayer.h4
-rw-r--r--src/core/NEON/kernels/NEROIAlignLayerKernel.cpp122
-rw-r--r--src/core/NEON/kernels/NEROIAlignLayerKernel.h10
-rw-r--r--tests/validation/NEON/ROIAlignLayer.cpp15
4 files changed, 89 insertions, 62 deletions
diff --git a/arm_compute/runtime/NEON/functions/NEROIAlignLayer.h b/arm_compute/runtime/NEON/functions/NEROIAlignLayer.h
index 1d992f53df..ea3be18932 100644
--- a/arm_compute/runtime/NEON/functions/NEROIAlignLayer.h
+++ b/arm_compute/runtime/NEON/functions/NEROIAlignLayer.h
@@ -43,7 +43,7 @@ class NEROIAlignLayer : public INESimpleFunctionNoBorder
public:
/** Set the input and output tensors.
*
- * @param[in] input Source tensor. Data types supported: QASYMM8/F16/F32.
+ * @param[in] input Source tensor. Data types supported: QASYMM8/QASYMM8_SIGNED/F16/F32.
* @param[in] rois ROIs tensor, it is a 2D tensor of size [5, N] (where N is the number of ROIs) containing top left and bottom right corner
* as coordinate of an image and batch_id of ROI [ batch_id, x1, y1, x2, y2 ].
* Data types supported: QASYMM16 with scale of 0.125 and 0 offset if @p input is QASYMM8, otherwise same as @p input
@@ -58,7 +58,7 @@ public:
void configure(const ITensor *input, const ITensor *rois, ITensor *output, const ROIPoolingLayerInfo &pool_info);
/** Static function to check if given info will lead to a valid configuration of @ref NEROIAlignLayerKernel
*
- * @param[in] input Source tensor info. Data types supported: QASYMM8/F16/F32.
+ * @param[in] input Source tensor info. Data types supported: QASYMM8/QASYMM8_SIGNED/F16/F32.
* @param[in] rois ROIs tensor info. Data types supported: QASYMM16 with scale of 0.125 and 0 offset if @p input is QASYMM8,
* otherwise same as @p input
* @param[in] output Destination tensor info. Data types supported: Same as @p input.
diff --git a/src/core/NEON/kernels/NEROIAlignLayerKernel.cpp b/src/core/NEON/kernels/NEROIAlignLayerKernel.cpp
index c48cda8b8e..e937dadba7 100644
--- a/src/core/NEON/kernels/NEROIAlignLayerKernel.cpp
+++ b/src/core/NEON/kernels/NEROIAlignLayerKernel.cpp
@@ -47,7 +47,7 @@ Status validate_arguments(const ITensorInfo *input, const ITensorInfo *rois, ITe
ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, rois, output);
ARM_COMPUTE_RETURN_ERROR_ON(rois->dimension(0) != 5);
ARM_COMPUTE_RETURN_ERROR_ON(rois->num_dimensions() > 2);
- ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::QASYMM8, DataType::F32, DataType::F16);
+ ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::QASYMM8, DataType::QASYMM8_SIGNED, DataType::F32, DataType::F16);
ARM_COMPUTE_RETURN_ERROR_ON_DATA_LAYOUT_NOT_IN(input, DataLayout::NHWC, DataLayout::NCHW);
ARM_COMPUTE_RETURN_ERROR_ON((pool_info.pooled_width() == 0) || (pool_info.pooled_height() == 0));
ARM_COMPUTE_RETURN_ERROR_ON_CPU_F16_UNSUPPORTED(input);
@@ -59,7 +59,7 @@ Status validate_arguments(const ITensorInfo *input, const ITensorInfo *rois, ITe
ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DIMENSIONS(compute_roi_align_shape(*input, *rois, pool_info), output->tensor_shape());
}
- if(input->data_type() == DataType::QASYMM8)
+ if(input->data_type() == DataType::QASYMM8 || input->data_type() == DataType::QASYMM8_SIGNED)
{
ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(rois, 1, DataType::QASYMM16);
@@ -116,7 +116,7 @@ Status NEROIAlignLayerKernel::validate(const ITensorInfo *input, const ITensorIn
}
/** Average pooling over an aligned window */
-template <typename input_data_type, DataLayout data_layout>
+template <typename input_data_type>
inline input_data_type roi_align_1x1(const ITensor *input,
unsigned int roi_batch,
float region_start_x,
@@ -135,7 +135,8 @@ inline input_data_type roi_align_1x1(const ITensor *input,
}
else
{
- float avg = 0;
+ const DataLayout data_layout = input->info()->data_layout();
+ float avg = 0;
// Iterate through the aligned pooling region
for(int iy = 0; iy < grid_size_y; ++iy)
{
@@ -185,7 +186,7 @@ inline input_data_type roi_align_1x1(const ITensor *input,
}
/** Average pooling over an aligned window */
-template <typename input_data_type, DataLayout data_layout>
+template <typename input_data_type>
inline input_data_type roi_align_1x1_qasymm8(const ITensor *input,
unsigned int roi_batch,
float region_start_x,
@@ -205,8 +206,11 @@ inline input_data_type roi_align_1x1_qasymm8(const ITensor *input,
}
else
{
- float avg = 0;
- const UniformQuantizationInfo input_qinfo = input->info()->quantization_info().uniform();
+ float avg = 0;
+ const UniformQuantizationInfo input_qinfo = input->info()->quantization_info().uniform();
+ const bool is_qasymm_signed = is_data_type_quantized_asymmetric_signed(input->info()->data_type());
+ const DataLayout data_layout = input->info()->data_layout();
+
// Iterate through the aligned pooling region
for(int iy = 0; iy < grid_size_y; ++iy)
{
@@ -234,26 +238,57 @@ inline input_data_type roi_align_1x1_qasymm8(const ITensor *input,
if(data_layout == DataLayout::NCHW)
{
- float data1 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_low, y_low, pz, roi_batch))), input_qinfo);
- float data2 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_high, y_low, pz, roi_batch))), input_qinfo);
- float data3 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_low, y_high, pz, roi_batch))), input_qinfo);
- float data4 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_high, y_high, pz, roi_batch))), input_qinfo);
- avg += w1 * data1 + w2 * data2 + w3 * data3 + w4 * data4;
+ if(is_qasymm_signed)
+ {
+ float data1 = dequantize_qasymm8_signed(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_low, y_low, pz, roi_batch))), input_qinfo);
+ float data2 = dequantize_qasymm8_signed(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_high, y_low, pz, roi_batch))), input_qinfo);
+ float data3 = dequantize_qasymm8_signed(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_low, y_high, pz, roi_batch))), input_qinfo);
+ float data4 = dequantize_qasymm8_signed(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_high, y_high, pz, roi_batch))), input_qinfo);
+ avg += w1 * data1 + w2 * data2 + w3 * data3 + w4 * data4;
+ }
+ else
+ {
+ float data1 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_low, y_low, pz, roi_batch))), input_qinfo);
+ float data2 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_high, y_low, pz, roi_batch))), input_qinfo);
+ float data3 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_low, y_high, pz, roi_batch))), input_qinfo);
+ float data4 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(x_high, y_high, pz, roi_batch))), input_qinfo);
+ avg += w1 * data1 + w2 * data2 + w3 * data3 + w4 * data4;
+ }
}
else
{
- const auto data1 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_low, y_low, roi_batch))), input_qinfo);
- const auto data2 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_high, y_low, roi_batch))), input_qinfo);
- const auto data3 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_low, y_high, roi_batch))), input_qinfo);
- const auto data4 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_high, y_high, roi_batch))), input_qinfo);
- avg += w1 * data1 + w2 * data2 + w3 * data3 + w4 * data4;
+ if(is_qasymm_signed)
+ {
+ const auto data1 = dequantize_qasymm8_signed(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_low, y_low, roi_batch))), input_qinfo);
+ const auto data2 = dequantize_qasymm8_signed(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_high, y_low, roi_batch))), input_qinfo);
+ const auto data3 = dequantize_qasymm8_signed(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_low, y_high, roi_batch))), input_qinfo);
+ const auto data4 = dequantize_qasymm8_signed(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_high, y_high, roi_batch))), input_qinfo);
+ avg += w1 * data1 + w2 * data2 + w3 * data3 + w4 * data4;
+ }
+ else
+ {
+ const auto data1 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_low, y_low, roi_batch))), input_qinfo);
+ const auto data2 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_high, y_low, roi_batch))), input_qinfo);
+ const auto data3 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_low, y_high, roi_batch))), input_qinfo);
+ const auto data4 = dequantize_qasymm8(*reinterpret_cast<const input_data_type *>(input->ptr_to_element(Coordinates(pz, x_high, y_high, roi_batch))), input_qinfo);
+ avg += w1 * data1 + w2 * data2 + w3 * data3 + w4 * data4;
+ }
}
}
}
avg /= grid_size_x * grid_size_y;
- return quantize_qasymm8(avg, out_qinfo);
+ input_data_type res = 0;
+ if(is_qasymm_signed)
+ {
+ res = quantize_qasymm8_signed(avg, out_qinfo);
+ }
+ else
+ {
+ res = quantize_qasymm8(avg, out_qinfo);
+ }
+ return res;
}
}
@@ -265,52 +300,30 @@ inline float compute_region_coordinate(int p, float bin_size, float roi_anchor,
void NEROIAlignLayerKernel::run(const Window &window, const ThreadInfo &info)
{
- if(_input->info()->data_layout() == DataLayout::NCHW)
+ const DataLayout data_layout = _input->info()->data_layout();
+ if(data_layout == DataLayout::NCHW || data_layout == DataLayout::NHWC)
{
switch(_input->info()->data_type())
{
case DataType::QASYMM8:
{
- NEROIAlignLayerKernel::internal_run<DataLayout::NCHW, uint8_t, uint16_t>(window, info);
- break;
- }
- case DataType::F32:
- {
- NEROIAlignLayerKernel::internal_run<DataLayout::NCHW, float>(window, info);
- break;
- }
-#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
- case DataType::F16:
- {
- NEROIAlignLayerKernel::internal_run<DataLayout::NCHW, float16_t>(window, info);
+ NEROIAlignLayerKernel::internal_run<uint8_t, uint16_t>(window, info);
break;
}
-#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
- default:
- {
- ARM_COMPUTE_ERROR("DataType not supported");
- break;
- }
- }
- }
- else if(_input->info()->data_layout() == DataLayout::NHWC)
- {
- switch(_input->info()->data_type())
- {
- case DataType::QASYMM8:
+ case DataType::QASYMM8_SIGNED:
{
- NEROIAlignLayerKernel::internal_run<DataLayout::NHWC, uint8_t, uint16_t>(window, info);
+ NEROIAlignLayerKernel::internal_run<int8_t, uint16_t>(window, info);
break;
}
case DataType::F32:
{
- NEROIAlignLayerKernel::internal_run<DataLayout::NHWC, float>(window, info);
+ NEROIAlignLayerKernel::internal_run<float>(window, info);
break;
}
#ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
case DataType::F16:
{
- NEROIAlignLayerKernel::internal_run<DataLayout::NHWC, float16_t>(window, info);
+ NEROIAlignLayerKernel::internal_run<float16_t>(window, info);
break;
}
#endif // __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
@@ -327,21 +340,22 @@ void NEROIAlignLayerKernel::run(const Window &window, const ThreadInfo &info)
}
}
-template <DataLayout data_layout, typename input_data_type, typename roi_data_type>
+template <typename input_data_type, typename roi_data_type>
void NEROIAlignLayerKernel::internal_run(const Window &window, const ThreadInfo &info)
{
ARM_COMPUTE_UNUSED(info);
ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(INEKernel::window(), window);
- const size_t values_per_roi = _rois->info()->dimension(0);
+ const DataLayout data_layout = _input->info()->data_layout();
+ const size_t values_per_roi = _rois->info()->dimension(0);
const int roi_list_start = window.x().start();
const int roi_list_end = window.x().end();
- const unsigned int idx_width = get_data_layout_dimension_index(_input->info()->data_layout(), DataLayoutDimension::WIDTH);
- const unsigned int idx_height = get_data_layout_dimension_index(_input->info()->data_layout(), DataLayoutDimension::HEIGHT);
- const unsigned int idx_depth = get_data_layout_dimension_index(_input->info()->data_layout(), DataLayoutDimension::CHANNEL);
+ const unsigned int idx_width = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH);
+ const unsigned int idx_height = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT);
+ const unsigned int idx_depth = get_data_layout_dimension_index(data_layout, DataLayoutDimension::CHANNEL);
const int input_width = _input->info()->dimension(idx_width);
const int input_height = _input->info()->dimension(idx_height);
@@ -397,14 +411,14 @@ void NEROIAlignLayerKernel::internal_run(const Window &window, const ThreadInfo
input_data_type out_val(0);
if(is_qasymm)
{
- out_val = roi_align_1x1_qasymm8<input_data_type, data_layout>(
+ out_val = roi_align_1x1_qasymm8<input_data_type>(
_input, roi_batch, region_start_x, bin_size_x,
roi_bin_grid_x, region_end_x, region_start_y, bin_size_y,
roi_bin_grid_y, region_end_y, ch, _output->info()->quantization_info());
}
else
{
- out_val = roi_align_1x1<input_data_type, data_layout>(
+ out_val = roi_align_1x1<input_data_type>(
_input, roi_batch, region_start_x, bin_size_x,
roi_bin_grid_x, region_end_x, region_start_y, bin_size_y,
roi_bin_grid_y, region_end_y, ch);
diff --git a/src/core/NEON/kernels/NEROIAlignLayerKernel.h b/src/core/NEON/kernels/NEROIAlignLayerKernel.h
index d909fb1758..fa31a879b7 100644
--- a/src/core/NEON/kernels/NEROIAlignLayerKernel.h
+++ b/src/core/NEON/kernels/NEROIAlignLayerKernel.h
@@ -55,10 +55,10 @@ public:
/** Set the input and output tensors.
*
- * @param[in] input Source tensor. Data types supported: QASYMM8/F16/F32.
+ * @param[in] input Source tensor. Data types supported: QASYMM8/QASYMM8_SIGNED/F16/F32.
* @param[in] rois ROIs tensor, it is a 2D tensor of size [5, N] (where N is the number of ROIs) containing top left and bottom right corner
* as coordinate of an image and batch_id of ROI [ batch_id, x1, y1, x2, y2 ].
- * Data types supported: QASYMM16 with scale of 0.125 and 0 offset if @p input is QASYMM8, otherwise same as @p input
+ * Data types supported: QASYMM16 with scale of 0.125 and 0 offset if @p input is QASYMM8/QASYMM8_SIGNED, otherwise same as @p input
* @param[out] output Destination tensor. Data types supported: Same as @p input.
* @param[in] pool_info Contains pooling operation information described in @ref ROIPoolingLayerInfo.
*
@@ -70,8 +70,8 @@ public:
void configure(const ITensor *input, const ITensor *rois, ITensor *output, const ROIPoolingLayerInfo &pool_info);
/** Static function to check if given info will lead to a valid configuration of @ref NEROIAlignLayerKernel
*
- * @param[in] input Source tensor info. Data types supported: QASYMM8/F16/F32.
- * @param[in] rois ROIs tensor info. Data types supported: QASYMM16 with scale of 0.125 and 0 offset if @p input is QASYMM8,
+ * @param[in] input Source tensor info. Data types supported: QASYMM8/QASYMM8_SIGNED/F16/F32.
+ * @param[in] rois ROIs tensor info. Data types supported: QASYMM16 with scale of 0.125 and 0 offset if @p input is QASYMM8/QASYMM8_SIGNED,
* otherwise same as @p input
* @param[in] output Destination tensor info. Data types supported: Same as @p input.
* @param[in] pool_info Contains pooling operation information described in @ref ROIPoolingLayerInfo.
@@ -89,7 +89,7 @@ public:
void run(const Window &window, const ThreadInfo &info) override;
private:
- template <DataLayout data_layout, typename input_data_type, typename roi_data_type = input_data_type>
+ template <typename input_data_type, typename roi_data_type = input_data_type>
void internal_run(const Window &window, const ThreadInfo &info);
const ITensor *_input;
diff --git a/tests/validation/NEON/ROIAlignLayer.cpp b/tests/validation/NEON/ROIAlignLayer.cpp
index 3f6c9d2082..e475c46c7d 100644
--- a/tests/validation/NEON/ROIAlignLayer.cpp
+++ b/tests/validation/NEON/ROIAlignLayer.cpp
@@ -129,10 +129,10 @@ FIXTURE_DATA_TEST_CASE(SmallROIAlignLayerHalf, NEROIAlignLayerHalfFixture, frame
TEST_SUITE_END() // Float
TEST_SUITE(Quantized)
-TEST_SUITE(QASYMM8)
template <typename T>
using NEROIAlignLayerQuantizedFixture = ROIAlignLayerQuantizedFixture<Tensor, Accessor, NEROIAlignLayer, T, uint16_t>;
+TEST_SUITE(QASYMM8)
FIXTURE_DATA_TEST_CASE(Small, NEROIAlignLayerQuantizedFixture<uint8_t>, framework::DatasetMode::ALL,
combine(combine(combine(combine(datasets::SmallROIDataset(),
framework::dataset::make("DataType", { DataType::QASYMM8 })),
@@ -144,6 +144,19 @@ FIXTURE_DATA_TEST_CASE(Small, NEROIAlignLayerQuantizedFixture<uint8_t>, framewor
validate(Accessor(_target), _reference, tolerance_qasymm8);
}
TEST_SUITE_END() // QASYMM8
+
+TEST_SUITE(QASYMM8_SIGNED)
+FIXTURE_DATA_TEST_CASE(Small, NEROIAlignLayerQuantizedFixture<int8_t>, framework::DatasetMode::ALL,
+ combine(combine(combine(combine(datasets::SmallROIDataset(),
+ framework::dataset::make("DataType", { DataType::QASYMM8_SIGNED })),
+ framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
+ framework::dataset::make("InputQuantizationInfo", { QuantizationInfo(1.f / 255.f, 127) })),
+ framework::dataset::make("OutputQuantizationInfo", { QuantizationInfo(2.f / 255.f, 120) })))
+{
+ // Validate output
+ validate(Accessor(_target), _reference, tolerance_qasymm8);
+}
+TEST_SUITE_END() // QASYMM8_SIGNED
TEST_SUITE_END() // Quantized
TEST_SUITE_END() // RoiAlign