From 820eb141a7a5d0eef200ccf9554a37eabade3264 Mon Sep 17 00:00:00 2001 From: Sang-Hoon Park Date: Wed, 8 Jan 2020 10:25:24 +0000 Subject: MLCE-139: add capability to align corners for bilinear resize * Add parsing of the related parameter to TfLiteParser * Update ResizeDescriptor to store the additional parameter * Update NEON/CL workload to pass the additional parameter. * Update Reference workload to pass and handle the additional parameter. !ComputeLibrary:2538 !ComputeLibrary:2569 !armnn:2612 Signed-off-by: Sang-Hoon Park Change-Id: Id149e1c24c2abed7e9dd81939acf54dfabfcdfd2 --- include/armnn/Descriptors.hpp | 12 ++++++++---- src/armnnTfLiteParser/TfLiteParser.cpp | 5 +++++ src/backends/cl/workloads/ClResizeWorkload.cpp | 8 ++++++-- src/backends/neon/workloads/NeonResizeWorkload.cpp | 4 +++- src/backends/reference/workloads/RefResizeWorkload.cpp | 8 +++++++- src/backends/reference/workloads/Resize.cpp | 11 ++++++++--- src/backends/reference/workloads/Resize.hpp | 3 ++- 7 files changed, 39 insertions(+), 12 deletions(-) diff --git a/include/armnn/Descriptors.hpp b/include/armnn/Descriptors.hpp index 45c0f421f3..2d7b17edbb 100644 --- a/include/armnn/Descriptors.hpp +++ b/include/armnn/Descriptors.hpp @@ -728,14 +728,16 @@ struct ResizeDescriptor , m_TargetHeight(0) , m_Method(ResizeMethod::NearestNeighbor) , m_DataLayout(DataLayout::NCHW) + , m_BilinearAlignCorners(false) {} bool operator ==(const ResizeDescriptor& rhs) const { - return m_TargetWidth == rhs.m_TargetWidth && - m_TargetHeight == rhs.m_TargetHeight && - m_Method == rhs.m_Method && - m_DataLayout == rhs.m_DataLayout; + return m_TargetWidth == rhs.m_TargetWidth && + m_TargetHeight == rhs.m_TargetHeight && + m_Method == rhs.m_Method && + m_DataLayout == rhs.m_DataLayout && + m_BilinearAlignCorners == rhs.m_BilinearAlignCorners; } /// Target width value. @@ -747,6 +749,8 @@ struct ResizeDescriptor ResizeMethod m_Method; /// The data layout to be used (NCHW, NHWC). DataLayout m_DataLayout; + /// Aligned corners for bilinear method + bool m_BilinearAlignCorners; }; diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp index d3eed9cfb1..10bb0f6e97 100644 --- a/src/armnnTfLiteParser/TfLiteParser.cpp +++ b/src/armnnTfLiteParser/TfLiteParser.cpp @@ -2004,6 +2004,11 @@ void TfLiteParser::ParseResize(size_t subgraphIndex, size_t operatorIndex, Resiz case ResizeMethod::Bilinear: { layerName += str(boost::format("BILINEAR:%1%:%2%") % subgraphIndex % operatorIndex); + + const auto & operatorPtr = m_Model->subgraphs[subgraphIndex]->operators[operatorIndex]; + const auto * options = operatorPtr->builtin_options.AsResizeBilinearOptions(); + + desc.m_BilinearAlignCorners = options->align_corners; break; } case ResizeMethod::NearestNeighbor: diff --git a/src/backends/cl/workloads/ClResizeWorkload.cpp b/src/backends/cl/workloads/ClResizeWorkload.cpp index bcf42814d9..05b212c3d4 100644 --- a/src/backends/cl/workloads/ClResizeWorkload.cpp +++ b/src/backends/cl/workloads/ClResizeWorkload.cpp @@ -38,7 +38,9 @@ arm_compute::Status ClResizeWorkloadValidate(const TensorInfo& input, aclInterpolationPolicy, arm_compute::BorderMode::REPLICATE, arm_compute::PixelValue(0.f), - arm_compute::SamplingPolicy::TOP_LEFT); + arm_compute::SamplingPolicy::TOP_LEFT, + true, + descriptor.m_BilinearAlignCorners); } ClResizeWorkload::ClResizeWorkload(const ResizeQueueDescriptor& descriptor, const WorkloadInfo& info) : @@ -61,7 +63,9 @@ ClResizeWorkload::ClResizeWorkload(const ResizeQueueDescriptor& descriptor, cons aclInterpolationPolicy, arm_compute::BorderMode::REPLICATE, arm_compute::PixelValue(0.f), - arm_compute::SamplingPolicy::TOP_LEFT); + arm_compute::SamplingPolicy::TOP_LEFT, + true, + descriptor.m_Parameters.m_BilinearAlignCorners); }; void ClResizeWorkload::Execute() const diff --git a/src/backends/neon/workloads/NeonResizeWorkload.cpp b/src/backends/neon/workloads/NeonResizeWorkload.cpp index a4e4a4a511..e936ab7446 100644 --- a/src/backends/neon/workloads/NeonResizeWorkload.cpp +++ b/src/backends/neon/workloads/NeonResizeWorkload.cpp @@ -60,7 +60,9 @@ NeonResizeWorkload::NeonResizeWorkload(const ResizeQueueDescriptor& descriptor, aclInterpolationPolicy, arm_compute::BorderMode::REPLICATE, arm_compute::PixelValue(0.f), - arm_compute::SamplingPolicy::TOP_LEFT); + arm_compute::SamplingPolicy::TOP_LEFT, + true, + descriptor.m_Parameters.m_BilinearAlignCorners); }; void NeonResizeWorkload::Execute() const diff --git a/src/backends/reference/workloads/RefResizeWorkload.cpp b/src/backends/reference/workloads/RefResizeWorkload.cpp index 26225f8823..624b426cbf 100644 --- a/src/backends/reference/workloads/RefResizeWorkload.cpp +++ b/src/backends/reference/workloads/RefResizeWorkload.cpp @@ -29,7 +29,13 @@ void RefResizeWorkload::Execute() const std::unique_ptr> encoderPtr = MakeEncoder(outputInfo, m_Data.m_Outputs[0]->Map()); Encoder &encoder = *encoderPtr; - Resize(decoder, inputInfo, encoder, outputInfo, m_Data.m_Parameters.m_DataLayout, m_Data.m_Parameters.m_Method); + Resize(decoder, + inputInfo, + encoder, + outputInfo, + m_Data.m_Parameters.m_DataLayout, + m_Data.m_Parameters.m_Method, + m_Data.m_Parameters.m_BilinearAlignCorners); } } //namespace armnn diff --git a/src/backends/reference/workloads/Resize.cpp b/src/backends/reference/workloads/Resize.cpp index 3050bae870..a26e34a1ff 100644 --- a/src/backends/reference/workloads/Resize.cpp +++ b/src/backends/reference/workloads/Resize.cpp @@ -37,7 +37,8 @@ void Resize(Decoder& in, Encoder& out, const TensorInfo& outputInfo, DataLayoutIndexed dataLayout, - armnn::ResizeMethod resizeMethod) + armnn::ResizeMethod resizeMethod, + bool alignCorners) { // We follow the definition of TensorFlow and AndroidNN: the top-left corner of a texel in the output // image is projected into the input image to figure out the interpolants and weights. Note that this @@ -51,10 +52,14 @@ void Resize(Decoder& in, const unsigned int outputHeight = outputInfo.GetShape()[dataLayout.GetHeightIndex()]; const unsigned int outputWidth = outputInfo.GetShape()[dataLayout.GetWidthIndex()]; + const unsigned int sizeOffset = resizeMethod == armnn::ResizeMethod::Bilinear && alignCorners ? 1 : 0; + // How much to scale pixel coordinates in the output image, to get the corresponding pixel coordinates // in the input image. - const float scaleY = boost::numeric_cast(inputHeight) / boost::numeric_cast(outputHeight); - const float scaleX = boost::numeric_cast(inputWidth) / boost::numeric_cast(outputWidth); + const float scaleY = boost::numeric_cast(inputHeight - sizeOffset) + / boost::numeric_cast(outputHeight - sizeOffset); + const float scaleX = boost::numeric_cast(inputWidth - sizeOffset) + / boost::numeric_cast(outputWidth - sizeOffset); TensorShape inputShape = inputInfo.GetShape(); TensorShape outputShape = outputInfo.GetShape(); diff --git a/src/backends/reference/workloads/Resize.hpp b/src/backends/reference/workloads/Resize.hpp index 4c357946d9..cd8835fa08 100644 --- a/src/backends/reference/workloads/Resize.hpp +++ b/src/backends/reference/workloads/Resize.hpp @@ -19,6 +19,7 @@ void Resize(Decoder& in, Encoder& out, const TensorInfo& outputInfo, armnnUtils::DataLayoutIndexed dataLayout = DataLayout::NCHW, - ResizeMethod resizeMethod = ResizeMethod::NearestNeighbor); + ResizeMethod resizeMethod = ResizeMethod::NearestNeighbor, + bool alignConers = false); } // namespace armnn -- cgit v1.2.1