Add Resize Nearest Neighbour support to TOSA Reference Backend

* Add support for quantized data in TosaRefPreCompiledWorkloadGetOutput.
* Remove extra includes from all TOSA operators headers.
* Added positive and negative unit tests for resize.

* Resolves: IVGCVSW-7346

Signed-off-by: Teresa Charlin <teresa.charlinreyes@arm.com>
Change-Id: Ib6e30d018a7a1bf26b380fc794560aae108b26c3
diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp
index 021435e..2d7a5fd 100644
--- a/src/backends/backendsCommon/WorkloadData.cpp
+++ b/src/backends/backendsCommon/WorkloadData.cpp
@@ -1592,6 +1592,7 @@
         DataType::Float32,
         DataType::QAsymmS8,
         DataType::QAsymmU8,
+        DataType::QSymmS8,
         DataType::QSymmS16
     };
 
diff --git a/src/backends/backendsCommon/test/ResizeEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/ResizeEndToEndTestImpl.hpp
index f8d17a8..071daa7 100644
--- a/src/backends/backendsCommon/test/ResizeEndToEndTestImpl.hpp
+++ b/src/backends/backendsCommon/test/ResizeEndToEndTestImpl.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2017 Arm Ltd. All rights reserved.
+// Copyright © 2017, 2019-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 #pragma once
@@ -37,7 +37,9 @@
 template<armnn::DataType ArmnnType>
 void ResizeEndToEnd(const std::vector<armnn::BackendId>& backends,
                     armnn::DataLayout dataLayout,
-                    armnn::ResizeMethod resizeMethod)
+                    armnn::ResizeMethod resizeMethod,
+                    bool alignCorners = false,
+                    bool halfPixel = false)
 {
     using namespace armnn;
     using T = ResolveType<ArmnnType>;
@@ -64,6 +66,11 @@
        7.f, 8.f, 9.f
     };
 
+    if (alignCorners && halfPixel)
+    {
+        throw InvalidArgumentException("alignCorners and halfPixel cannot be true simultaneously ");
+    }
+
     std::vector<float> expectedOutputData;
     switch(resizeMethod)
     {
@@ -81,14 +88,42 @@
         }
         case ResizeMethod::NearestNeighbor:
         {
-            expectedOutputData =
+            if (alignCorners)
             {
-                1.f, 1.f, 2.f, 2.f, 3.f,
-                1.f, 1.f, 2.f, 2.f, 3.f,
-                4.f, 4.f, 5.f, 5.f, 6.f,
-                4.f, 4.f, 5.f, 5.f, 6.f,
-                7.f, 7.f, 8.f, 8.f, 9.f
-            };
+                expectedOutputData =
+                {
+                    1.f, 2.f, 2.f, 3.f, 3.f,
+                    4.f, 5.f, 5.f, 6.f, 6.f,
+                    4.f, 5.f, 5.f, 6.f, 6.f,
+                    7.f, 8.f, 8.f, 9.f, 9.f,
+                    7.f, 8.f, 8.f, 9.f, 9.f
+                };
+            }
+            else
+            {
+                if (halfPixel)
+                {
+                    expectedOutputData =
+                    {
+                        1.f, 1.f, 2.f, 3.f, 3.f,
+                        1.f, 1.f, 2.f, 3.f, 3.f,
+                        4.f, 4.f, 5.f, 6.f, 6.f,
+                        7.f, 7.f, 8.f, 9.f, 9.f,
+                        7.f, 7.f, 8.f, 9.f, 9.f
+                    };
+                }
+                else
+                {
+                    expectedOutputData =
+                    {
+                        1.f, 1.f, 2.f, 2.f, 3.f,
+                        1.f, 1.f, 2.f, 2.f, 3.f,
+                        4.f, 4.f, 5.f, 5.f, 6.f,
+                        4.f, 4.f, 5.f, 5.f, 6.f,
+                        7.f, 7.f, 8.f, 8.f, 9.f
+                    };
+                }
+            }
             break;
         }
         default:
@@ -102,6 +137,9 @@
     descriptor.m_TargetHeight = outputHeight;
     descriptor.m_Method       = resizeMethod;
     descriptor.m_DataLayout   = dataLayout;
+    descriptor.m_AlignCorners = alignCorners;
+    descriptor.m_HalfPixelCenters = halfPixel;
+
 
     // swizzle data if needed
     if (dataLayout == armnn::DataLayout::NHWC)
@@ -137,7 +175,9 @@
 
 template<armnn::DataType ArmnnType>
 void ResizeNearestNeighborEndToEnd(const std::vector<armnn::BackendId>& backends,
-                                   armnn::DataLayout dataLayout)
+                                   armnn::DataLayout dataLayout,
+                                   bool alignCorners = false,
+                                   bool halfPixel = false)
 {
-    ResizeEndToEnd<ArmnnType>(backends, dataLayout, armnn::ResizeMethod::NearestNeighbor);
+    ResizeEndToEnd<ArmnnType>(backends, dataLayout, armnn::ResizeMethod::NearestNeighbor, alignCorners, halfPixel);
 }
diff --git a/src/backends/reference/RefLayerSupport.cpp b/src/backends/reference/RefLayerSupport.cpp
index 2be227a..40d243e 100644
--- a/src/backends/reference/RefLayerSupport.cpp
+++ b/src/backends/reference/RefLayerSupport.cpp
@@ -2381,13 +2381,14 @@
 {
     IgnoreUnused(descriptor);
     bool supported = true;
-    std::array<DataType,6> supportedTypes =
+    std::array<DataType,7> supportedTypes =
     {
         DataType::BFloat16,
         DataType::Float32,
         DataType::Float16,
         DataType::QAsymmS8,
         DataType::QAsymmU8,
+        DataType::QSymmS8,
         DataType::QSymmS16
     };
 
diff --git a/src/backends/reference/test/RefEndToEndTests.cpp b/src/backends/reference/test/RefEndToEndTests.cpp
index 13995f5..7e07c65 100644
--- a/src/backends/reference/test/RefEndToEndTests.cpp
+++ b/src/backends/reference/test/RefEndToEndTests.cpp
@@ -1274,6 +1274,11 @@
     ResizeBilinearEndToEnd<armnn::DataType::QAsymmU8>(defaultBackends, armnn::DataLayout::NCHW);
 }
 
+TEST_CASE("RefResizeBilinearEndToEndInt8NchwTest")
+{
+    ResizeBilinearEndToEnd<armnn::DataType::QSymmS8>(defaultBackends, armnn::DataLayout::NCHW);
+}
+
 TEST_CASE("RefResizeBilinearEndToEndInt16NchwTest")
 {
     ResizeBilinearEndToEnd<armnn::DataType::QSymmS16>(defaultBackends, armnn::DataLayout::NCHW);
@@ -1289,6 +1294,11 @@
     ResizeBilinearEndToEnd<armnn::DataType::QAsymmU8>(defaultBackends, armnn::DataLayout::NHWC);
 }
 
+TEST_CASE("RefResizeBilinearEndToEndInt8NhwcTest")
+{
+    ResizeBilinearEndToEnd<armnn::DataType::QSymmS8>(defaultBackends, armnn::DataLayout::NHWC);
+}
+
 TEST_CASE("RefResizeBilinearEndToEndInt16NhwcTest")
 {
     ResizeBilinearEndToEnd<armnn::DataType::QSymmS16>(defaultBackends, armnn::DataLayout::NHWC);
@@ -1305,6 +1315,11 @@
     ResizeNearestNeighborEndToEnd<armnn::DataType::QAsymmU8>(defaultBackends, armnn::DataLayout::NCHW);
 }
 
+TEST_CASE("RefResizeNearestNeighborEndToEndInt8NchwTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::QAsymmS8>(defaultBackends, armnn::DataLayout::NCHW);
+}
+
 TEST_CASE("RefResizeNearestNeighborEndToEndInt16NchwTest")
 {
     ResizeNearestNeighborEndToEnd<armnn::DataType::QSymmS16>(defaultBackends, armnn::DataLayout::NCHW);
@@ -1320,11 +1335,37 @@
     ResizeNearestNeighborEndToEnd<armnn::DataType::QAsymmU8>(defaultBackends, armnn::DataLayout::NHWC);
 }
 
+TEST_CASE("RefResizeNearestNeighborEndToEndInt8NhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::QAsymmS8>(defaultBackends, armnn::DataLayout::NHWC);
+}
+
 TEST_CASE("RefResizeNearestNeighborEndToEndInt16NhwcTest")
 {
     ResizeNearestNeighborEndToEnd<armnn::DataType::QSymmS16>(defaultBackends, armnn::DataLayout::NHWC);
 }
 
+TEST_CASE("RefResizeNearestNeighborEndToEndFloatAlignCornersNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::Float32>(defaultBackends, armnn::DataLayout::NHWC, true, false);
+}
+
+TEST_CASE("RefResizeNearestNeighborEndToEndFloatHalfPixelNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::Float32>(defaultBackends, armnn::DataLayout::NHWC, false, true);
+}
+
+TEST_CASE("RefResizeNearestNeighborEndToEndInt8AlignCornersNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::QAsymmS8>(defaultBackends, armnn::DataLayout::NHWC, true, false);
+}
+
+TEST_CASE("TosaRefResizeNearestNeighborEndToEndInt8HalfPixelNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::QSymmS8>(defaultBackends, armnn::DataLayout::NHWC, false, true);
+}
+
+
 // ReverseV2
 TEST_CASE("RefReverseV2EndToEndFloat16Test")
 {
diff --git a/src/backends/tosaCommon/TosaMappings.cpp b/src/backends/tosaCommon/TosaMappings.cpp
index a998996..6567026 100644
--- a/src/backends/tosaCommon/TosaMappings.cpp
+++ b/src/backends/tosaCommon/TosaMappings.cpp
@@ -74,6 +74,11 @@
             auto reshapeDesc = PolymorphicDowncast<const ReshapeDescriptor*>(&descriptor);
             return ConvertReshapeToTosaOperator(layer, inputs, outputs, reshapeDesc);
         }
+        case LayerType::Resize:
+        {
+            auto resizeDesc = PolymorphicDowncast<const ResizeDescriptor*>(&descriptor);
+            return ConvertResizeToTosaOperator(layer, inputs, outputs, resizeDesc);
+        }
         case LayerType::Slice:
         {
             auto sliceDesc = PolymorphicDowncast<const SliceDescriptor*>(&descriptor);
diff --git a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
index 26f51b6..c864544 100644
--- a/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
+++ b/src/backends/tosaCommon/operatorMappings/CMakeLists.txt
@@ -20,6 +20,8 @@
         Pooling2DOperator.cpp
         ReshapeOperator.hpp
         ReshapeOperator.cpp
+        ResizeOperator.hpp
+        ResizeOperator.cpp
         SliceOperator.hpp
         SliceOperator.cpp
         TosaOperatorUtils.hpp
diff --git a/src/backends/tosaCommon/operatorMappings/ConcatOperator.hpp b/src/backends/tosaCommon/operatorMappings/ConcatOperator.hpp
index e6094ce..cbd7aca 100644
--- a/src/backends/tosaCommon/operatorMappings/ConcatOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/ConcatOperator.hpp
@@ -1,14 +1,10 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
 #pragma once
 
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
 #include "TosaOperatorUtils.hpp"
 
 using namespace armnn;
diff --git a/src/backends/tosaCommon/operatorMappings/ConstantOperator.hpp b/src/backends/tosaCommon/operatorMappings/ConstantOperator.hpp
index df158ac..598e041 100644
--- a/src/backends/tosaCommon/operatorMappings/ConstantOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/ConstantOperator.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
@@ -7,10 +7,6 @@
 
 #include "TosaOperatorUtils.hpp"
 
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
 using namespace armnn;
 using namespace tosa;
 
diff --git a/src/backends/tosaCommon/operatorMappings/Conv2dOperator.hpp b/src/backends/tosaCommon/operatorMappings/Conv2dOperator.hpp
index 909151b..f22a8d2 100644
--- a/src/backends/tosaCommon/operatorMappings/Conv2dOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/Conv2dOperator.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
@@ -7,10 +7,6 @@
 
 #include "TosaOperatorUtils.hpp"
 
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
 using namespace armnn;
 using namespace tosa;
 
diff --git a/src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.hpp b/src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.hpp
index 86031c6..4966ed1 100644
--- a/src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/ElementwiseBinaryOperator.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
@@ -7,10 +7,6 @@
 
 #include "TosaOperatorUtils.hpp"
 
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
 using namespace armnn;
 using namespace tosa;
 
diff --git a/src/backends/tosaCommon/operatorMappings/ElementwiseUnaryOperator.hpp b/src/backends/tosaCommon/operatorMappings/ElementwiseUnaryOperator.hpp
index d13428c..635abd6 100644
--- a/src/backends/tosaCommon/operatorMappings/ElementwiseUnaryOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/ElementwiseUnaryOperator.hpp
@@ -6,9 +6,6 @@
 #pragma once
 
 #include "TosaOperatorUtils.hpp"
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
 
 using namespace armnn;
 using namespace tosa;
diff --git a/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.hpp b/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.hpp
index cc9ec09..1323abc 100644
--- a/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
@@ -7,10 +7,6 @@
 
 #include "TosaOperatorUtils.hpp"
 
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
 using namespace armnn;
 using namespace tosa;
 
diff --git a/src/backends/tosaCommon/operatorMappings/ReshapeOperator.hpp b/src/backends/tosaCommon/operatorMappings/ReshapeOperator.hpp
index 4f363df..007d2df 100644
--- a/src/backends/tosaCommon/operatorMappings/ReshapeOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/ReshapeOperator.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
@@ -7,10 +7,6 @@
 
 #include "TosaOperatorUtils.hpp"
 
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
 using namespace armnn;
 using namespace tosa;
 
diff --git a/src/backends/tosaCommon/operatorMappings/ResizeOperator.cpp b/src/backends/tosaCommon/operatorMappings/ResizeOperator.cpp
new file mode 100644
index 0000000..72c7352
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/ResizeOperator.cpp
@@ -0,0 +1,173 @@
+//
+// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+// Copyright © 2020, 2023 The TensorFlow Authors. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <numeric>
+#include "ResizeOperator.hpp"
+
+// This function is paraphrased from:
+// tensorflow/compiler/mlir/tosa/transforms/legalize_common.cc from function convertResizeOp
+// tensorflow/lite/kernels/internal/reference/resize_utils.h
+TosaSerializationBasicBlock* ConvertResizeToTosaOperator(const Layer* layer,
+                                                         const std::vector<const TensorInfo*>& inputs,
+                                                         const std::vector<const TensorInfo*>& outputs,
+                                                         const ResizeDescriptor* resizeDescriptor)
+{
+    ARMNN_THROW_INVALIDARG_MSG_IF_FALSE( inputs.size() == 1,
+                                         "ConvertResizeToTosaOperator: Resize must have only one input." );
+    ARMNN_THROW_INVALIDARG_MSG_IF_FALSE( resizeDescriptor->m_DataLayout == DataLayout::NHWC,
+                                         "ConvertResizeToTosaOperator: NCHW not supported.");
+
+    ResizeMode mode;
+    if (resizeDescriptor->m_Method == ResizeMethod::NearestNeighbor)
+    {
+        mode = tosa::ResizeMode_NEAREST;
+    }
+    else if (resizeDescriptor->m_Method == ResizeMethod::Bilinear)
+    {
+        mode = tosa::ResizeMode_BILINEAR;
+        throw armnn::InvalidArgumentException("ConvertResizeToTosaOperator: Unimplemented Resize method.");
+    }
+    else
+    {
+        throw armnn::InvalidArgumentException("ConvertResizeToTosaOperator: Unsupported Resize method.");
+    }
+
+    std::string inputName = std::string("input0_");
+    std::string outputName = std::string("output0_");
+    std::string blockName  = std::string("Op_RESIZE_block_") + GetUniqueTosaMappingID();
+
+    // If a layer is present then the block will be used for execution, so input and output names need to be determined
+    // using the previous and following layers so the graph is connected correctly. For validation this doesn't matter.
+    if(layer != nullptr)
+    {
+        // Get the layers connected to the input slots and determine unique tensor names.
+        Layer& connectedLayer = layer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer();
+        inputName = GenerateUniqueName(connectedLayer, 0);
+
+        // Determine unique output tensor name.
+        outputName = GenerateUniqueOutputName(*layer, 0);
+    }
+
+    int32_t inputHeight = static_cast<int32_t>(inputs[0]->GetShape()[1]);
+    int32_t inputWidth = static_cast<int32_t>(inputs[0]->GetShape()[2]);
+
+    int32_t outputHeight = static_cast<int32_t>(resizeDescriptor->m_TargetHeight);
+    int32_t outputWidth = static_cast<int32_t>(resizeDescriptor->m_TargetWidth);
+    bool alignCorners = resizeDescriptor->m_AlignCorners;
+    bool halfPixel = resizeDescriptor->m_HalfPixelCenters;
+
+    // Go from ArmNN parameters (outputShape, halfPixel and alignedCorners)
+    // to TOSA parameters (scale, offset and border)
+    // Align corners sets the scaling ratio to (O - 1)/(I - 1) rather than O / I.
+    auto preprocessResizeParameters = [&](int inputSize, int outputSize, int& scale_n, int& scale_d, int& offset)
+    {
+        // Dimension is length 1, we are just sampling from one value.
+        if (inputSize == 1)
+        {
+            scale_n = outputSize;
+            scale_d = 1;
+            offset = 0;
+            return;
+        }
+
+        // Apply if aligned and capable to be aligned.
+        // Align corners sets the scaling ratio to (OH - 1)/(IH - 1) rather than OH / IH. Same for width.
+        bool applyAligned = alignCorners && (outputSize > 1);
+        scale_n = applyAligned ? (outputSize - 1) : outputSize;
+        scale_d = applyAligned ? (inputSize - 1) : inputSize;
+
+        // Simplify the scales, make sure they are even values.
+        int gcd = std::gcd(scale_n, scale_d);
+        scale_n = 2 * scale_n / gcd;
+        scale_d = 2 * scale_d / gcd;
+
+        // If half pixel centers then input and output sampling positions are offset by 1/2 pixel.
+        offset = halfPixel ? (scale_d / 2 - scale_n / 2) : 0;
+
+        // Reduce the scaling ratio if possible, we know scale_n and scale_d are even
+        if ((offset & 1) == 0)
+        {
+            scale_n /= 2;
+            scale_d /= 2;
+            offset /= 2;
+        }
+    };
+
+    int scale_y_n, scale_y_d, offset_y;
+    int scale_x_n, scale_x_d, offset_x;
+    preprocessResizeParameters(inputHeight, outputHeight, scale_y_n, scale_y_d, offset_y);
+    preprocessResizeParameters(inputWidth, outputWidth, scale_x_n, scale_x_d, offset_x);
+
+    int border_y = scale_y_d * (outputHeight - 1) - scale_y_n * (inputHeight - 1) + offset_y;
+    int border_x = scale_x_d * (outputWidth - 1) - scale_x_n * (inputWidth - 1) + offset_x;
+
+    // [scale_y_n, scale_y_d, scale_x_n, scale_x_d]
+    std::vector<int16_t> scale = { static_cast<int16_t>(scale_y_n),
+                                   static_cast<int16_t>(scale_y_d),
+                                   static_cast<int16_t>(scale_x_n),
+                                   static_cast<int16_t>(scale_x_d) };
+
+    // [offset_y, offset_x]
+    std::vector<int16_t> offset = { static_cast<int16_t>(offset_y),
+                                    static_cast<int16_t>(offset_x) };
+    // [border_y, border_x]
+    std::vector<int16_t> border = { static_cast<int16_t>(border_y),
+                                    static_cast<int16_t>(border_x) };
+
+    auto isInt16Range = [](int x)
+    {
+        return (x <= std::numeric_limits<int16_t>::max()) && (x >= std::numeric_limits<int16_t>::min());
+    };
+
+    if (inputs[0]->IsQuantized())
+    {
+        // It isn't commonly seen these numbers aren't fit within 16 bits, and won't match TFLite reference.
+        if (!isInt16Range(scale_y_n) || !isInt16Range(scale_y_d) ||
+            !isInt16Range(scale_x_n) || !isInt16Range(scale_x_d) ||
+            !isInt16Range(offset_y) || !isInt16Range(offset_x) ||
+            !isInt16Range(border_y) || !isInt16Range(border_x))
+        {
+            throw armnn::Exception("ConvertResizeToTosaOperator: stride or offset out of 16 bit range");
+        }
+    }
+
+    TosaResizeAttribute resizeAttribute(scale, offset, border, mode);
+
+    auto* op = new TosaSerializationOperator(Op_RESIZE,
+                                             Attribute_ResizeAttribute,
+                                             &resizeAttribute,
+                                             {inputName},
+                                             {outputName});
+
+    std::vector<TosaSerializationTensor*> tensors;
+
+    // Only add input tensors if connected layer is an input layer.
+    // As intermediate or constant tensors will be created separately.
+    // There also can't be duplicate tensor.
+    if(inputName.find("input0_") != std::string::npos)
+    {
+        std::vector<int32_t> inputShape = GetTosaTensorShape(inputs[0]->GetShape());
+        DType inputDType = ArmNNToDType(inputs[0]->GetDataType());
+
+        tensors.push_back(new TosaSerializationTensor(inputName, inputShape, inputDType, {}));
+    }
+
+    std::vector<int32_t> outputShape = GetTosaTensorShape(outputs[0]->GetShape());
+    DType outputDType = ArmNNToDType(outputs[0]->GetDataType());
+
+    tensors.push_back(new TosaSerializationTensor(outputName, outputShape, outputDType, {}));
+
+    // operatorInputNames/operatorOutputNames ends up being the same as
+    // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings
+    return new TosaSerializationBasicBlock(blockName, // name
+                                           mainName, // region name
+                                           {op}, // operators
+                                           tensors, // tensors
+                                           {inputName}, // inputs
+                                           {outputName}); // outputs
+}
\ No newline at end of file
diff --git a/src/backends/tosaCommon/operatorMappings/ResizeOperator.hpp b/src/backends/tosaCommon/operatorMappings/ResizeOperator.hpp
new file mode 100644
index 0000000..881e7c7
--- /dev/null
+++ b/src/backends/tosaCommon/operatorMappings/ResizeOperator.hpp
@@ -0,0 +1,16 @@
+//
+// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "TosaOperatorUtils.hpp"
+
+using namespace armnn;
+using namespace tosa;
+
+TosaSerializationBasicBlock* ConvertResizeToTosaOperator(const Layer* inputSize,
+                                                         const std::vector<const TensorInfo*>& outputSize,
+                                                         const std::vector<const TensorInfo*>& scale_n,
+                                                         const ResizeDescriptor* scale_d);
diff --git a/src/backends/tosaCommon/operatorMappings/SliceOperator.hpp b/src/backends/tosaCommon/operatorMappings/SliceOperator.hpp
index 127cc81..69a4df5 100644
--- a/src/backends/tosaCommon/operatorMappings/SliceOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/SliceOperator.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
@@ -7,10 +7,6 @@
 
 #include "TosaOperatorUtils.hpp"
 
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
 using namespace armnn;
 using namespace tosa;
 
diff --git a/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
index 66dc1b3..369b37f 100644
--- a/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
+++ b/src/backends/tosaCommon/operatorMappings/TosaCommonOperators.hpp
@@ -13,6 +13,7 @@
 #include "ElementwiseUnaryOperator.hpp"
 #include "Pooling2DOperator.hpp"
 #include "ReshapeOperator.hpp"
+#include "ResizeOperator.hpp"
 #include "SliceOperator.hpp"
 #include "TransposeConv2dOperator.hpp"
 #include "TransposeOperator.hpp"
diff --git a/src/backends/tosaCommon/operatorMappings/TransposeConv2dOperator.hpp b/src/backends/tosaCommon/operatorMappings/TransposeConv2dOperator.hpp
index eb911a1..c94795c 100644
--- a/src/backends/tosaCommon/operatorMappings/TransposeConv2dOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/TransposeConv2dOperator.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
@@ -7,10 +7,6 @@
 
 #include "TosaOperatorUtils.hpp"
 
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
 using namespace armnn;
 using namespace tosa;
 
diff --git a/src/backends/tosaCommon/operatorMappings/TransposeOperator.hpp b/src/backends/tosaCommon/operatorMappings/TransposeOperator.hpp
index 3d1e2ac..19c97cf 100644
--- a/src/backends/tosaCommon/operatorMappings/TransposeOperator.hpp
+++ b/src/backends/tosaCommon/operatorMappings/TransposeOperator.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
@@ -7,10 +7,6 @@
 
 #include "TosaOperatorUtils.hpp"
 
-#include <Layer.hpp>
-
-#include <tosa_serialization_handler.h>
-
 using namespace armnn;
 using namespace tosa;
 
diff --git a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
index 0cf8002..267c9fb 100644
--- a/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
+++ b/src/backends/tosaCommon/test/OneToOneMappingTests.cpp
@@ -553,6 +553,148 @@
                                         LayerType::Reshape);
 }
 
+
+TEST_CASE("GetTosaMapping_ResizeLayer")
+{
+    TensorInfo inputInfo  = TensorInfo({ 1, 2, 3, 3 }, DataType::Float32);
+    TensorInfo outputInfo = TensorInfo({ 1, 4, 6, 3 }, DataType::Float32);
+
+    std::vector<std::vector<int32_t>> inputShape  = {{ 1, 2, 3, 3 }};
+    std::vector<std::vector<int32_t>> outputShape = {{ 1, 4, 6, 3 }};
+
+    ResizeDescriptor descriptor;
+    descriptor.m_DataLayout = DataLayout::NHWC;
+    descriptor.m_TargetHeight = 4;
+    descriptor.m_TargetWidth = 6;
+
+    TosaSerializationBasicBlock* basicBlock = GetTosaMapping(nullptr,
+                                                             LayerType::Resize,
+                                                             {&inputInfo},
+                                                             {&outputInfo},
+                                                             descriptor);
+    AssertTosaOneToOneMappingBasicBlock(basicBlock,
+                                        inputShape,
+                                        outputShape,
+                                        Op_RESIZE,
+                                        Attribute_ResizeAttribute,
+                                        descriptor,
+                                        LayerType::Resize);
+}
+
+TEST_CASE("GetTosaMappingFromLayer_ResizeLayer")
+{
+    IRuntime::CreationOptions options;
+    IRuntimePtr runtime(IRuntime::Create(options));
+
+    // Builds up the structure of the network.
+    INetworkPtr net(INetwork::Create());
+
+    ResizeDescriptor descriptor;
+    descriptor.m_DataLayout = DataLayout::NHWC;
+    descriptor.m_TargetHeight = 2;
+    descriptor.m_TargetWidth = 3;
+
+    IConnectableLayer* input  = net->AddInputLayer(0, "input");
+    IConnectableLayer* resize = net->AddResizeLayer(descriptor, "resize");
+    IConnectableLayer* output = net->AddOutputLayer(0, "output");
+
+    input->GetOutputSlot(0).Connect(resize->GetInputSlot(0));
+    resize->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+    TensorInfo inputInfo  = TensorInfo({ 1, 4, 6, 3 }, DataType::Float32);
+    TensorInfo outputInfo = TensorInfo({ 1, 2, 3, 3 }, DataType::Float32);
+
+    input->GetOutputSlot(0).SetTensorInfo(inputInfo);
+    resize->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+    std::vector<std::vector<int32_t>> inputShape  = {{ 1, 4, 6, 3 }};
+    std::vector<std::vector<int32_t>> outputShape = {{ 1, 2, 3, 3 }};
+
+    TosaSerializationBasicBlock* basicBlock = GetTosaMappingFromLayer(PolymorphicDowncast<Layer*>(resize));
+    AssertTosaOneToOneMappingBasicBlock(basicBlock,
+                                        inputShape,
+                                        outputShape,
+                                        Op_RESIZE,
+                                        Attribute_ResizeAttribute,
+                                        descriptor,
+                                        LayerType::Resize);
+}
+
+TEST_CASE("UNSUPPORTED_GetTosaMapping_ResizeLayer_NCHW")
+{
+    TensorInfo inputInfo  = TensorInfo({ 1, 3, 2, 3 }, DataType::Float32);
+    TensorInfo outputInfo = TensorInfo({ 1, 3, 4, 6 }, DataType::Float32);
+
+    std::vector<std::vector<int32_t>> inputShape  = {{ 1, 3, 2, 3 }};
+    std::vector<std::vector<int32_t>> outputShape = {{ 1, 3, 4, 6 }};
+
+    ResizeDescriptor descriptor;
+    descriptor.m_DataLayout = DataLayout::NCHW;
+    descriptor.m_TargetHeight = 4;
+    descriptor.m_TargetWidth = 6;
+
+    try
+    {
+        TosaSerializationBasicBlock* basicBlock = GetTosaMapping(nullptr,
+                                                                 LayerType::Resize,
+                                                                 {&inputInfo},
+                                                                 {&outputInfo},
+                                                                 descriptor);
+
+        AssertTosaOneToOneMappingBasicBlock(basicBlock,
+                                            inputShape,
+                                            outputShape,
+                                            Op_RESIZE,
+                                            Attribute_ResizeAttribute,
+                                            descriptor,
+                                            LayerType::Resize);
+
+        FAIL("An exception should have been thrown");
+    }
+    catch (const armnn::InvalidArgumentException& e)
+    {
+        CHECK(strcmp(e.what(), "ConvertResizeToTosaOperator: NCHW not supported.") == 0);
+    }
+}
+
+TEST_CASE("UNSUPPORTED_GetTosaMapping_ResizeLayer_Bilinear")
+{
+    TensorInfo inputInfo  = TensorInfo({ 1, 2, 3, 3 }, DataType::Float32);
+    TensorInfo outputInfo = TensorInfo({ 1, 4, 6, 3 }, DataType::Float32);
+
+    std::vector<std::vector<int32_t>> inputShape  = {{ 1, 2, 3, 3 }};
+    std::vector<std::vector<int32_t>> outputShape = {{ 1, 4, 6, 3 }};
+
+    ResizeDescriptor descriptor;
+    descriptor.m_Method = ResizeMethod::Bilinear;
+    descriptor.m_DataLayout = DataLayout::NHWC;
+    descriptor.m_TargetHeight = 4;
+    descriptor.m_TargetWidth = 6;
+
+    try
+    {
+        TosaSerializationBasicBlock* basicBlock = GetTosaMapping(nullptr,
+                                                                 LayerType::Resize,
+                                                                 {&inputInfo},
+                                                                 {&outputInfo},
+                                                                 descriptor);
+
+        AssertTosaOneToOneMappingBasicBlock(basicBlock,
+                                            inputShape,
+                                            outputShape,
+                                            Op_RESIZE,
+                                            Attribute_ResizeAttribute,
+                                            descriptor,
+                                            LayerType::Resize);
+
+        FAIL("An exception should have been thrown");
+    }
+    catch (const armnn::InvalidArgumentException& e)
+    {
+        CHECK(strcmp(e.what(), "ConvertResizeToTosaOperator: Unimplemented Resize method.") == 0);
+    }
+}
+
 TEST_CASE("GetTosaMapping_SliceLayer")
 {
     TensorInfo inputInfo = TensorInfo({ 3, 2, 3 }, DataType::Float32);
diff --git a/src/backends/tosaCommon/test/TosaTestUtils.hpp b/src/backends/tosaCommon/test/TosaTestUtils.hpp
index e240553..87ff5ff 100644
--- a/src/backends/tosaCommon/test/TosaTestUtils.hpp
+++ b/src/backends/tosaCommon/test/TosaTestUtils.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
+// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
 // SPDX-License-Identifier: MIT
 //
 
@@ -125,16 +125,65 @@
 
             break;
         }
+        case LayerType::Resize:
+        {
+            auto resizeDesc = PolymorphicDowncast<const ResizeDescriptor*>(&descriptor);
+            TosaResizeAttribute resizeAttribute(attribute);
+
+            // Check output shape
+            uint32_t outputHeight = resizeDesc->m_TargetHeight;
+            uint32_t outputWidth = resizeDesc->m_TargetWidth;
+
+            CHECK((outputShape.size() == 4));
+            if (resizeDesc->m_DataLayout == DataLayout::NHWC)
+            {
+                //Check output is not dynamic
+                CHECK((outputShape[1] > 0));
+                CHECK((outputShape[2] > 0));
+
+                CHECK((outputHeight == static_cast<uint32_t>(outputShape[1])));
+                CHECK((outputWidth == static_cast<uint32_t>(outputShape[2])));
+            }
+            else if (resizeDesc->m_DataLayout == DataLayout::NCHW)
+            {
+                //Check output is not dynamic
+                CHECK((outputShape[2] > 0));
+                CHECK((outputShape[3] > 0));
+
+                CHECK((outputHeight == static_cast<uint32_t>(outputShape[2])));
+                CHECK((outputWidth == static_cast<uint32_t>(outputShape[3])));
+            }
+            else
+            {
+                throw armnn::Exception("VerifyTosaAttribute: Invalid DataLayout in Resize.");
+            }
+
+            // Check Resize mode/method
+            if (resizeDesc->m_Method == ResizeMethod::NearestNeighbor)
+            {
+                CHECK((resizeAttribute.mode() == tosa::ResizeMode_NEAREST));
+            }
+            else if (resizeDesc->m_Method == ResizeMethod::Bilinear)
+            {
+                CHECK((resizeAttribute.mode() == tosa::ResizeMode_BILINEAR));
+            }
+            else
+            {
+                throw armnn::Exception("VerifyTosaAttribute: Unsupported Resize method.");
+            }
+
+            break;
+        }
         case LayerType::Slice:
         {
             auto sliceDesc = PolymorphicDowncast<const SliceDescriptor*>(&descriptor);
-            TosaSliceAttribute reshapeAttribute(attribute);
+            TosaSliceAttribute sliceAttribute(attribute);
 
             std::vector<int32_t> begin(sliceDesc->m_Begin.begin(), sliceDesc->m_Begin.end());
             std::vector<int32_t> size(sliceDesc->m_Size.begin(), sliceDesc->m_Size.end());
 
-            CHECK(begin == reshapeAttribute.start());
-            CHECK(size == reshapeAttribute.size());
+            CHECK(begin == sliceAttribute.start());
+            CHECK(size == sliceAttribute.size());
 
             CHECK(begin.size() == inputShape.size());
             CHECK(size.size() == inputShape.size());
diff --git a/src/backends/tosaReference/TosaRefLayerSupport.cpp b/src/backends/tosaReference/TosaRefLayerSupport.cpp
index e1c349f..04be52d 100644
--- a/src/backends/tosaReference/TosaRefLayerSupport.cpp
+++ b/src/backends/tosaReference/TosaRefLayerSupport.cpp
@@ -71,6 +71,7 @@
         case LayerType::ElementwiseUnary:
         case LayerType::Pooling2d:
         case LayerType::Reshape:
+        case LayerType::Resize:
         case LayerType::Slice:
         case LayerType::Transpose:
             inputInfos.push_back(&infos[0]);
diff --git a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
index 26cadd2..b35dacb 100644
--- a/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefEndToEndTests.cpp
@@ -11,6 +11,7 @@
 #include "backendsCommon/test/MultiplicationEndToEndTestImpl.hpp"
 #include "backendsCommon/test/Pooling2dEndToEndTestImpl.hpp"
 #include "backendsCommon/test/ReshapeEndToEndTestImpl.hpp"
+#include "backendsCommon/test/ResizeEndToEndTestImpl.hpp"
 #include "backendsCommon/test/ElementwiseUnaryEndToEndTestImpl.hpp"
 #include "backendsCommon/test/SliceEndToEndTestImpl.hpp"
 #include "backendsCommon/test/SubtractionEndToEndTestImpl.hpp"
@@ -145,6 +146,47 @@
                                                              UnaryOperation::Rsqrt);
 }
 
+// Resize
+TEST_CASE("TosaRefResizeNearestNeighborEndToEndFloat32AlignCornersNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::Float32>(tosaDefaultBackends, armnn::DataLayout::NHWC, true, false);
+}
+
+TEST_CASE("TosaRefResizeNearestNeighborEndToEndFloat32HalfPixelNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::Float32>(tosaDefaultBackends, armnn::DataLayout::NHWC, false, true);
+}
+
+TEST_CASE("TosaRefResizeNearestNeighborEndToEndFloat16AlignCornersNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::Float16>(tosaDefaultBackends, armnn::DataLayout::NHWC, true, false);
+}
+
+TEST_CASE("TosaRefResizeNearestNeighborEndToEndFloat16HalfPixelNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::Float16>(tosaDefaultBackends, armnn::DataLayout::NHWC, false, true);
+}
+
+TEST_CASE("TosaRefResizeNearestNeighborEndToEndInt8AlignCornersNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::QSymmS8>(tosaDefaultBackends, armnn::DataLayout::NHWC, true, false);
+}
+
+TEST_CASE("TosaRefResizeNearestNeighborEndToEndInt8HalfPixelNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::QSymmS8>(tosaDefaultBackends, armnn::DataLayout::NHWC, false, true);
+}
+
+TEST_CASE("TosaRefResizeNearestNeighborEndToEndInt16AlignCornersNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::QSymmS16>(tosaDefaultBackends, armnn::DataLayout::NHWC, true, false);
+}
+
+TEST_CASE("TosaRefResizeNearestNeighborEndToEndInt16HalfPixelNhwcTest")
+{
+    ResizeNearestNeighborEndToEnd<armnn::DataType::QSymmS16>(tosaDefaultBackends, armnn::DataLayout::NHWC, false, true);
+}
+
 // Slice
 TEST_CASE("TosaRefSliceEndtoEndTestFloat32")
 {
diff --git a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
index e32894f..fb4c84f 100644
--- a/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
+++ b/src/backends/tosaReference/test/TosaRefLayerSupportTests.cpp
@@ -352,6 +352,30 @@
     CHECK(supported);
 }
 
+TEST_CASE("IsLayerSupportedTosaReferenceResize")
+{
+    TensorShape inShape  = { 1, 720, 1280, 3 };
+    TensorShape outShape = { 1, 1080, 1920, 3 };
+    TensorInfo in(inShape, DataType::Float32);
+    TensorInfo out(outShape, DataType::Float32);
+
+    ResizeDescriptor descriptor;
+    descriptor.m_DataLayout = armnn::DataLayout::NHWC;
+    descriptor.m_TargetHeight = 1080;
+    descriptor.m_TargetWidth = 1920;
+
+    TosaRefLayerSupport supportChecker;
+    std::string reasonIfNotSupported;
+    auto supported = supportChecker.IsLayerSupported(LayerType::Resize,
+                                                     {in, out},
+                                                     descriptor,
+                                                     EmptyOptional(),
+                                                     EmptyOptional(),
+                                                     reasonIfNotSupported);
+
+    CHECK(supported);
+}
+
 TEST_CASE("IsLayerSupportedTosaReferenceReshapeUnsupported")
 {
     TensorShape inShape = {3,4};
diff --git a/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp
index 8b08f01..5e4103a 100644
--- a/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp
+++ b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.cpp
@@ -50,9 +50,15 @@
                 SetInput<float>(runner, inputNames[inputSlotIdx], inputSlotIdx);
                 break;
             case DataType::QAsymmU8:
+                SetInput<uint8_t, int32_t>(runner, inputNames[inputSlotIdx], inputSlotIdx);
+                break;
             case DataType::QAsymmS8:
             case DataType::QSymmS8:
+                SetInput<int8_t, int32_t>(runner, inputNames[inputSlotIdx], inputSlotIdx);
+                break;
             case DataType::QSymmS16:
+                SetInput<int16_t, int32_t>(runner, inputNames[inputSlotIdx], inputSlotIdx);
+                break;
             case DataType::Signed32:
                 SetInput<int32_t>(runner, inputNames[inputSlotIdx], inputSlotIdx);
                 break;
@@ -87,9 +93,15 @@
                 GetOutput<float>(runner, outputNames[outputSlotIdx], outputSlotIdx);
                 break;
             case DataType::QAsymmU8:
+                GetOutput<uint8_t, int32_t>(runner, outputNames[outputSlotIdx], outputSlotIdx);
+                break;
             case DataType::QAsymmS8:
             case DataType::QSymmS8:
+                GetOutput<int8_t, int32_t>(runner, outputNames[outputSlotIdx], outputSlotIdx);
+                break;
             case DataType::QSymmS16:
+                GetOutput<int16_t, int32_t>(runner, outputNames[outputSlotIdx], outputSlotIdx);
+                break;
             case DataType::Signed32:
                 GetOutput<int32_t>(runner, outputNames[outputSlotIdx], outputSlotIdx);
                 break;
@@ -110,10 +122,23 @@
                                           std::string inputName,
                                           uint32_t inputIndex) const
 {
+    SetInput<T, T>(runner, inputName, inputIndex);
+}
+
+template <typename T, typename Trunner>
+void TosaRefPreCompiledWorkload::SetInput(TosaReference::IModelRunner& runner,
+                                          std::string inputName,
+                                          uint32_t inputIndex) const
+{
     std::vector<T> inputData(m_Data.m_Inputs[inputIndex]->GetShape().GetNumElements());
+    std::vector<Trunner> inputDataRunner(m_Data.m_Inputs[inputIndex]->GetShape().GetNumElements());
+
     m_Data.m_Inputs[inputIndex]->CopyOutTo(inputData.data());
 
-    runner.setInput<T>(inputName, inputData);
+    std::transform(inputData.begin(), inputData.end(),
+                   inputDataRunner.begin(), [](T x) { return static_cast<Trunner>(x);});
+
+    runner.setInput<Trunner>(inputName, inputDataRunner);
 }
 
 template <typename T>
@@ -121,7 +146,19 @@
                                            std::string outputName,
                                            uint32_t outputIndex) const
 {
-    std::vector<T> actualOutputs = runner.getOutput<T>(outputName);
+    GetOutput<T, T>(runner, outputName, outputIndex);
+}
+
+template <typename T, typename Trunner>
+void TosaRefPreCompiledWorkload::GetOutput(TosaReference::IModelRunner& runner,
+                                           std::string outputName,
+                                           uint32_t outputIndex) const
+{
+    std::vector<Trunner> actualOutputsRunner = runner.getOutput<Trunner>(outputName);
+    std::vector<T> actualOutputs (actualOutputsRunner.size());
+
+    std::transform(actualOutputsRunner.begin(), actualOutputsRunner.end(),
+                   actualOutputs.begin(), [](Trunner x) { return static_cast<T>(x);});
 
     m_Data.m_Outputs[outputIndex]->CopyInFrom(actualOutputs.data());
 }
diff --git a/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.hpp b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.hpp
index 2b3a314..337e8f9 100644
--- a/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.hpp
+++ b/src/backends/tosaReference/workloads/TosaRefPreCompiledWorkload.hpp
@@ -42,9 +42,15 @@
         this->m_Data.m_Outputs[slot] = tensorHandle;
     }
 
+    template <typename T, typename Trunner>
+    void SetInput(TosaReference::IModelRunner& runner, std::string inputName, uint32_t inputIndex) const;
+
     template <typename T>
     void SetInput(TosaReference::IModelRunner& runner, std::string inputName, uint32_t inputIndex) const;
 
+    template <typename T, typename Trunner>
+    void GetOutput(TosaReference::IModelRunner& runner, std::string outputName, uint32_t outputIndex) const;
+
     template <typename T>
     void GetOutput(TosaReference::IModelRunner& runner, std::string outputName, uint32_t outputIndex) const;