aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Monahan <david.monahan@arm.com>2020-06-19 16:43:48 +0100
committerDavid Monahan <david.monahan@arm.com>2020-06-20 09:46:26 +0000
commitab219756319667ae7abb0d767cf15e766ab343b1 (patch)
treeb68fce250273230d59a2d446f156283e576d6b0d /src
parent7e989834019e49f904df5c5ab0a299bde37c90c9 (diff)
downloadarmnn-ab219756319667ae7abb0d767cf15e766ab343b1.tar.gz
IVGCVSW-4707 - Add AlignCorners and HalfPixelCenters to Resize
* Added AlignCorners and HalfPixelCenters Parameters to Resize * Added Unit Tests Signed-off-by: David Monahan <david.monahan@arm.com> Change-Id: I83420a9bcb7beec9073d201448f64eb53090e1f1
Diffstat (limited to 'src')
-rw-r--r--src/armnn/SerializeLayerParameters.cpp4
-rw-r--r--src/armnn/layers/ResizeLayer.cpp5
-rw-r--r--src/backends/backendsCommon/test/layerTests/ResizeTestImpl.cpp156
-rw-r--r--src/backends/backendsCommon/test/layerTests/ResizeTestImpl.hpp24
-rw-r--r--src/backends/reference/test/RefLayerTests.cpp12
-rw-r--r--src/backends/reference/workloads/RefResizeWorkload.cpp3
-rw-r--r--src/backends/reference/workloads/Resize.cpp77
-rw-r--r--src/backends/reference/workloads/Resize.hpp3
8 files changed, 266 insertions, 18 deletions
diff --git a/src/armnn/SerializeLayerParameters.cpp b/src/armnn/SerializeLayerParameters.cpp
index 76b92f3f9d..e4bf094b7c 100644
--- a/src/armnn/SerializeLayerParameters.cpp
+++ b/src/armnn/SerializeLayerParameters.cpp
@@ -293,6 +293,8 @@ void StringifyLayerParameters<ResizeBilinearDescriptor>::Serialize(ParameterStri
fn("TargetWidth", std::to_string(desc.m_TargetWidth));
fn("TargetHeight", std::to_string(desc.m_TargetHeight));
fn("DataLayout", GetDataLayoutName(desc.m_DataLayout));
+ fn("AlignCorners", std::to_string(desc.m_AlignCorners));
+ fn("HalfPixelCenters", std::to_string(desc.m_HalfPixelCenters));
}
void StringifyLayerParameters<ResizeDescriptor>::Serialize(ParameterStringifyFunction& fn,
@@ -302,6 +304,8 @@ void StringifyLayerParameters<ResizeDescriptor>::Serialize(ParameterStringifyFun
fn("TargetHeight", std::to_string(desc.m_TargetHeight));
fn("ResizeMethod", GetResizeMethodAsCString(desc.m_Method));
fn("DataLayout", GetDataLayoutName(desc.m_DataLayout));
+ fn("AlignCorners", std::to_string(desc.m_AlignCorners));
+ fn("HalfPixelCenters", std::to_string(desc.m_HalfPixelCenters));
}
void StringifyLayerParameters<SpaceToBatchNdDescriptor>::Serialize(ParameterStringifyFunction& fn,
diff --git a/src/armnn/layers/ResizeLayer.cpp b/src/armnn/layers/ResizeLayer.cpp
index 9654e58b43..b16adeb860 100644
--- a/src/armnn/layers/ResizeLayer.cpp
+++ b/src/armnn/layers/ResizeLayer.cpp
@@ -50,6 +50,11 @@ std::vector<TensorShape> ResizeLayer::InferOutputShapes(const std::vector<Tensor
TensorShape( { outBatch, outHeight, outWidth, outChannels } ) :
TensorShape( { outBatch, outChannels, outHeight, outWidth });
+ if (m_Param.m_HalfPixelCenters && m_Param.m_AlignCorners)
+ {
+ throw LayerValidationException("ResizeLayer: AlignCorners cannot be true when HalfPixelCenters is true");
+ }
+
return std::vector<TensorShape>({ tensorShape });
}
diff --git a/src/backends/backendsCommon/test/layerTests/ResizeTestImpl.cpp b/src/backends/backendsCommon/test/layerTests/ResizeTestImpl.cpp
index f12f53c794..72507d39ac 100644
--- a/src/backends/backendsCommon/test/layerTests/ResizeTestImpl.cpp
+++ b/src/backends/backendsCommon/test/layerTests/ResizeTestImpl.cpp
@@ -29,7 +29,9 @@ struct ResizeTestParams
, m_InQuantScale(1.0f)
, m_InQuantOffset(0)
, m_OutQuantScale(1.0f)
- , m_OutQuantOffset(0) {}
+ , m_OutQuantOffset(0)
+ , m_AlignCorners(false)
+ , m_HalfPixelCenters(false) {}
armnn::ResizeMethod m_ResizeMethod;
armnn::DataLayout m_DataLayout;
@@ -46,6 +48,9 @@ struct ResizeTestParams
float m_OutQuantScale;
int32_t m_OutQuantOffset;
+ bool m_AlignCorners;
+ bool m_HalfPixelCenters;
+
void SetInQuantParams(float quantScale, int32_t quantOffset)
{
m_InQuantScale = quantScale;
@@ -111,6 +116,8 @@ LayerTestResult<T, NumDims> ResizeTestImpl(
armnn::ResizeQueueDescriptor descriptor;
descriptor.m_Parameters.m_Method = params.m_ResizeMethod;
descriptor.m_Parameters.m_DataLayout = params.m_DataLayout;
+ descriptor.m_Parameters.m_AlignCorners = params.m_AlignCorners;
+ descriptor.m_Parameters.m_HalfPixelCenters = params.m_HalfPixelCenters;
armnnUtils::DataLayoutIndexed dataLayoutIndexed(params.m_DataLayout);
descriptor.m_Parameters.m_TargetWidth = params.m_OutputShape[dataLayoutIndexed.GetWidthIndex()];
@@ -528,6 +535,129 @@ LayerTestResult<T, 4> ResizeNearestNeighborMagTest(
return ResizeTestImpl<4, ArmnnType>(workloadFactory, memoryManager, testParams);
}
+template<armnn::DataType ArmnnType, typename T>
+LayerTestResult<T, 4> HalfPixelCentersResizeBilinearTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout)
+{
+ ResizeTestParams testParams;
+ testParams.m_ResizeMethod = armnn::ResizeMethod::Bilinear;
+ testParams.m_DataLayout = dataLayout;
+ testParams.m_HalfPixelCenters = true;
+
+ testParams.m_InputShape = { 2, 1, 2, 2 };
+ testParams.m_OutputShape = { 2, 1, 3, 3 };
+
+ testParams.m_InputData =
+ {
+ 1.0f, 2.0f,
+ 3.0f, 4.0f,
+
+ 1.0f, 2.0f,
+ 3.0f, 4.0f
+ };
+
+ testParams.m_ExpectedOutputData =
+ {
+ 1.0f, 1.5f, 2.0f,
+ 2.0f, 2.5f, 3.0f,
+ 3.0f, 3.5f, 4.0f,
+
+ 1.0f, 1.5f, 2.0f,
+ 2.0f, 2.5f, 3.0f,
+ 3.0f, 3.5f, 4.0f,
+ };
+
+ return ResizeTestImpl<4, ArmnnType>(workloadFactory, memoryManager, testParams);
+}
+
+template<armnn::DataType ArmnnType, typename T>
+LayerTestResult<T, 4> AlignCornersResizeBilinearTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout)
+{
+ ResizeTestParams testParams;
+ testParams.m_ResizeMethod = armnn::ResizeMethod::Bilinear;
+ testParams.m_DataLayout = dataLayout;
+ testParams.m_AlignCorners = true;
+
+ testParams.m_InputShape = { 1, 1, 2, 2 };
+ testParams.m_OutputShape = { 1, 1, 1, 1 };
+
+ testParams.m_InputData =
+ {
+ 1.0f, 2.0f,
+ 3.0f, 4.0f,
+ };
+
+ testParams.m_ExpectedOutputData =
+ {
+ 1.0f
+ };
+
+ return ResizeTestImpl<4, ArmnnType>(workloadFactory, memoryManager, testParams);
+}
+
+template<armnn::DataType ArmnnType, typename T>
+LayerTestResult<T, 4> HalfPixelCentersResizeNearestNeighbourTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout)
+{
+ ResizeTestParams testParams;
+ testParams.m_ResizeMethod = armnn::ResizeMethod::NearestNeighbor;
+ testParams.m_DataLayout = dataLayout;
+ testParams.m_HalfPixelCenters = true;
+
+ testParams.m_InputShape = { 1, 1, 2, 5 };
+ testParams.m_OutputShape = { 1, 1, 2, 2 };
+
+ testParams.m_InputData =
+ {
+ 1.0f, 2.0f, 3.0f, 4.0f, 5.0f,
+
+ 1.0f, 2.0f, 3.0f, 4.0f, 5.0f
+ };
+
+ testParams.m_ExpectedOutputData =
+ {
+ 2.0f, 4.0f,
+ 2.0f, 4.0f
+ };
+
+ return ResizeTestImpl<4, ArmnnType>(workloadFactory, memoryManager, testParams);
+}
+
+template<armnn::DataType ArmnnType, typename T>
+LayerTestResult<T, 4> AlignCornersResizeNearestNeighbourTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout)
+{
+ ResizeTestParams testParams;
+ testParams.m_ResizeMethod = armnn::ResizeMethod::NearestNeighbor;
+ testParams.m_DataLayout = dataLayout;
+ testParams.m_AlignCorners = true;
+
+ testParams.m_InputShape = { 1, 1, 2, 2 };
+ testParams.m_OutputShape = { 1, 1, 1, 1 };
+
+ testParams.m_InputData =
+ {
+ 1.0f, 2.0f,
+ 3.0f, 4.0f,
+ };
+
+ testParams.m_ExpectedOutputData =
+ {
+ 1.0f
+ };
+
+ return ResizeTestImpl<4, ArmnnType>(workloadFactory, memoryManager, testParams);
+}
+
//
// Explicit template instantiations
//
@@ -597,6 +727,30 @@ ResizeNearestNeighborMagTest<armnn::DataType::Float32>(
float outQuantScale,
int32_t outQuantOffset);
+template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
+HalfPixelCentersResizeBilinearTest<armnn::DataType::Float32>(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout);
+
+template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
+AlignCornersResizeBilinearTest<armnn::DataType::Float32>(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout);
+
+template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
+HalfPixelCentersResizeNearestNeighbourTest<armnn::DataType::Float32>(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout);
+
+template LayerTestResult<armnn::ResolveType<armnn::DataType::Float32>, 4>
+AlignCornersResizeNearestNeighbourTest<armnn::DataType::Float32>(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout);
+
// Float16
template LayerTestResult<armnn::ResolveType<armnn::DataType::Float16>, 4>
ResizeBilinearNopTest<armnn::DataType::Float16>(
diff --git a/src/backends/backendsCommon/test/layerTests/ResizeTestImpl.hpp b/src/backends/backendsCommon/test/layerTests/ResizeTestImpl.hpp
index 538a64c21a..b70ae85b8f 100644
--- a/src/backends/backendsCommon/test/layerTests/ResizeTestImpl.hpp
+++ b/src/backends/backendsCommon/test/layerTests/ResizeTestImpl.hpp
@@ -79,3 +79,27 @@ LayerTestResult<T, 4> ResizeNearestNeighborMagTest(
int32_t inQuantOffset,
float outQuantScale,
int32_t outQuantOffset);
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+LayerTestResult<T, 4> HalfPixelCentersResizeBilinearTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout);
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+LayerTestResult<T, 4> AlignCornersResizeBilinearTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout);
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+LayerTestResult<T, 4> HalfPixelCentersResizeNearestNeighbourTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout);
+
+template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
+LayerTestResult<T, 4> AlignCornersResizeNearestNeighbourTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::DataLayout dataLayout); \ No newline at end of file
diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp
index 93bfb90244..4d347cab46 100644
--- a/src/backends/reference/test/RefLayerTests.cpp
+++ b/src/backends/reference/test/RefLayerTests.cpp
@@ -873,6 +873,12 @@ ARMNN_AUTO_TEST_CASE(ResizeBilinearMagUint8,
ARMNN_AUTO_TEST_CASE(ResizeBilinearMagUint16,
SimpleResizeBilinearTest<DataType::QSymmS16>,
DataLayout::NCHW)
+ARMNN_AUTO_TEST_CASE(HalfPixelCentersResizeBilinear,
+ HalfPixelCentersResizeBilinearTest<DataType::Float32>,
+ DataLayout::NCHW)
+ARMNN_AUTO_TEST_CASE(AlignCornersResizeBilinear,
+ AlignCornersResizeBilinearTest<DataType::Float32>,
+ DataLayout::NCHW)
// Resize Bilinear - NHWC
ARMNN_AUTO_TEST_CASE(ResizeBilinearNopNhwc,
@@ -1012,6 +1018,12 @@ ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMagUint8,
ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborMagUint16,
SimpleResizeNearestNeighborTest<DataType::QSymmS16>,
DataLayout::NCHW)
+ARMNN_AUTO_TEST_CASE(HalfPixelCentersResizeNearestNeighbour,
+ HalfPixelCentersResizeNearestNeighbourTest<DataType::Float32>,
+ DataLayout::NCHW)
+ARMNN_AUTO_TEST_CASE(AlignCornersResizeNearestNeighbour,
+ AlignCornersResizeNearestNeighbourTest<DataType::Float32>,
+ DataLayout::NCHW)
// Resize NearestNeighbor - NHWC
ARMNN_AUTO_TEST_CASE(ResizeNearestNeighborNopNhwc,
diff --git a/src/backends/reference/workloads/RefResizeWorkload.cpp b/src/backends/reference/workloads/RefResizeWorkload.cpp
index 49e4f36d2d..21ff852320 100644
--- a/src/backends/reference/workloads/RefResizeWorkload.cpp
+++ b/src/backends/reference/workloads/RefResizeWorkload.cpp
@@ -35,7 +35,8 @@ void RefResizeWorkload::Execute() const
outputInfo,
m_Data.m_Parameters.m_DataLayout,
m_Data.m_Parameters.m_Method,
- m_Data.m_Parameters.m_AlignCorners);
+ m_Data.m_Parameters.m_AlignCorners,
+ m_Data.m_Parameters.m_HalfPixelCenters);
}
} //namespace armnn
diff --git a/src/backends/reference/workloads/Resize.cpp b/src/backends/reference/workloads/Resize.cpp
index 407774e05d..16cdd4a2d0 100644
--- a/src/backends/reference/workloads/Resize.cpp
+++ b/src/backends/reference/workloads/Resize.cpp
@@ -30,6 +30,36 @@ inline double EuclideanDistance(float Xa, float Ya, const unsigned int Xb, const
return std::sqrt(pow(Xa - boost::numeric_cast<float>(Xb), 2) + pow(Ya - boost::numeric_cast<float>(Yb), 2));
}
+inline float CalculateResizeScale(const unsigned int& InputSize,
+ const unsigned int& OutputSize,
+ const bool& AlignCorners)
+{
+ return (AlignCorners && OutputSize > 1)
+ ? boost::numeric_cast<float>(InputSize - 1) / boost::numeric_cast<float>(OutputSize - 1)
+ : boost::numeric_cast<float>(InputSize) / boost::numeric_cast<float>(OutputSize);
+}
+
+inline float PixelScaler(const unsigned int& Pixel,
+ const float& Scale,
+ const bool& HalfPixelCenters,
+ armnn::ResizeMethod& resizeMethod)
+{
+ // For Half Pixel Centers the Top Left texel is assumed to be at 0.5,0.5
+ if (HalfPixelCenters && resizeMethod == armnn::ResizeMethod::Bilinear)
+ {
+ return (static_cast<float>(Pixel) + 0.5f) * Scale - 0.5f;
+ }
+ // Nearest Neighbour doesn't need to have 0.5f trimmed off as it will floor the values later
+ else if (HalfPixelCenters && resizeMethod == armnn::ResizeMethod::NearestNeighbor)
+ {
+ return (static_cast<float>(Pixel) + 0.5f) * Scale;
+ }
+ else
+ {
+ return static_cast<float>(Pixel) * Scale;
+ }
+}
+
}// anonymous namespace
void Resize(Decoder<float>& in,
@@ -38,8 +68,12 @@ void Resize(Decoder<float>& in,
const TensorInfo& outputInfo,
DataLayoutIndexed dataLayout,
armnn::ResizeMethod resizeMethod,
- bool alignCorners)
+ bool alignCorners,
+ bool halfPixelCenters)
{
+ // alignCorners and halfPixelCenters cannot both be true
+ ARMNN_ASSERT(!(alignCorners && halfPixelCenters));
+
// 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
// will yield different results than if projecting the centre of output texels.
@@ -52,14 +86,10 @@ void Resize(Decoder<float>& 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<float>(inputHeight - sizeOffset)
- / boost::numeric_cast<float>(outputHeight - sizeOffset);
- const float scaleX = boost::numeric_cast<float>(inputWidth - sizeOffset)
- / boost::numeric_cast<float>(outputWidth - sizeOffset);
+ const float scaleY = CalculateResizeScale(inputHeight, outputHeight, alignCorners);
+ const float scaleX = CalculateResizeScale(inputWidth, outputWidth, alignCorners);
TensorShape inputShape = inputInfo.GetShape();
TensorShape outputShape = outputInfo.GetShape();
@@ -71,11 +101,13 @@ void Resize(Decoder<float>& in,
for (unsigned int y = 0; y < outputHeight; ++y)
{
// Corresponding real-valued height coordinate in input image.
- const float iy = boost::numeric_cast<float>(y) * scaleY;
+ float iy = PixelScaler(y, scaleY, halfPixelCenters, resizeMethod);
// Discrete height coordinate of top-left texel (in the 2x2 texel area used for interpolation).
- const float fiy = floorf(iy);
- const unsigned int y0 = boost::numeric_cast<unsigned int>(fiy);
+ const float fiy = (resizeMethod == armnn::ResizeMethod::NearestNeighbor && alignCorners) ?
+ roundf(iy) : floorf(iy);
+ // Pixel scaling a value with Half Pixel Centers can be negative, if so set to 0
+ const unsigned int y0 = static_cast<unsigned int>(std::max(fiy, 0.0f));
// Interpolation weight (range [0,1]).
const float yw = iy - fiy;
@@ -83,16 +115,31 @@ void Resize(Decoder<float>& in,
for (unsigned int x = 0; x < outputWidth; ++x)
{
// Real-valued and discrete width coordinates in input image.
- const float ix = boost::numeric_cast<float>(x) * scaleX;
- const float fix = floorf(ix);
- const unsigned int x0 = boost::numeric_cast<unsigned int>(fix);
+ float ix = PixelScaler(x, scaleX, halfPixelCenters, resizeMethod);
+
+ // Nearest Neighbour uses rounding to align to corners
+ const float fix = resizeMethod == armnn::ResizeMethod::NearestNeighbor && alignCorners ?
+ roundf(ix) : floorf(ix);
+ // Pixel scaling a value with Half Pixel Centers can be negative, if so set to 0
+ const unsigned int x0 = static_cast<unsigned int>(std::max(fix, 0.0f));
// Interpolation weight (range [0,1]).
const float xw = ix - fix;
+ unsigned int x1;
+ unsigned int y1;
+ // Half Pixel Centers uses the scaling to compute a weighted parameter for nearby pixels
+ if (halfPixelCenters)
+ {
+ x1 = std::min(static_cast<unsigned int>(std::ceil(ix)), inputWidth - 1u);
+ y1 = std::min(static_cast<unsigned int>(std::ceil(iy)), inputHeight - 1u);
+ }
// Discrete width/height coordinates of texels below and to the right of (x0, y0).
- const unsigned int x1 = std::min(x0 + 1, inputWidth - 1u);
- const unsigned int y1 = std::min(y0 + 1, inputHeight - 1u);
+ else
+ {
+ x1 = std::min(x0 + 1, inputWidth - 1u);
+ y1 = std::min(y0 + 1, inputHeight - 1u);
+ }
float interpolatedValue;
switch (resizeMethod)
diff --git a/src/backends/reference/workloads/Resize.hpp b/src/backends/reference/workloads/Resize.hpp
index 58ec7dfb4f..99362afb05 100644
--- a/src/backends/reference/workloads/Resize.hpp
+++ b/src/backends/reference/workloads/Resize.hpp
@@ -20,6 +20,7 @@ void Resize(Decoder<float>& in,
const TensorInfo& outputInfo,
armnnUtils::DataLayoutIndexed dataLayout = DataLayout::NCHW,
ResizeMethod resizeMethod = ResizeMethod::NearestNeighbor,
- bool alignConers = false);
+ bool alignCorners = false,
+ bool halfPixelCenters = false);
} // namespace armnn