IVGCVSW-4179 Add RESIZE_NEAREST_NEIGHBOUR to the TfLite parser

Signed-off-by: Sadik Armagan <sadik.armagan@arm.com>
Change-Id: I6359a8a405c86aef04cde75404393dd4ee917fa5
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7b6e1ab..b05f506 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -718,6 +718,7 @@
              src/armnnTfLiteParser/test/Pad.cpp
              src/armnnTfLiteParser/test/Reshape.cpp
              src/armnnTfLiteParser/test/ResizeBilinear.cpp
+             src/armnnTfLiteParser/test/ResizeNearestNeighbor.cpp
              src/armnnTfLiteParser/test/Softmax.cpp
              src/armnnTfLiteParser/test/SpaceToBatchND.cpp
              src/armnnTfLiteParser/test/Slice.cpp
diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp
index 090fbed..6122f5e 100644
--- a/src/armnnTfLiteParser/TfLiteParser.cpp
+++ b/src/armnnTfLiteParser/TfLiteParser.cpp
@@ -436,38 +436,39 @@
 , m_ParserFunctions(tflite::BuiltinOperator_MAX+1, &TfLiteParser::ParseUnsupportedOperator)
 {
     // register supported operators
-    m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D]   = &TfLiteParser::ParseAveragePool2D;
-    m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND] = &TfLiteParser::ParseBatchToSpaceND;
-    m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION]     = &TfLiteParser::ParseConcatenation;
-    m_ParserFunctions[tflite::BuiltinOperator_CONV_2D]           = &TfLiteParser::ParseConv2D;
-    m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D] = &TfLiteParser::ParseDepthwiseConv2D;
-    m_ParserFunctions[tflite::BuiltinOperator_CUSTOM]            = &TfLiteParser::ParseCustomOperator;
-    m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED]   = &TfLiteParser::ParseFullyConnected;
-    m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC]          = &TfLiteParser::ParseLogistic;
-    m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION]  = &TfLiteParser::ParseL2Normalization;
-    m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D]       = &TfLiteParser::ParseMaxPool2D;
-    m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM]           = &TfLiteParser::ParseMaximum;
-    m_ParserFunctions[tflite::BuiltinOperator_MINIMUM]           = &TfLiteParser::ParseMinimum;
-    m_ParserFunctions[tflite::BuiltinOperator_RELU]              = &TfLiteParser::ParseRelu;
-    m_ParserFunctions[tflite::BuiltinOperator_RELU6]             = &TfLiteParser::ParseRelu6;
-    m_ParserFunctions[tflite::BuiltinOperator_RESHAPE]           = &TfLiteParser::ParseReshape;
-    m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR]   = &TfLiteParser::ParseResizeBilinear;
-    m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX]           = &TfLiteParser::ParseSoftmax;
-    m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND] = &TfLiteParser::ParseSpaceToBatchND;
-    m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE]           = &TfLiteParser::ParseSqueeze;
-    m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE]     = &TfLiteParser::ParseStridedSlice;
-    m_ParserFunctions[tflite::BuiltinOperator_SUB]               = &TfLiteParser::ParseSub;
-    m_ParserFunctions[tflite::BuiltinOperator_ADD]               = &TfLiteParser::ParseAdd;
-    m_ParserFunctions[tflite::BuiltinOperator_MUL]               = &TfLiteParser::ParseMul;
-    m_ParserFunctions[tflite::BuiltinOperator_MEAN]              = &TfLiteParser::ParseMean;
-    m_ParserFunctions[tflite::BuiltinOperator_PACK]              = &TfLiteParser::ParsePack;
-    m_ParserFunctions[tflite::BuiltinOperator_PAD]               = &TfLiteParser::ParsePad;
-    m_ParserFunctions[tflite::BuiltinOperator_SLICE]             = &TfLiteParser::ParseSlice;
-    m_ParserFunctions[tflite::BuiltinOperator_SPLIT]             = &TfLiteParser::ParseSplit;
-    m_ParserFunctions[tflite::BuiltinOperator_TANH]              = &TfLiteParser::ParseTanH;
-    m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE]         = &TfLiteParser::ParseTranspose;
-    m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV]    = &TfLiteParser::ParseTransposeConv;
-    m_ParserFunctions[tflite::BuiltinOperator_UNPACK]            = &TfLiteParser::ParseUnpack;
+    m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D]         = &TfLiteParser::ParseAveragePool2D;
+    m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND]       = &TfLiteParser::ParseBatchToSpaceND;
+    m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION]           = &TfLiteParser::ParseConcatenation;
+    m_ParserFunctions[tflite::BuiltinOperator_CONV_2D]                 = &TfLiteParser::ParseConv2D;
+    m_ParserFunctions[tflite::BuiltinOperator_DEPTHWISE_CONV_2D]       = &TfLiteParser::ParseDepthwiseConv2D;
+    m_ParserFunctions[tflite::BuiltinOperator_CUSTOM]                  = &TfLiteParser::ParseCustomOperator;
+    m_ParserFunctions[tflite::BuiltinOperator_FULLY_CONNECTED]         = &TfLiteParser::ParseFullyConnected;
+    m_ParserFunctions[tflite::BuiltinOperator_LOGISTIC]                = &TfLiteParser::ParseLogistic;
+    m_ParserFunctions[tflite::BuiltinOperator_L2_NORMALIZATION]        = &TfLiteParser::ParseL2Normalization;
+    m_ParserFunctions[tflite::BuiltinOperator_MAX_POOL_2D]             = &TfLiteParser::ParseMaxPool2D;
+    m_ParserFunctions[tflite::BuiltinOperator_MAXIMUM]                 = &TfLiteParser::ParseMaximum;
+    m_ParserFunctions[tflite::BuiltinOperator_MINIMUM]                 = &TfLiteParser::ParseMinimum;
+    m_ParserFunctions[tflite::BuiltinOperator_RELU]                    = &TfLiteParser::ParseRelu;
+    m_ParserFunctions[tflite::BuiltinOperator_RELU6]                   = &TfLiteParser::ParseRelu6;
+    m_ParserFunctions[tflite::BuiltinOperator_RESHAPE]                 = &TfLiteParser::ParseReshape;
+    m_ParserFunctions[tflite::BuiltinOperator_RESIZE_BILINEAR]         = &TfLiteParser::ParseResizeBilinear;
+    m_ParserFunctions[tflite::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR] = &TfLiteParser::ParseResizeNearestNeighbor;
+    m_ParserFunctions[tflite::BuiltinOperator_SOFTMAX]                 = &TfLiteParser::ParseSoftmax;
+    m_ParserFunctions[tflite::BuiltinOperator_SPACE_TO_BATCH_ND]       = &TfLiteParser::ParseSpaceToBatchND;
+    m_ParserFunctions[tflite::BuiltinOperator_SQUEEZE]                 = &TfLiteParser::ParseSqueeze;
+    m_ParserFunctions[tflite::BuiltinOperator_STRIDED_SLICE]           = &TfLiteParser::ParseStridedSlice;
+    m_ParserFunctions[tflite::BuiltinOperator_SUB]                     = &TfLiteParser::ParseSub;
+    m_ParserFunctions[tflite::BuiltinOperator_ADD]                     = &TfLiteParser::ParseAdd;
+    m_ParserFunctions[tflite::BuiltinOperator_MUL]                     = &TfLiteParser::ParseMul;
+    m_ParserFunctions[tflite::BuiltinOperator_MEAN]                    = &TfLiteParser::ParseMean;
+    m_ParserFunctions[tflite::BuiltinOperator_PACK]                    = &TfLiteParser::ParsePack;
+    m_ParserFunctions[tflite::BuiltinOperator_PAD]                     = &TfLiteParser::ParsePad;
+    m_ParserFunctions[tflite::BuiltinOperator_SLICE]                   = &TfLiteParser::ParseSlice;
+    m_ParserFunctions[tflite::BuiltinOperator_SPLIT]                   = &TfLiteParser::ParseSplit;
+    m_ParserFunctions[tflite::BuiltinOperator_TANH]                    = &TfLiteParser::ParseTanH;
+    m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE]               = &TfLiteParser::ParseTranspose;
+    m_ParserFunctions[tflite::BuiltinOperator_TRANSPOSE_CONV]          = &TfLiteParser::ParseTransposeConv;
+    m_ParserFunctions[tflite::BuiltinOperator_UNPACK]                  = &TfLiteParser::ParseUnpack;
 
     // register supported custom operators
     m_CustomParserFunctions["TFLite_Detection_PostProcess"]      = &TfLiteParser::ParseDetectionPostProcess;
@@ -1877,6 +1878,16 @@
 
 void TfLiteParser::ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex)
 {
+    ParseResize(subgraphIndex, operatorIndex, ResizeMethod::Bilinear);
+}
+
+void TfLiteParser::ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex)
+{
+    ParseResize(subgraphIndex, operatorIndex, ResizeMethod::NearestNeighbor);
+}
+
+void TfLiteParser::ParseResize(size_t subgraphIndex, size_t operatorIndex, ResizeMethod resizeMethod)
+{
     CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
 
     auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
@@ -1894,12 +1905,33 @@
     ::memcpy(sizeTensorData.data(), sizeBufferPtr->data.data(), sizeTensorInfo.GetNumBytes());
 
     ResizeDescriptor desc;
-    desc.m_Method       = armnn::ResizeMethod::Bilinear;
+    desc.m_Method       = resizeMethod;
     desc.m_TargetHeight = static_cast<uint32_t> (sizeTensorData[0]);
     desc.m_TargetWidth  = static_cast<uint32_t> (sizeTensorData[1]);
     desc.m_DataLayout   = armnn::DataLayout::NHWC;
 
-    auto layerName = boost::str(boost::format("ResizeBilinear:%1%:%2%") % subgraphIndex % operatorIndex);
+    auto layerName = str(boost::format("Resize:"));
+
+    switch (resizeMethod)
+    {
+        case ResizeMethod::Bilinear:
+        {
+            layerName += str(boost::format("BILINEAR:%1%:%2%") % subgraphIndex % operatorIndex);
+            break;
+        }
+        case ResizeMethod::NearestNeighbor:
+        {
+            layerName += str(boost::format("NEARESTNEIGHBOR:%1%:%2%") % subgraphIndex % operatorIndex);
+            break;
+        }
+        default:
+        {
+            throw ParseException(
+                boost::str(boost::format("Unexpected ResizeMethod[%1%] when creating layerName "
+                                         " %2% ") %static_cast<int>(resizeMethod)% CHECK_LOCATION().AsString()));
+        }
+    }
+
     IConnectableLayer* layer = m_Network->AddResizeLayer(desc, layerName.c_str());
 
     TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
diff --git a/src/armnnTfLiteParser/TfLiteParser.hpp b/src/armnnTfLiteParser/TfLiteParser.hpp
index 5ac6a89..7f97b6d 100644
--- a/src/armnnTfLiteParser/TfLiteParser.hpp
+++ b/src/armnnTfLiteParser/TfLiteParser.hpp
@@ -115,7 +115,9 @@
     void ParseRelu(size_t subgraphIndex, size_t operatorIndex);
     void ParseRelu6(size_t subgraphIndex, size_t operatorIndex);
     void ParseReshape(size_t subgraphIndex, size_t operatorIndex);
+    void ParseResize(size_t subgraphIndex, size_t operatorIndex, armnn::ResizeMethod resizeMethod);
     void ParseResizeBilinear(size_t subgraphIndex, size_t operatorIndex);
+    void ParseResizeNearestNeighbor(size_t subgraphIndex, size_t operatorIndex);
     void ParseSlice(size_t subgraphIndex, size_t operatorIndex);
     void ParseSoftmax(size_t subgraphIndex, size_t operatorIndex);
     void ParseSpaceToBatchND(size_t subgraphIndex, size_t operatorIndex);
diff --git a/src/armnnTfLiteParser/test/ResizeNearestNeighbor.cpp b/src/armnnTfLiteParser/test/ResizeNearestNeighbor.cpp
new file mode 100644
index 0000000..fada810
--- /dev/null
+++ b/src/armnnTfLiteParser/test/ResizeNearestNeighbor.cpp
@@ -0,0 +1,111 @@
+//
+// Copyright © 2019 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <boost/test/unit_test.hpp>
+#include "ParserFlatbuffersFixture.hpp"
+#include "../TfLiteParser.hpp"
+
+#include <string>
+#include <iostream>
+
+using armnnTfLiteParser::TfLiteParser;
+
+BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
+
+struct ResizeNearestNeighborFixture : public ParserFlatbuffersFixture
+{
+    explicit ResizeNearestNeighborFixture(const std::string & inputShape,
+                                          const std::string & outputShape,
+                                          const std::string & sizeShape,
+                                          const std::string & sizeData)
+    {
+        m_JsonString = R"(
+            {
+                "version": 3,
+                "operator_codes": [ { "builtin_code": "RESIZE_NEAREST_NEIGHBOR" } ],
+                "subgraphs": [ {
+                    "tensors": [
+                        {
+                            "shape": )" + sizeShape + R"( ,
+                            "type": "INT32",
+                            "buffer": 0,
+                            "name": "sizeTensor",
+                            "quantization": {
+                                "min": [ 0.0 ],
+                                "max": [ 255.0 ],
+                                "scale": [ 1.0 ],
+                                "zero_point": [ 0 ],
+                            }
+                        },
+                        {
+                            "shape": )" + inputShape + R"(,
+                            "type": "FLOAT32",
+                            "buffer": 1,
+                            "name": "InputTensor",
+                            "quantization": {
+                                "min": [ 0.0 ],
+                                "max": [ 255.0 ],
+                                "scale": [ 1.0 ],
+                                "zero_point": [ 0 ],
+                            }
+                        },
+                        {
+                            "shape": )" + outputShape + R"( ,
+                            "type": "FLOAT32",
+                            "buffer": 2,
+                            "name": "OutputTensor",
+                            "quantization": {
+                                "min": [ 0.0 ],
+                                "max": [ 255.0 ],
+                                "scale": [ 1.0 ],
+                                "zero_point": [ 0 ],
+                            }
+                        }
+                    ],
+                "inputs": [ 1 ],
+                "outputs": [ 2 ],
+                "operators": [
+                    {
+                        "opcode_index": 0,
+                        "inputs": [ 1, 0 ],
+                        "outputs": [ 2 ],
+                        "builtin_options_type": "ResizeNearestNeighborOptions",
+                        "builtin_options": {
+                        },
+                        "custom_options_format": "FLEXBUFFERS"
+                    }
+                ],
+              } ],
+              "buffers" : [
+                  { "data": )" + sizeData + R"(, },
+                  { },
+                  { },
+              ]
+            }
+      )";
+      Setup();
+    }
+};
+
+
+struct SimpleResizeNearestNeighborFixture : ResizeNearestNeighborFixture
+{
+    SimpleResizeNearestNeighborFixture()
+        : ResizeNearestNeighborFixture("[ 1, 2, 2, 1 ]",         // inputShape
+                                       "[ 1, 1, 1, 1 ]",         // outputShape
+                                       "[ 2 ]",                  // sizeShape
+                                       "[ 1,0,0,0, 1,0,0,0 ]")   // sizeData
+    {}
+};
+
+BOOST_FIXTURE_TEST_CASE(ParseResizeNearestNeighbor, SimpleResizeNearestNeighborFixture)
+{
+    RunTest<4, armnn::DataType::Float32>(
+                0,
+                {{"InputTensor", {  1.0f, 2.0f, 3.0f, 4.0f }}},
+                {{"OutputTensor", {  1.0f }}});
+}
+
+BOOST_AUTO_TEST_SUITE_END()