aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Bottini <manuel.bottini@arm.com>2019-07-10 17:06:12 +0100
committerManuel Bottini <manuel.bottini@arm.com>2019-07-19 09:49:54 +0000
commitd25af6786c0a714f2b4f099d0338dab17a5dc7e1 (patch)
treeb8a1eafa1d01be903a238fff92ad6acd34b6a499
parentdb9116ff15170ff734aad0300b46c48abc2a3b7b (diff)
downloadComputeLibrary-d25af6786c0a714f2b4f099d0338dab17a5dc7e1.tar.gz
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>
-rw-r--r--arm_compute/runtime/NEON/functions/NEDeconvolutionLayer.h7
-rw-r--r--src/core/CPP/kernels/CPPUpsampleKernel.cpp10
-rw-r--r--src/runtime/NEON/functions/NEDeconvolutionLayer.cpp142
-rw-r--r--tests/validation/NEON/DeconvolutionLayer.cpp10
-rw-r--r--tests/validation/NEON/Upsample.cpp16
-rw-r--r--tests/validation/fixtures/UpsampleLayerFixture.h67
-rw-r--r--tests/validation/reference/UpsampleLayer.cpp36
7 files changed, 225 insertions, 63 deletions
diff --git a/arm_compute/runtime/NEON/functions/NEDeconvolutionLayer.h b/arm_compute/runtime/NEON/functions/NEDeconvolutionLayer.h
index 62977a7647..360bb23f22 100644
--- a/arm_compute/runtime/NEON/functions/NEDeconvolutionLayer.h
+++ b/arm_compute/runtime/NEON/functions/NEDeconvolutionLayer.h
@@ -118,8 +118,15 @@ private:
NEConvolutionLayer _conv_f;
CPPUpsample _upsample_f;
CPPFlipWeightsKernel _flip_weights;
+ NEPermute _permute_input;
+ NEPermute _permute_weights;
+ NEPermute _permute_output;
Tensor _scaled_output;
Tensor _weights_flipped;
+ Tensor _permuted_input;
+ Tensor _permuted_weights;
+ Tensor _permuted_output;
+ bool _is_nchw;
const ITensor *_original_weights;
ITensor *_input;
PadStrideInfo _info;
diff --git a/src/core/CPP/kernels/CPPUpsampleKernel.cpp b/src/core/CPP/kernels/CPPUpsampleKernel.cpp
index 6620ce2aeb..ad2d54a0f8 100644
--- a/src/core/CPP/kernels/CPPUpsampleKernel.cpp
+++ b/src/core/CPP/kernels/CPPUpsampleKernel.cpp
@@ -34,8 +34,8 @@
#include <cstddef>
#include <cstdint>
-using namespace arm_compute;
-
+namespace arm_compute
+{
CPPUpsampleKernel::CPPUpsampleKernel()
: _input(nullptr), _output(nullptr), _info()
{
@@ -82,7 +82,10 @@ void CPPUpsampleKernel::run(const Window &window, const ThreadInfo &info)
const int end_x = width_scaled - _info.pad().first;
const size_t element_size = _input->info()->element_size();
- std::fill_n(_output->buffer(), _output->info()->total_size(), 0);
+ //The fill value is normally 0, but for QASYMM8 the '0' corresponds to the offset
+ const uint8_t fill_value = _output->info()->data_type() == DataType::QASYMM8 ? utility::clamp<uint8_t>(_output->info()->quantization_info().uniform().offset) : 0;
+ //Filling a value different than 0 works only for QASYMM8 datatype since we are filling 1byte values in a buffer of uint8_ts
+ std::fill_n(_output->buffer(), _output->info()->total_size(), fill_value);
// Create window
Window window_out(window);
@@ -99,3 +102,4 @@ void CPPUpsampleKernel::run(const Window &window, const ThreadInfo &info)
},
in, out);
}
+} // namespace arm_compute \ No newline at end of file
diff --git a/src/runtime/NEON/functions/NEDeconvolutionLayer.cpp b/src/runtime/NEON/functions/NEDeconvolutionLayer.cpp
index 7bbacb139c..581f257581 100644
--- a/src/runtime/NEON/functions/NEDeconvolutionLayer.cpp
+++ b/src/runtime/NEON/functions/NEDeconvolutionLayer.cpp
@@ -38,8 +38,15 @@ NEDeconvolutionLayer::NEDeconvolutionLayer(std::shared_ptr<IMemoryManager> memor
_conv_f(),
_upsample_f(),
_flip_weights(),
+ _permute_input(),
+ _permute_weights(),
+ _permute_output(),
_scaled_output(),
_weights_flipped(),
+ _permuted_input(),
+ _permuted_weights(),
+ _permuted_output(),
+ _is_nchw(false),
_original_weights(nullptr),
_input(nullptr),
_info(),
@@ -52,18 +59,20 @@ Status NEDeconvolutionLayer::validate(const ITensorInfo *input, const ITensorInf
ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, weights, output);
ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32, DataType::F16, DataType::QASYMM8);
ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(weights, input);
- ARM_COMPUTE_RETURN_ERROR_ON(weights->dimension(0) != weights->dimension(1));
- ARM_COMPUTE_RETURN_ERROR_ON(weights->dimension(0) < 1);
+ ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_LAYOUT(weights, input);
+ const unsigned int width_idx = get_data_layout_dimension_index(weights->data_layout(), DataLayoutDimension::WIDTH);
+ const unsigned int height_idx = get_data_layout_dimension_index(weights->data_layout(), DataLayoutDimension::HEIGHT);
+ ARM_COMPUTE_RETURN_ERROR_ON(weights->dimension(width_idx) != weights->dimension(height_idx));
+ ARM_COMPUTE_RETURN_ERROR_ON(weights->dimension(width_idx) < 1);
ARM_COMPUTE_RETURN_ERROR_ON(!info.padding_is_symmetric());
const unsigned int stride_x = info.stride().first;
const unsigned int stride_y = info.stride().second;
- auto out_dims = deconvolution_output_dimensions(input->dimension(0), input->dimension(1), weights->dimension(0), weights->dimension(1),
+ auto out_dims = deconvolution_output_dimensions(input->dimension(width_idx), input->dimension(height_idx), weights->dimension(width_idx), weights->dimension(height_idx),
info.pad().first, info.pad().second, stride_x, stride_y);
ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, weights);
-
if(is_data_type_quantized_asymmetric(input->data_type()))
{
ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(bias, 1, DataType::S32);
@@ -90,10 +99,10 @@ Status NEDeconvolutionLayer::validate(const ITensorInfo *input, const ITensorInf
TensorInfo scale_out_info(input->clone()->set_is_resizable(true).reset_padding().set_tensor_shape(scale_out_shape));
const PadStrideInfo conv_info(1, 1, 0, 0, 0, 0, DimensionRoundingType::CEIL);
- for(size_t i = 2; i < Coordinates::num_max_dimensions; ++i)
- {
- ARM_COMPUTE_RETURN_ERROR_ON(input->dimension(i) != scale_out_info.dimension(i));
- }
+ const unsigned int batches_idx = get_data_layout_dimension_index(weights->data_layout(), DataLayoutDimension::BATCHES);
+ const unsigned int channel_idx = get_data_layout_dimension_index(weights->data_layout(), DataLayoutDimension::CHANNEL);
+ ARM_COMPUTE_RETURN_ERROR_ON(input->dimension(batches_idx) != scale_out_info.dimension(batches_idx));
+ ARM_COMPUTE_RETURN_ERROR_ON(input->dimension(channel_idx) != scale_out_info.dimension(channel_idx));
ARM_COMPUTE_RETURN_ON_ERROR(NEConvolutionLayer::validate(&scale_out_info, weights, bias, output, conv_info, WeightsInfo()));
@@ -103,21 +112,24 @@ Status NEDeconvolutionLayer::validate(const ITensorInfo *input, const ITensorInf
void NEDeconvolutionLayer::configure(ITensor *input, const ITensor *weights, const ITensor *bias, ITensor *output, const PadStrideInfo &info)
{
ARM_COMPUTE_ERROR_ON_NULLPTR(input, weights, output);
+ ARM_COMPUTE_ERROR_THROW_ON(NEDeconvolutionLayer::validate(input->info(), weights->info(), bias->info(), output->info(), info));
+
+ const DataLayout data_layout = input->info()->data_layout();
_input = input;
_original_weights = weights;
_info = info;
_is_prepared = false;
+ _is_nchw = data_layout == DataLayout::NCHW;
- const DataLayout data_layout = input->info()->data_layout();
- const unsigned int stride_x = info.stride().first;
- const unsigned int stride_y = info.stride().second;
+ const unsigned int stride_x = info.stride().first;
+ const unsigned int stride_y = info.stride().second;
- _weights_flipped.allocator()->init(weights->info()->clone()->set_data_layout(data_layout));
- _flip_weights.configure(weights, &_weights_flipped);
-
- auto out_dims = deconvolution_output_dimensions(input->info()->dimension(0), input->info()->dimension(1), weights->info()->dimension(0), weights->info()->dimension(1),
- info.pad().first, info.pad().second, stride_x, stride_y);
+ const unsigned int width_idx = get_data_layout_dimension_index(data_layout, DataLayoutDimension::WIDTH);
+ const unsigned int height_idx = get_data_layout_dimension_index(data_layout, DataLayoutDimension::HEIGHT);
+ auto out_dims = deconvolution_output_dimensions(input->info()->dimension(width_idx), input->info()->dimension(height_idx), weights->info()->dimension(width_idx),
+ weights->info()->dimension(height_idx),
+ info.pad().first, info.pad().second, stride_x, stride_y);
const TensorShape output_shape = compute_deconvolution_output_shape(out_dims, *input->info(), *weights->info());
// Output auto initialization if not yet initialized
@@ -128,20 +140,73 @@ void NEDeconvolutionLayer::configure(ITensor *input, const ITensor *weights, con
_memory_group.manage(&_scaled_output);
- // Find the upsampled dimensions and the padding needed for the convolution with stride 1 in order to match output shape
- unsigned int padx = 0;
- unsigned int pady = 0;
- const TensorShape scale_out_shape = compute_deconvolution_upsampled_shape(*input->info(), *weights->info(), stride_x, stride_y, out_dims, padx, pady);
-
- TensorInfo scale_out_info(scale_out_shape, 1, input->info()->data_type(), input->info()->quantization_info());
- _scaled_output.allocator()->init(scale_out_info);
-
- const PadStrideInfo upsample_info(stride_x, stride_y, padx / 2, pady / 2);
- _upsample_f.configure(input, &_scaled_output, upsample_info);
-
- // setup the function to convolve the upscaled output
- const PadStrideInfo conv_info(1, 1, 0, 0, 0, 0, DimensionRoundingType::CEIL);
- _conv_f.configure(&_scaled_output, &_weights_flipped, bias, output, conv_info);
+ if(!_is_nchw)
+ {
+ _memory_group.manage(&_permuted_input);
+ _memory_group.manage(&_permuted_weights);
+ _memory_group.manage(&_permuted_output);
+
+ // Configure the function to transform the input tensor from NHWC -> NCHW
+ _permuted_input.info()->set_quantization_info(input->info()->quantization_info());
+ _permute_input.configure(input, &_permuted_input, PermutationVector(1U, 2U, 0U));
+ _permuted_input.info()->set_data_layout(DataLayout::NCHW);
+
+ // Configure the function to transform the weights tensor from NHWC -> NCHW
+ _permuted_weights.info()->set_quantization_info(weights->info()->quantization_info());
+ _permute_weights.configure(weights, &_permuted_weights, PermutationVector(1U, 2U, 0U));
+ _permuted_weights.info()->set_data_layout(DataLayout::NCHW);
+
+ // Find the upsampled dimensions and the padding needed for the convolution with stride 1 in order to match output shape
+ unsigned int padx = 0;
+ unsigned int pady = 0;
+ const TensorShape scale_out_shape = compute_deconvolution_upsampled_shape(*_permuted_input.info(), *_permuted_weights.info(), stride_x, stride_y, out_dims, padx,
+ pady);
+
+ TensorInfo scale_out_info(scale_out_shape, 1, _permuted_input.info()->data_type(), _permuted_input.info()->quantization_info());
+ scale_out_info.set_data_layout(DataLayout::NCHW);
+ _scaled_output.allocator()->init(scale_out_info);
+
+ const PadStrideInfo upsample_info(stride_x, stride_y, padx / 2, pady / 2);
+ _upsample_f.configure(&_permuted_input, &_scaled_output, upsample_info);
+
+ _weights_flipped.allocator()->init(*_permuted_weights.info()->clone());
+ _weights_flipped.info()->set_quantization_info(weights->info()->quantization_info());
+ _flip_weights.configure(&_permuted_weights, &_weights_flipped);
+
+ // setup the function to convolve the upscaled output
+ const PadStrideInfo conv_info(1, 1, 0, 0, 0, 0, DimensionRoundingType::CEIL);
+
+ _permuted_output.info()->set_quantization_info(output->info()->quantization_info());
+ _conv_f.configure(&_scaled_output, &_weights_flipped, bias, &_permuted_output, conv_info);
+ _permuted_output.info()->set_data_layout(DataLayout::NCHW);
+
+ // Configure the function to transform the convoluted output to NHWC
+ _permute_output.configure(&_permuted_output, output, PermutationVector(2U, 0U, 1U));
+
+ _permuted_input.allocator()->allocate();
+ _permuted_weights.allocator()->allocate();
+ _permuted_output.allocator()->allocate();
+ }
+ else
+ {
+ // Find the upsampled dimensions and the padding needed for the convolution with stride 1 in order to match output shape
+ unsigned int padx = 0;
+ unsigned int pady = 0;
+ const TensorShape scale_out_shape = compute_deconvolution_upsampled_shape(*input->info(), *weights->info(), stride_x, stride_y, out_dims, padx, pady);
+
+ TensorInfo scale_out_info(scale_out_shape, 1, input->info()->data_type(), input->info()->quantization_info());
+ scale_out_info.set_data_layout(data_layout);
+ _scaled_output.allocator()->init(scale_out_info);
+ const PadStrideInfo upsample_info(stride_x, stride_y, padx / 2, pady / 2);
+ _upsample_f.configure(input, &_scaled_output, upsample_info);
+
+ _weights_flipped.allocator()->init(weights->info()->clone()->set_data_layout(data_layout));
+ _flip_weights.configure(weights, &_weights_flipped);
+
+ // setup the function to convolve the upscaled output
+ const PadStrideInfo conv_info(1, 1, 0, 0, 0, 0, DimensionRoundingType::CEIL);
+ _conv_f.configure(&_scaled_output, &_weights_flipped, bias, output, conv_info);
+ }
_scaled_output.allocator()->allocate();
}
@@ -151,8 +216,20 @@ void NEDeconvolutionLayer::run()
MemoryGroupResourceScope scope_mg(_memory_group);
+ // Permute input
+ if(!_is_nchw)
+ {
+ _permute_input.run();
+ }
+
_upsample_f.run();
_conv_f.run();
+
+ // Permute output
+ if(!_is_nchw)
+ {
+ _permute_output.run();
+ }
}
void NEDeconvolutionLayer::prepare()
@@ -163,6 +240,11 @@ void NEDeconvolutionLayer::prepare()
// Run weights flipping and mark original weights tensor as unused
_weights_flipped.allocator()->allocate();
+ // Permute weights
+ if(!_is_nchw)
+ {
+ _permute_weights.run();
+ }
NEScheduler::get().schedule(&_flip_weights, Window::DimZ);
_original_weights->mark_as_unused();
diff --git a/tests/validation/NEON/DeconvolutionLayer.cpp b/tests/validation/NEON/DeconvolutionLayer.cpp
index 4d0ce63089..34a1bf5a45 100644
--- a/tests/validation/NEON/DeconvolutionLayer.cpp
+++ b/tests/validation/NEON/DeconvolutionLayer.cpp
@@ -62,7 +62,7 @@ const auto data3x3_precommit = datasets::SmallDeconvolutionShapes() * framework:
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 @@ TEST_SUITE(W4x4)
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 @@ TEST_SUITE(W3x3)
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(RunSmall, NEDeconvolutionLayerQuantizedFixture3x3<uint8_t
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 @@ TEST_SUITE(W1x1)
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 39b69ee1e3..9ddfbe0f8e 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 @@ DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(zip(
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_END() // Float
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 40229e2866..0a72e44dad 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 test
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 @@ protected:
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 @@ protected:
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 876f6d794a..8e36ee857e 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 validation
{
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 @@ SimpleTensor<T> upsample_layer(const SimpleTensor<T> &src,
}
}
}
-
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