aboutsummaryrefslogtreecommitdiff
path: root/src/backends/reference/workloads/MirrorPad.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/backends/reference/workloads/MirrorPad.cpp')
-rw-r--r--src/backends/reference/workloads/MirrorPad.cpp199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/backends/reference/workloads/MirrorPad.cpp b/src/backends/reference/workloads/MirrorPad.cpp
new file mode 100644
index 0000000000..7388fed147
--- /dev/null
+++ b/src/backends/reference/workloads/MirrorPad.cpp
@@ -0,0 +1,199 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "MirrorPad.hpp"
+
+#include "BaseIterator.hpp"
+#include "Decoders.hpp"
+#include "Encoders.hpp"
+
+namespace
+{
+
+// Convert a linear index into n-dimensional coordinates.
+// E.g. index = 2 returns [0, 0, 2].
+inline std::vector<unsigned int> IndexToCoord(const armnn::TensorShape& shape, unsigned int index)
+{
+ unsigned int numOfElements = shape.GetNumElements();
+
+ ARMNN_ASSERT_MSG(index <= numOfElements, "Index has to be in [0, num_elements]");
+ ARMNN_ASSERT_MSG(numOfElements != 0, "Cannot create coordinate from empty shape");
+
+ std::vector<unsigned int> coord(shape.GetNumDimensions());
+ for(unsigned int i = 0; i < shape.GetNumDimensions(); ++i)
+ {
+ numOfElements /= shape[i];
+ coord[i] = index / numOfElements;
+ index %= numOfElements;
+ }
+
+ return coord;
+}
+
+// Returns the index of a given coordinate.
+// E.g. [0, 0, 2] returns 2.
+inline unsigned int CoordToIndex(const armnn::TensorShape& shape, const std::vector<unsigned int>& coord)
+{
+ ARMNN_ASSERT_MSG(shape.GetNumDimensions() != 0, "Cannot get index from empty shape");
+ ARMNN_ASSERT_MSG(coord.size() != 0, "Cannot get index of empty coordinate");
+
+ unsigned int index = 0;
+ unsigned int dimSize = 1;
+
+ for (unsigned int i = shape.GetNumDimensions(); i > 0; --i)
+ {
+ index += coord[i - 1] * dimSize;
+ dimSize *= shape[i - 1];
+ }
+
+ return index;
+}
+
+} // anonymous namespace
+
+namespace armnn
+{
+
+void MirrorPad(const TensorInfo& inputInfo,
+ const TensorInfo& outputInfo,
+ const ITensorHandle* inputHandle,
+ ITensorHandle* outputHandle,
+ const PadQueueDescriptor& data)
+{
+ auto padList = data.m_Parameters.m_PadList;
+ PaddingMode paddingMode = data.m_Parameters.m_PaddingMode;
+
+ TensorShape outputShape = outputInfo.GetShape();
+ TensorShape inputShape = inputInfo.GetShape();
+
+ unsigned int numOutputElements = outputInfo.GetNumElements();
+ unsigned int numInputDimensions = inputShape.GetNumDimensions();
+ assert(numInputDimensions == outputShape.GetNumDimensions());
+
+ // If padding mode is Reflect then both paddings must be no greater than inputShape(i) - 1.
+ // If padding mode is Symmetric then both paddings must be no greater than inputShape(i).
+ const unsigned int isReflect = static_cast<unsigned int>(paddingMode == PaddingMode::Reflect);
+ for(unsigned int i = 0; i < padList.size(); ++i)
+ {
+ if(padList.at(i).first > (inputShape[i] - isReflect) ||
+ padList.at(i).second > (inputShape[i] - isReflect))
+ {
+ throw armnn::InvalidArgumentException("Paddings must be less (Reflect) or "
+ "equal (Symmetric) to the dimension size.");
+ }
+ }
+
+ auto inputData = MakeDecoder<float>(inputInfo, inputHandle->Map());
+ auto outData = MakeEncoder<float>(outputInfo, outputHandle->Map());
+
+ Decoder<float>& input = *inputData;
+ Encoder<float>& output = *outData;
+
+ for(unsigned int idx = 0; idx < numOutputElements; ++idx)
+ {
+ // Get the coordinates of the current index in vector form. E.g inx 1 = [0, 0, 0, 1 ]
+ const std::vector<unsigned int> coord = IndexToCoord(outputShape, idx);
+
+ std::vector<unsigned int> dimensions;
+ std::vector<unsigned int> coords;
+
+ for(unsigned int i = 0; i < numInputDimensions; ++i)
+ {
+ dimensions.emplace_back(i);
+ coords.emplace_back(coord[i]);
+ }
+
+ auto isInPadding = [&](unsigned int i)
+ {
+ return (coords[i] < padList[i].first || coords[i] > inputShape[i] + padList[i].first - 1);
+ };
+
+ auto getReflectIndex = [&](unsigned int i) -> unsigned int
+ {
+ if(isInPadding(i))
+ {
+ if(coords[i] < padList[i].first)
+ {
+ return padList[i].first - coords[i];
+ }
+ else
+ {
+ return 2 * inputShape[i] + padList[i].first - 2 - coords[i];
+ }
+ }
+ return coords[i] - padList[i].first;
+ };
+
+ auto getSymmetricIndex = [&](unsigned int i) -> unsigned int
+ {
+ if(isInPadding(i))
+ {
+ if(coords[i] < padList[i].first)
+ {
+ return padList[i].first - coords[i] - 1;
+ }
+ else
+ {
+ return 2 * inputShape[i] + padList[i].first - 1 - coords[i];
+ }
+ }
+ return coords[i] - padList[i].first;
+ };
+
+ // Location of the value in the input tensor to use in the output.
+ std::vector<unsigned int> coordOfInput;
+
+ // any_of works as a loop here to check if any of the dimensions are in the padding.
+ // If dimensions is in the padding area, then create the coordinates of the location in the
+ // input tensor to use in the output.
+ // E.g.
+ // Input tensor = [ 1, 2, 3 ], Rank = 1.
+ // Output tensor = [ 2, 1, 2, 3, 1 ] if Reflect or [ 1, 1, 2, 3, 3 ] if Symmetric with a padding of (1, 1).
+ // So it will either return [ 1 ] or [ 0 ] which is used to set the first value in the output tensor and so on.
+ if(std::any_of(dimensions.begin(), dimensions.end(), isInPadding))
+ {
+ switch(paddingMode)
+ {
+ case PaddingMode::Reflect:
+ {
+ for(unsigned int i = 0; i < numInputDimensions; ++i)
+ {
+ coordOfInput.emplace_back(getReflectIndex(i));
+ }
+ break;
+ }
+ case PaddingMode::Symmetric:
+ {
+ for(unsigned int i = 0; i < numInputDimensions; ++i)
+ {
+ coordOfInput.emplace_back(getSymmetricIndex(i));
+ }
+ break;
+ }
+ default:
+ throw InvalidArgumentException("Padding mode not supported.");
+ break;
+ }
+ }
+ else
+ {
+ for(unsigned int i = 0; i < numInputDimensions; ++i)
+ {
+ coordOfInput.emplace_back(coord[i] - padList[i].first);
+ }
+ }
+
+ // Set output value using the coordinate of the input value to use.
+ const unsigned int indexOfInput = CoordToIndex(inputShape, coordOfInput);
+
+ input[indexOfInput];
+ auto inputValue = input.Get();
+
+ output[idx];
+ output.Set(inputValue);
+ }
+}
+
+} //namespace armnn \ No newline at end of file