COMPMID-2456: NEDeconvolutionLayer.cpp, NHWC is not supported

Support of NHWC for NEDeconvolutionLayer
Bugfix for QASYMM8 in CPPUpsample when offset is different than 0
QASYMM8 tests added in NEUpsample with offset different than 0

Change-Id: I8283fa5e5e323fd4d5777136359ddb33025674bb
Signed-off-by: Manuel Bottini <manuel.bottini@arm.com>
Reviewed-on: https://review.mlplatform.org/c/1517
Comments-Addressed: Arm Jenkins <bsgcomp@arm.com>
Tested-by: Arm Jenkins <bsgcomp@arm.com>
Reviewed-by: Pablo Marquez <pablo.tello@arm.com>
diff --git a/tests/validation/NEON/DeconvolutionLayer.cpp b/tests/validation/NEON/DeconvolutionLayer.cpp
index 4d0ce63..34a1bf5 100644
--- a/tests/validation/NEON/DeconvolutionLayer.cpp
+++ b/tests/validation/NEON/DeconvolutionLayer.cpp
@@ -62,7 +62,7 @@
 const auto data1x1 = datasets::SmallDeconvolutionShapes() * framework::dataset::make("StrideX", 1, 4) * framework::dataset::make("StrideY", 1, 4) * framework::dataset::make("PadX", 0, 1)
                      * framework::dataset::make("PadY", 0, 1) * framework::dataset::make("NumKernels", { 3 });
 
-const auto data_layouts_dataset = framework::dataset::make("DataLayout", { DataLayout::NCHW });
+const auto data_layouts_dataset = framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC });
 } // namespace
 
 TEST_SUITE(NEON)
@@ -250,7 +250,7 @@
 FIXTURE_DATA_TEST_CASE(Run, NEDeconvolutionLayerQuantizedFixture4x4<uint8_t>, framework::DatasetMode::NIGHTLY, combine(combine(combine(data4x4, framework::dataset::make("DataType",
                                                                                                                        DataType::QASYMM8)),
                                                                                                                        data_layouts_dataset),
-                                                                                                                       framework::dataset::make("QuantizationInfo", QuantizationInfo(2.f / 255.f, 0))))
+                                                                                                                       framework::dataset::make("QuantizationInfo", QuantizationInfo(2.f / 255.f, 10))))
 {
     // Validate output
     validate(Accessor(_target), _reference, tolerance_qasymm8, tolerance_num);
@@ -261,7 +261,7 @@
 FIXTURE_DATA_TEST_CASE(RunSmall, NEDeconvolutionLayerQuantizedFixture3x3<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(data3x3_precommit, framework::dataset::make("DataType",
                        DataType::QASYMM8)),
                        data_layouts_dataset),
-                       framework::dataset::make("QuantizationInfo", QuantizationInfo(2.f / 255.f, 0))))
+                       framework::dataset::make("QuantizationInfo", QuantizationInfo(2.f / 255.f, 10))))
 {
     // Validate output
     validate(Accessor(_target), _reference, tolerance_qasymm8, tolerance_num);
@@ -269,7 +269,7 @@
 FIXTURE_DATA_TEST_CASE(RunLarge, NEDeconvolutionLayerQuantizedFixture3x3<uint8_t>, framework::DatasetMode::NIGHTLY, combine(combine(combine(data3x3, framework::dataset::make("DataType",
                        DataType::QASYMM8)),
                        data_layouts_dataset),
-                       framework::dataset::make("QuantizationInfo", QuantizationInfo(2.f / 255.f, 0))))
+                       framework::dataset::make("QuantizationInfo", QuantizationInfo(2.f / 255.f, 10))))
 {
     // Validate output
     validate(Accessor(_target), _reference, tolerance_qasymm8, tolerance_num);
@@ -280,7 +280,7 @@
 FIXTURE_DATA_TEST_CASE(Run, NEDeconvolutionLayerQuantizedFixture1x1<uint8_t>, framework::DatasetMode::NIGHTLY, combine(combine(combine(data1x1, framework::dataset::make("DataType",
                                                                                                                        DataType::QASYMM8)),
                                                                                                                        data_layouts_dataset),
-                                                                                                                       framework::dataset::make("QuantizationInfo", QuantizationInfo(2.f / 255.f, 0))))
+                                                                                                                       framework::dataset::make("QuantizationInfo", QuantizationInfo(2.f / 255.f, 10))))
 {
     // Validate output
     validate(Accessor(_target), _reference, tolerance_qasymm8, tolerance_num);
diff --git a/tests/validation/NEON/Upsample.cpp b/tests/validation/NEON/Upsample.cpp
index 39b69ee..9ddfbe0 100644
--- a/tests/validation/NEON/Upsample.cpp
+++ b/tests/validation/NEON/Upsample.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 ARM Limited.
+ * Copyright (c) 2018-2019 ARM Limited.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -105,6 +105,9 @@
 template <typename T>
 using NEUpsampleLayerFixture = UpsampleLayerFixture<Tensor, Accessor, NEUpsampleLayer, T>;
 
+template <typename T>
+using NEUpsampleLayerQuantizedFixture = UpsampleLayerQuantizedFixture<Tensor, Accessor, NEUpsampleLayer, T>;
+
 TEST_SUITE(Float)
 TEST_SUITE(FP32)
 FIXTURE_DATA_TEST_CASE(RunSmall, NEUpsampleLayerFixture<float>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(datasets::SmallShapes(),
@@ -136,11 +139,12 @@
 
 TEST_SUITE(Quantized)
 TEST_SUITE(QASYMM8)
-FIXTURE_DATA_TEST_CASE(RunSmall, NEUpsampleLayerFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(datasets::SmallShapes(),
-                                                                                                                     framework::dataset::make("DataType", DataType::QASYMM8)),
-                                                                                                                     framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
-                                                                                                                     framework::dataset::make("PadInfo", { Size2D(2, 2) })),
-                                                                                                             framework::dataset::make("UpsamplingPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR })))
+FIXTURE_DATA_TEST_CASE(RunSmall, NEUpsampleLayerQuantizedFixture<uint8_t>, framework::DatasetMode::PRECOMMIT, combine(combine(combine(combine(combine(datasets::SmallShapes(),
+                                                                                                                      framework::dataset::make("DataType", DataType::QASYMM8)),
+                                                                                                                      framework::dataset::make("DataLayout", { DataLayout::NCHW, DataLayout::NHWC })),
+                                                                                                                      framework::dataset::make("PadInfo", { Size2D(2, 2) })),
+                                                                                                                      framework::dataset::make("UpsamplingPolicy", { InterpolationPolicy::NEAREST_NEIGHBOR })),
+                                                                                                                      framework::dataset::make("QuantizationInfo", QuantizationInfo(2.f / 255.f, 10))))
 {
     // Validate output
     validate(Accessor(_target), _reference);
diff --git a/tests/validation/fixtures/UpsampleLayerFixture.h b/tests/validation/fixtures/UpsampleLayerFixture.h
index 40229e2..0a72e44 100644
--- a/tests/validation/fixtures/UpsampleLayerFixture.h
+++ b/tests/validation/fixtures/UpsampleLayerFixture.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 ARM Limited.
+ * Copyright (c) 2018-2019 ARM Limited.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -40,37 +40,51 @@
 namespace validation
 {
 template <typename TensorType, typename AccessorType, typename FunctionType, typename T>
-class UpsampleLayerFixture : public framework::Fixture
+class UpsampleLayerFixtureBase : public framework::Fixture
 {
 public:
     template <typename...>
     void setup(TensorShape input_shape, DataType data_type, DataLayout data_layout,
-               Size2D info, const InterpolationPolicy &policy)
+               Size2D info, const InterpolationPolicy &policy, QuantizationInfo quantization_info)
     {
         _data_type = data_type;
 
-        _target    = compute_target(input_shape, info, policy, data_type, data_layout);
-        _reference = compute_reference(input_shape, info, policy, data_type);
+        _target    = compute_target(input_shape, info, policy, data_type, data_layout, quantization_info);
+        _reference = compute_reference(input_shape, info, policy, data_type, quantization_info);
     }
 
 protected:
     template <typename U>
     void fill(U &&tensor, int i)
     {
-        library->fill_tensor_uniform(tensor, i);
+        if(_data_type == DataType::QASYMM8)
+        {
+            const auto                             bounds = get_quantized_bounds(tensor.quantization_info(), -1.0f, 1.0f);
+            std::uniform_int_distribution<uint8_t> distribution(bounds.first, bounds.second);
+            library->fill(tensor, distribution, i);
+        }
+        else
+        {
+            library->fill_tensor_uniform(tensor, i);
+        }
     }
 
-    TensorType compute_target(TensorShape   input_shape,
-                              const Size2D &info, const InterpolationPolicy &policy, DataType data_type, DataLayout data_layout)
+    TensorType compute_target(TensorShape input_shape, const Size2D &info, const InterpolationPolicy &policy,
+                              DataType data_type, DataLayout data_layout, QuantizationInfo quantization_info)
     {
+        TensorShape output_shape(input_shape);
+        output_shape.set(0, info.x() * input_shape[0]);
+        output_shape.set(1, info.y() * input_shape[1]);
+
         if(data_layout == DataLayout::NHWC)
         {
             permute(input_shape, PermutationVector(2U, 0U, 1U));
+            permute(output_shape, PermutationVector(2U, 0U, 1U));
         }
 
         // Create tensors
-        TensorType src = create_tensor<TensorType>(input_shape, data_type, 1, QuantizationInfo(), data_layout);
-        TensorType dst;
+        TensorType src = create_tensor<TensorType>(input_shape, data_type, 1, quantization_info, data_layout);
+        TensorType dst = create_tensor<TensorType>(output_shape, data_type, 1, quantization_info, data_layout);
 
         // Create and configure function
         FunctionType upsample;
@@ -95,11 +109,11 @@
         return dst;
     }
 
-    SimpleTensor<T> compute_reference(const TensorShape &input_shape,
-                                      const Size2D &info, const InterpolationPolicy &policy, DataType data_type)
+    SimpleTensor<T> compute_reference(const TensorShape &input_shape, const Size2D &info, const InterpolationPolicy &policy,
+                                      DataType data_type, QuantizationInfo quantization_info)
     {
         // Create reference
-        SimpleTensor<T> src{ input_shape, data_type };
+        SimpleTensor<T> src{ input_shape, data_type, 1, quantization_info };
 
         // Fill reference
         fill(src, 0);
@@ -111,6 +125,33 @@
     SimpleTensor<T> _reference{};
     DataType        _data_type{};
 };
+
+template <typename TensorType, typename AccessorType, typename FunctionType, typename T>
+class UpsampleLayerFixture : public UpsampleLayerFixtureBase<TensorType, AccessorType, FunctionType, T>
+{
+public:
+    template <typename...>
+    void setup(TensorShape input_shape, DataType data_type, DataLayout data_layout,
+               Size2D info, const InterpolationPolicy &policy)
+    {
+        UpsampleLayerFixtureBase<TensorType, AccessorType, FunctionType, T>::setup(input_shape, data_type, data_layout,
+                                                                                   info, policy, QuantizationInfo());
+    }
+};
+
+template <typename TensorType, typename AccessorType, typename FunctionType, typename T>
+class UpsampleLayerQuantizedFixture : public UpsampleLayerFixtureBase<TensorType, AccessorType, FunctionType, T>
+{
+public:
+    template <typename...>
+    void setup(TensorShape input_shape, DataType data_type, DataLayout data_layout,
+               Size2D info, const InterpolationPolicy &policy, QuantizationInfo quantization_info)
+    {
+        UpsampleLayerFixtureBase<TensorType, AccessorType, FunctionType, T>::setup(input_shape, data_type, data_layout,
+                                                                                   info, policy, quantization_info);
+    }
+};
+
 } // namespace validation
 } // namespace test
 } // namespace arm_compute
diff --git a/tests/validation/reference/UpsampleLayer.cpp b/tests/validation/reference/UpsampleLayer.cpp
index 876f6d7..8e36ee8 100644
--- a/tests/validation/reference/UpsampleLayer.cpp
+++ b/tests/validation/reference/UpsampleLayer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 ARM Limited.
+ * Copyright (c) 2018-2019 ARM Limited.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -33,9 +33,10 @@
 {
 namespace reference
 {
+namespace
+{
 template <typename T>
-SimpleTensor<T> upsample_layer(const SimpleTensor<T> &src,
-                               const Size2D &info, const InterpolationPolicy policy)
+SimpleTensor<T> upsample_function(const SimpleTensor<T> &src, const Size2D &info, const InterpolationPolicy policy)
 {
     ARM_COMPUTE_ERROR_ON(policy != InterpolationPolicy::NEAREST_NEIGHBOR);
     ARM_COMPUTE_UNUSED(policy);
@@ -72,16 +73,39 @@
             }
         }
     }
-
     return out;
 }
 
+} // namespace
+
+template <typename T>
+SimpleTensor<T> upsample_layer(const SimpleTensor<T> &src, const Size2D &info, const InterpolationPolicy policy)
+{
+    return upsample_function<T>(src, info, policy);
+}
+
+template <>
+SimpleTensor<uint8_t> upsample_layer(const SimpleTensor<uint8_t> &src, const Size2D &info, const InterpolationPolicy policy)
+{
+    SimpleTensor<uint8_t> dst(src.shape(), src.data_type(), 1, src.quantization_info());
+
+    if(is_data_type_quantized_asymmetric(src.data_type()))
+    {
+        SimpleTensor<float> src_tmp = convert_from_asymmetric(src);
+        SimpleTensor<float> dst_tmp = upsample_function<float>(src_tmp, info, policy);
+        dst                         = convert_to_asymmetric(dst_tmp, src.quantization_info());
+    }
+    else
+    {
+        dst = upsample_function<uint8_t>(src, info, policy);
+    }
+    return dst;
+}
+
 template SimpleTensor<float> upsample_layer(const SimpleTensor<float> &src,
                                             const Size2D &info, const InterpolationPolicy policy);
 template SimpleTensor<half> upsample_layer(const SimpleTensor<half> &src,
                                            const Size2D &info, const InterpolationPolicy policy);
-template SimpleTensor<uint8_t> upsample_layer(const SimpleTensor<uint8_t> &src,
-                                              const Size2D &info, const InterpolationPolicy policy);
 } // namespace reference
 } // namespace validation
 } // namespace test