IVGCVSW-3663 Add utility function to expand tensor dimension
authorNarumol Prangnawarat <narumol.prangnawarat@arm.com>
Wed, 11 Sep 2019 15:43:09 +0000 (16:43 +0100)
committerÁron Virginás-Tar <aron.virginas-tar@arm.com>
Thu, 12 Sep 2019 12:05:42 +0000 (12:05 +0000)
Signed-off-by: Narumol Prangnawarat <narumol.prangnawarat@arm.com>
Change-Id: I54d2416be305db7d3fc15fb3123694ad6740b27d

CMakeLists.txt
src/armnnUtils/TensorUtils.cpp
src/armnnUtils/TensorUtils.hpp
src/armnnUtils/test/TensorUtilsTest.cpp [new file with mode: 0644]

index f8ff91e..e92dc7e 100644 (file)
@@ -550,6 +550,7 @@ if(BUILD_UNIT_TESTS)
         src/armnn/test/UtilsTests.cpp
         src/armnnUtils/test/PrototxtConversionsTest.cpp
         src/armnnUtils/test/ParserHelperTest.cpp
+        src/armnnUtils/test/TensorUtilsTest.cpp
         src/profiling/test/ProfilingTests.cpp
         src/profiling/test/SendCounterPacketTests.cpp
         )
index c2fbbe0..8baea78 100644 (file)
@@ -6,6 +6,10 @@
 #include "TensorUtils.hpp"
 #include <backendsCommon/ITensorHandle.hpp>
 
+#include <boost/assert.hpp>
+#include <boost/format.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+
 namespace armnnUtils
 {
 
@@ -75,4 +79,32 @@ std::pair<float, float> FindMinMax(armnn::ITensorHandle* tensorHandle)
     return std::make_pair(min, max);
 }
 
+armnn::TensorShape ExpandDims(const armnn::TensorShape& tensorShape, int axis)
+{
+    unsigned int outputDim = tensorShape.GetNumDimensions() + 1;
+
+    if (axis < -boost::numeric_cast<int>(outputDim) || axis > boost::numeric_cast<int>(tensorShape.GetNumDimensions()))
+    {
+        throw armnn::InvalidArgumentException(
+            boost::str(boost::format("Invalid expansion axis %1% for %2%D input tensor. %3%") %
+                       axis %
+                       tensorShape.GetNumDimensions() %
+                       CHECK_LOCATION().AsString()));
+    }
+
+    if (axis < 0)
+    {
+        axis = boost::numeric_cast<int>(outputDim) + axis;
+    }
+
+    std::vector<unsigned int> outputShape;
+    for (unsigned int i = 0; i < tensorShape.GetNumDimensions(); ++i)
+    {
+        outputShape.push_back(tensorShape[i]);
+    }
+    outputShape.insert(outputShape.begin() + axis, 1);
+
+    return armnn::TensorShape(outputDim, outputShape.data());
+}
+
 }
index c273b49..03b1c8a 100644 (file)
@@ -24,4 +24,6 @@ armnn::TensorInfo GetTensorInfo(unsigned int numberOfBatches,
 
 std::pair<float, float> FindMinMax(armnn::ITensorHandle* tensorHandle);
 
+armnn::TensorShape ExpandDims(const armnn::TensorShape& tensorShape, int axis);
+
 } // namespace armnnUtils
diff --git a/src/armnnUtils/test/TensorUtilsTest.cpp b/src/armnnUtils/test/TensorUtilsTest.cpp
new file mode 100644 (file)
index 0000000..a903b63
--- /dev/null
@@ -0,0 +1,137 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <TensorUtils.hpp>
+
+#include <armnn/Types.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace armnn;
+using namespace armnnUtils;
+
+BOOST_AUTO_TEST_SUITE(TensorUtilsSuite)
+
+BOOST_AUTO_TEST_CASE(ExpandDimsAxis0Test)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Expand dimension 0
+    armnn::TensorShape outputShape = ExpandDims(inputShape, 0);
+    BOOST_TEST(outputShape.GetNumDimensions() == 4);
+    BOOST_TEST(outputShape[0] == 1);
+    BOOST_TEST(outputShape[1] == 2);
+    BOOST_TEST(outputShape[2] == 3);
+    BOOST_TEST(outputShape[3] == 4);
+}
+
+BOOST_AUTO_TEST_CASE(ExpandDimsAxis1Test)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Expand dimension 1
+    armnn::TensorShape outputShape = ExpandDims(inputShape, 1);
+    BOOST_TEST(outputShape.GetNumDimensions() == 4);
+    BOOST_TEST(outputShape[0] == 2);
+    BOOST_TEST(outputShape[1] == 1);
+    BOOST_TEST(outputShape[2] == 3);
+    BOOST_TEST(outputShape[3] == 4);
+}
+
+BOOST_AUTO_TEST_CASE(ExpandDimsAxis2Test)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Expand dimension 2
+    armnn::TensorShape outputShape = ExpandDims(inputShape, 2);
+    BOOST_TEST(outputShape.GetNumDimensions() == 4);
+    BOOST_TEST(outputShape[0] == 2);
+    BOOST_TEST(outputShape[1] == 3);
+    BOOST_TEST(outputShape[2] == 1);
+    BOOST_TEST(outputShape[3] == 4);
+}
+
+BOOST_AUTO_TEST_CASE(ExpandDimsAxis3Test)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Expand dimension 3
+    armnn::TensorShape outputShape = ExpandDims(inputShape, 3);
+    BOOST_TEST(outputShape.GetNumDimensions() == 4);
+    BOOST_TEST(outputShape[0] == 2);
+    BOOST_TEST(outputShape[1] == 3);
+    BOOST_TEST(outputShape[2] == 4);
+    BOOST_TEST(outputShape[3] == 1);
+}
+
+BOOST_AUTO_TEST_CASE(ExpandDimsNegativeAxis1Test)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Expand dimension -1
+    armnn::TensorShape outputShape = ExpandDims(inputShape, -1);
+    BOOST_TEST(outputShape.GetNumDimensions() == 4);
+    BOOST_TEST(outputShape[0] == 2);
+    BOOST_TEST(outputShape[1] == 3);
+    BOOST_TEST(outputShape[2] == 4);
+    BOOST_TEST(outputShape[3] == 1);
+}
+
+BOOST_AUTO_TEST_CASE(ExpandDimsNegativeAxis2Test)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Expand dimension -2
+    armnn::TensorShape outputShape = ExpandDims(inputShape, -2);
+    BOOST_TEST(outputShape.GetNumDimensions() == 4);
+    BOOST_TEST(outputShape[0] == 2);
+    BOOST_TEST(outputShape[1] == 3);
+    BOOST_TEST(outputShape[2] == 1);
+    BOOST_TEST(outputShape[3] == 4);
+}
+
+BOOST_AUTO_TEST_CASE(ExpandDimsNegativeAxis3Test)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Expand dimension -3
+    armnn::TensorShape outputShape = ExpandDims(inputShape, -3);
+    BOOST_TEST(outputShape.GetNumDimensions() == 4);
+    BOOST_TEST(outputShape[0] == 2);
+    BOOST_TEST(outputShape[1] == 1);
+    BOOST_TEST(outputShape[2] == 3);
+    BOOST_TEST(outputShape[3] == 4);
+}
+
+BOOST_AUTO_TEST_CASE(ExpandDimsNegativeAxis4Test)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Expand dimension -4
+    armnn::TensorShape outputShape = ExpandDims(inputShape, -4);
+    BOOST_TEST(outputShape.GetNumDimensions() == 4);
+    BOOST_TEST(outputShape[0] == 1);
+    BOOST_TEST(outputShape[1] == 2);
+    BOOST_TEST(outputShape[2] == 3);
+    BOOST_TEST(outputShape[3] == 4);
+}
+
+BOOST_AUTO_TEST_CASE(ExpandDimsInvalidAxisTest)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Invalid expand dimension 4
+    BOOST_CHECK_THROW(ExpandDims(inputShape, 4), armnn::InvalidArgumentException);
+}
+
+BOOST_AUTO_TEST_CASE(ExpandDimsInvalidNegativeAxisTest)
+{
+    armnn::TensorShape inputShape({ 2, 3, 4 });
+
+    // Invalid expand dimension -5
+    BOOST_CHECK_THROW(ExpandDims(inputShape, -5), armnn::InvalidArgumentException);
+}
+
+BOOST_AUTO_TEST_SUITE_END()