From 0506ef0a099f5ba564af5e110e6857a68f462080 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Tue, 3 Jan 2023 16:29:44 +0000 Subject: GitHub #543 Problem Parsing Mixed-Precision Model * Fixed bug when converting Constants with Per-Axis Quantization Signed-off-by: Mike Kelly Change-Id: Ifbea23e60483746ec987da491dae96e74cb33af4 --- include/armnnUtils/TensorUtils.hpp | 5 + src/armnn/TypesUtils.cpp | 6 +- src/armnnTfLiteParser/TfLiteParser.cpp | 104 +++++++++---------- src/armnnTfLiteParser/TfLiteParser.hpp | 8 ++ src/armnnTfLiteParser/test/Conv2D.cpp | 2 +- src/armnnUtils/TensorUtils.cpp | 91 ++++++++++++++++- src/armnnUtils/test/TensorUtilsTest.cpp | 173 +++++++++++++++++++++++++++++++- 7 files changed, 329 insertions(+), 60 deletions(-) diff --git a/include/armnnUtils/TensorUtils.hpp b/include/armnnUtils/TensorUtils.hpp index f7f20bd065..2d6ec2fea4 100644 --- a/include/armnnUtils/TensorUtils.hpp +++ b/include/armnnUtils/TensorUtils.hpp @@ -55,4 +55,9 @@ unsigned int GetNumElementsAfter(const armnn::TensorShape& shape, unsigned int a std::pair> GetPerAxisParams(const armnn::TensorInfo& info); +template +std::unique_ptr ToFloatArray(const std::vector& data, const armnn::TensorInfo& tensorInfo); + +std::unique_ptr ToFloatArray(const std::vector& data, const armnn::TensorInfo& tensorInfo); + } // namespace armnnUtils diff --git a/src/armnn/TypesUtils.cpp b/src/armnn/TypesUtils.cpp index 4ba9ed19e1..74ac231bc9 100644 --- a/src/armnn/TypesUtils.cpp +++ b/src/armnn/TypesUtils.cpp @@ -81,4 +81,8 @@ float armnn::Dequantize(int16_t value, float scale, int32_t offset); /// Explicit specialization of Dequantize for int32_t template -float armnn::Dequantize(int32_t value, float scale, int32_t offset); \ No newline at end of file +float armnn::Dequantize(int32_t value, float scale, int32_t offset); + +/// Explicit specialization of Dequantize for int64_t +template +float armnn::Dequantize(int64_t value, float scale, int32_t offset); diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp index 0484c6f478..191cfd2b48 100644 --- a/src/armnnTfLiteParser/TfLiteParser.cpp +++ b/src/armnnTfLiteParser/TfLiteParser.cpp @@ -316,6 +316,14 @@ std::vector GetUIntBuffer(armnn::TensorInfo info, ::memcpy(uint64Buffer.data(), bufferPtr->data.data(), bufferPtr->data.size()); buffer.assign(std::begin(uint64Buffer), std::end(uint64Buffer)); } + else + { + CheckLocation location = CHECK_LOCATION(); + throw ParseException( + fmt::format("Unsupported data type for uint buffer {}, only Signed 32 or Signed 64 are supported. {}", + GetDataTypeName(info.GetDataType()), + location.AsString())); + } return buffer; } @@ -911,42 +919,16 @@ INetworkPtr TfLiteParserImpl::CreateNetworkFromModel() return std::move(m_Network); } -std::unique_ptr AsFloatArray(TfLiteParserImpl::BufferRawPtr bufferPtr, - const TensorInfo& tensorInfo) +bool TfLiteParserImpl::ShouldConstantTensorBeConverted(TfLiteParserImpl::TensorRawPtr tensorPtr, + armnn::DataType inputDataType, + armnn::DataType tensorDataType) { - if (tensorInfo.GetDataType() == DataType::QAsymmS8 || tensorInfo.GetDataType() == DataType::QSymmS8 || - tensorInfo.GetDataType() == DataType::QAsymmU8) - { - std::unique_ptr buffer(new float[tensorInfo.GetNumElements()]); - - if (tensorInfo.HasPerAxisQuantization()) - { - unsigned int axis = tensorInfo.GetQuantizationDim().value(); - auto axisDimensionality = tensorInfo.GetShape()[axis]; - auto axisFactor = armnnUtils::GetNumElementsAfter(tensorInfo.GetShape(), axis); - - for (unsigned int i = 0; i < tensorInfo.GetNumDimensions(); ++i) - { - unsigned int axisIndex = (i / axisFactor) % axisDimensionality; - buffer[i] = Dequantize(bufferPtr->data[i], tensorInfo.GetQuantizationScales()[axisIndex], - tensorInfo.GetQuantizationOffset()); - } - } - else - { - for (unsigned int i = 0; i < tensorInfo.GetNumElements(); ++i) - { - buffer[i] = Dequantize(bufferPtr->data[i], tensorInfo.GetQuantizationScale(), - tensorInfo.GetQuantizationOffset()); - } - } - return buffer; - } - throw ParseException( - fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}", - GetDataTypeName(DataType::Float32), - GetDataTypeName(tensorInfo.GetDataType()), - CHECK_LOCATION().AsString())); + return (TfLiteParserImpl::IsConstTensor(tensorPtr) && inputDataType == DataType::Float32 && + (tensorDataType == DataType::QAsymmU8 || + tensorDataType == DataType::QAsymmS8 || + tensorDataType == DataType::QSymmS8 || + tensorDataType == DataType::Signed32 || + tensorDataType == DataType::Signed64)); } void TfLiteParserImpl::RegisterProducerOfTensor(size_t subgraphIndex, @@ -1136,9 +1118,7 @@ void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex) auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex); armnn::IConnectableLayer* layer = m_Network->AddConvolution2dLayer(desc, layerName.c_str()); - if (IsConstTensor(inputs[1]) && inputTensorInfo.GetDataType() == DataType::Float32 && - (filterTensorInfo.GetDataType() == DataType::QAsymmU8 || - filterTensorInfo.GetDataType() == DataType::QAsymmS8)) + if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType())) { m_ConstantsToDequantize.emplace_back(inputs[1]->buffer); } @@ -1150,9 +1130,7 @@ void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex) // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers. tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]); - if (IsConstTensor(inputs[2]) && inputTensorInfo.GetDataType() == DataType::Float32 && - (filterTensorInfo.GetDataType() == DataType::QAsymmU8 || - filterTensorInfo.GetDataType() == DataType::QAsymmS8)) + if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType())) { m_ConstantsToDequantize.emplace_back(inputs[2]->buffer); } @@ -3112,9 +3090,7 @@ void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operator // Add the weights input to the registration list, constant layers will be added by SetupConstantLayers if constant. tensorIndexesToRegister.emplace_back(inputTensorIndexes[1]); - if (desc.m_ConstantWeights && inputTensorInfo.GetDataType() == DataType::Float32 && - (filterTensorInfo.GetDataType() == DataType::QAsymmU8 || - filterTensorInfo.GetDataType() == DataType::QAsymmS8)) + if (ShouldConstantTensorBeConverted(inputs[1], inputTensorInfo.GetDataType(), filterTensorInfo.GetDataType())) { m_ConstantsToDequantize.emplace_back(inputs[1]->buffer); } @@ -3127,9 +3103,7 @@ void TfLiteParserImpl::ParseFullyConnected(size_t subgraphIndex, size_t operator // Add the biases input to the registration list, constant layer will be added by SetupConstantLayers. tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]); - if (desc.m_ConstantWeights && inputTensorInfo.GetDataType() == DataType::Float32 && - (biasTensorInfo.GetDataType() == DataType::QAsymmU8 || - biasTensorInfo.GetDataType() == DataType::QAsymmS8)) + if (ShouldConstantTensorBeConverted(inputs[2], inputTensorInfo.GetDataType(), biasTensorInfo.GetDataType())) { m_ConstantsToDequantize.emplace_back(inputs[2]->buffer); } @@ -4925,11 +4899,22 @@ TfLiteParserImpl::CreateConstTensorNonPermuted(TensorRawPtr tensorPtr, // Make sure isConstant flag is set. tensorInfo.SetConstant(); - if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32) + if (inputDataType == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32) { - TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true); - std::unique_ptr data = AsFloatArray(bufferPtr, tensorInfo); - return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data)); + try + { + TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true); + std::unique_ptr data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo); + return std::make_pair(ConstTensor(constTensorInfo, data.get()), std::move(data)); + } + catch (armnn::InvalidArgumentException) + { + throw ParseException( + fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}", + GetDataTypeName(DataType::Float32), + GetDataTypeName(tensorInfo.GetDataType()), + CHECK_LOCATION().AsString())); + } } else { @@ -4950,9 +4935,20 @@ TfLiteParserImpl::CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo if (inputTensorInfo.GetDataType() == DataType::Float32 && tensorInfo.GetDataType() != DataType::Float32) { - TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true); - std::unique_ptr data = AsFloatArray(bufferPtr, tensorInfo); - return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data)); + try + { + TensorInfo constTensorInfo(tensorInfo.GetShape(), DataType::Float32, 0.0f, 0, true); + std::unique_ptr data = armnnUtils::ToFloatArray(bufferPtr->data, tensorInfo); + return std::make_pair(new ConstTensor(constTensorInfo, data.get()), std::move(data)); + } + catch (armnn::InvalidArgumentException) + { + throw ParseException( + fmt::format("Unsupported input/weights combination: Input {} not supported with Weights {}", + GetDataTypeName(DataType::Float32), + GetDataTypeName(tensorInfo.GetDataType()), + CHECK_LOCATION().AsString())); + } } else { diff --git a/src/armnnTfLiteParser/TfLiteParser.hpp b/src/armnnTfLiteParser/TfLiteParser.hpp index f8ddc55649..7eb6c48501 100644 --- a/src/armnnTfLiteParser/TfLiteParser.hpp +++ b/src/armnnTfLiteParser/TfLiteParser.hpp @@ -242,7 +242,13 @@ private: }; bool ShouldConstantTensorBeCreated(unsigned int tensorIndex); + bool IsConstTensor(TensorRawPtr tensorPtr); + + bool ShouldConstantTensorBeConverted(TfLiteParserImpl::TensorRawPtr tensorPtr, + armnn::DataType inputDataType, + armnn::DataType filterDataType); + armnn::ConstTensor CreateConstTensorNonPermuted(TensorRawPtr tensorPtr, armnn::TensorInfo& tensorInfo); @@ -250,6 +256,7 @@ private: CreateConstTensorPermuted(TensorRawPtr tensorPtr, armnn::TensorInfo& tensorInfo, armnn::Optional permutationVector); + std::pair> CreateConstTensorNonPermuted(TensorRawPtr tensorPtr, armnn::TensorInfo& tensorInfo, @@ -261,6 +268,7 @@ private: TfLiteParserImpl::TensorRawPtr tensorPtr, armnn::TensorInfo& tensorInfo, armnn::Optional permutationVector); + std::pair> CreateConstTensorPtr(TensorRawPtr tensorPtr, armnn::TensorInfo& inputTensorInfo); diff --git a/src/armnnTfLiteParser/test/Conv2D.cpp b/src/armnnTfLiteParser/test/Conv2D.cpp index 45c4a43519..334c102344 100644 --- a/src/armnnTfLiteParser/test/Conv2D.cpp +++ b/src/armnnTfLiteParser/test/Conv2D.cpp @@ -673,7 +673,7 @@ struct Conv2FloatWithInt8WeightsAndBiasesFixture : Conv2DWithBiasesFixture "[ 1, 2, 2, 1 ]", // filterShape "[ 2,1, 0,6 ]", // filterData "[ 1 ]", // biasShape - "[ 10, 0, 0, 0 ]", // biasData + "[ 10 ]", // biasData "1", // stride w and h "NONE", // activation "1.0", // filterScale diff --git a/src/armnnUtils/TensorUtils.cpp b/src/armnnUtils/TensorUtils.cpp index d77f5d74c3..9e3d719211 100644 --- a/src/armnnUtils/TensorUtils.cpp +++ b/src/armnnUtils/TensorUtils.cpp @@ -128,12 +128,11 @@ TensorShape ExpandDims(const TensorShape& tensorShape, int axis) } outputShape.insert(outputShape.begin() + axis, 1); - return TensorShape(outputDim, outputShape.data()); + return { outputDim, outputShape.data() }; } std::vector SqueezeDims(const TensorShape& tensorShape) { - unsigned int outputDimSize = 0; std::vector squeezedDims; for (unsigned int i = 0; i < tensorShape.GetNumDimensions(); ++i) @@ -141,7 +140,6 @@ std::vector SqueezeDims(const TensorShape& tensorShape) if (tensorShape[i] != 1) { squeezedDims.push_back(tensorShape[i]); - ++outputDimSize; } } return squeezedDims; @@ -201,4 +199,91 @@ std::pair> GetPerAxisParams(const armnn::Tensor return { axisFactor, scales }; } +template +void CheckSizes(const std::vector& data, const armnn::TensorInfo& tensorInfo, unsigned int size = 1) +{ + if (data.size() / size != tensorInfo.GetNumElements()) + { + throw InvalidArgumentException( + fmt::format("The data does not contain the expected number of elements {} != {}. {}", + data.size(), tensorInfo.GetNumElements(), CHECK_LOCATION().AsString())); + } +} + +template +std::unique_ptr ToFloatArray(const std::vector& data, const armnn::TensorInfo& tensorInfo) +{ + CheckSizes(data, tensorInfo); + + std::unique_ptr returnBuffer(new float[tensorInfo.GetNumElements()]); + + if (tensorInfo.HasPerAxisQuantization()) + { + unsigned int axis = tensorInfo.GetQuantizationDim().value(); + auto axisDimensionality = tensorInfo.GetShape()[axis]; + auto axisFactor = armnnUtils::GetNumElementsAfter(tensorInfo.GetShape(), axis); + + for (unsigned int i = 0; i < tensorInfo.GetNumElements(); ++i) + { + unsigned int axisIndex; + + if (i < axisFactor) + { + axisIndex = 0; + } + else + { + axisIndex = (i / axisFactor) % axisDimensionality; + } + returnBuffer[i] = Dequantize(data[i], + tensorInfo.GetQuantizationScales()[axisIndex], + tensorInfo.GetQuantizationOffset()); + } + } + else + { + for (unsigned int i = 0; i < tensorInfo.GetNumElements(); ++i) + { + returnBuffer[i] = Dequantize(data[i], + tensorInfo.GetQuantizationScale(), + tensorInfo.GetQuantizationOffset()); + } + } + return returnBuffer; +} + +std::unique_ptr ToFloatArray(const std::vector& data, const armnn::TensorInfo& tensorInfo) +{ + if (tensorInfo.GetDataType() == DataType::QAsymmS8 || tensorInfo.GetDataType() == DataType::QSymmS8) + { + CheckSizes(data, tensorInfo); + std::vector buffer(tensorInfo.GetNumElements()); + ::memcpy(buffer.data(), data.data(), data.size()); + return ToFloatArray(buffer, tensorInfo); + } + else if (tensorInfo.GetDataType() == DataType::QAsymmU8) + { + CheckSizes(data, tensorInfo); + return ToFloatArray(data, tensorInfo); + } + else if (tensorInfo.GetDataType() == DataType::Signed32) + { + CheckSizes(data, tensorInfo, 4); + std::vector buffer(tensorInfo.GetNumElements()); + ::memcpy(buffer.data(), data.data(), data.size()); + return ToFloatArray(buffer, tensorInfo); + } + else if (tensorInfo.GetDataType() == DataType::Signed64) + { + CheckSizes(data, tensorInfo, 8); + std::vector buffer(tensorInfo.GetNumElements()); + ::memcpy(buffer.data(), data.data(), data.size()); + return ToFloatArray(buffer, tensorInfo); + } + throw InvalidArgumentException( + fmt::format("Unsupported datatype {}. {}", + GetDataTypeName(tensorInfo.GetDataType()), + CHECK_LOCATION().AsString())); +} + } // namespace armnnUtils diff --git a/src/armnnUtils/test/TensorUtilsTest.cpp b/src/armnnUtils/test/TensorUtilsTest.cpp index 6d5f719eb1..16349c554e 100644 --- a/src/armnnUtils/test/TensorUtilsTest.cpp +++ b/src/armnnUtils/test/TensorUtilsTest.cpp @@ -1,5 +1,5 @@ // -// Copyright © 2019 Arm Ltd. All rights reserved. +// Copyright © 2019,2021-2022 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -134,4 +134,175 @@ TEST_CASE("ExpandDimsInvalidNegativeAxisTest") CHECK_THROWS_AS(ExpandDims(inputShape, -5), armnn::InvalidArgumentException); } +TEST_CASE("ToFloatArrayInvalidDataType") +{ + armnn::TensorInfo info({ 2, 3, 4 }, armnn::DataType::BFloat16); + std::vector data {1,2,3,4,5,6,7,8,9,10}; + + // Invalid argument + CHECK_THROWS_AS(ToFloatArray(data, info), armnn::InvalidArgumentException); +} + +TEST_CASE("ToFloatArrayQSymmS8PerAxis") +{ + std::vector quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f }; + unsigned int quantizationDim = 1; + + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QSymmS8, quantizationScales, quantizationDim); + std::vector data { 100, 120, 130, 140, 150, 160, 170 ,180, 190, 200, 210, 220 }; + float expected[] { 10.0f, 24.0f, -37.8f, -46.4f, -10.6f, -19.2f, -25.8f, -30.4f, -6.6f, -11.2f, -13.8f, -14.4f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} + +TEST_CASE("ToFloatArrayQSymmS8") +{ + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QSymmS8, 0.1f); + std::vector data { 100, 120, 130, 140, 150, 160, 170 ,180, 190, 200, 210, 220 }; + float expected[] { 10.0f, 12.0f, -12.6f, -11.6f, -10.6f, -9.6f, -8.6f, -7.6f, -6.6f, -5.6f, -4.6f, -3.6f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} + +TEST_CASE("ToFloatArrayQAsymmS8PerAxis") +{ + std::vector quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f }; + unsigned int quantizationDim = 1; + + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QAsymmS8, quantizationScales, quantizationDim); + std::vector data { 100, 120, 130, 140, 150, 160, 170 ,180, 190, 200, 210, 220 }; + float expected[] { 10.0f, 24.0f, -37.8f, -46.4f, -10.6f, -19.2f, -25.8f, -30.4f, -6.6f, -11.2f, -13.8f, -14.4f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} + +TEST_CASE("ToFloatArrayQAsymmS8") +{ + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QAsymmS8, 0.1f); + std::vector data { 100, 120, 130, 140, 150, 160, 170 ,180, 190, 200, 210, 220 }; + float expected[] { 10.0f, 12.0f, -12.6f, -11.6f, -10.6f, -9.6f, -8.6f, -7.6f, -6.6f, -5.6f, -4.6f, -3.6f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} + +TEST_CASE("ToFloatArrayQASymmU8PerAxis") +{ + std::vector quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f }; + unsigned int quantizationDim = 1; + + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QAsymmU8, quantizationScales, quantizationDim); + std::vector data { 100, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220 }; + float expected[] { 10.0f, 24.0f, 39.0f, 56.0f, 15.0f, 32.0f, 51.0f, 72.0f, 19.0f, 40.0f, 63.0f, 88.0f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} + +TEST_CASE("ToFloatArrayQAsymmU8") +{ + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::QAsymmU8, 0.1f); + std::vector data { 100, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220 }; + float expected[] { 10.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} + +TEST_CASE("ToFloatArraySigned32PerAxis") +{ + std::vector quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f }; + unsigned int quantizationDim = 1; + + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::Signed32, quantizationScales, quantizationDim); + std::vector data { 100, 0, 0, 0, 120, 0, 0, 0, 130, 0, 0, 0, 140, 0, 0, 0, 150, 0, 0, 0, 160, 0, 0, 0, + 170, 0, 0, 0, 180, 0, 0, 0, 190, 0, 0, 0, 200, 0, 0, 0, 210, 0, 0, 0, 220, 0, 0, 0 }; + float expected[] { 10.0f, 24.0f, 39.0f, 56.0f, 15.0f, 32.0f, 51.0f, 72.0f, 19.0f, 40.0f, 63.0f, 88.0f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} + +TEST_CASE("ToFloatArraySigned32") +{ + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::Signed32, 0.1f); + std::vector data { 100, 0, 0, 0, 120, 0, 0, 0, 130, 0, 0, 0, 140, 0, 0, 0, 150, 0, 0, 0, 160, 0, 0, 0, + 170, 0, 0, 0, 180, 0, 0, 0, 190, 0, 0, 0, 200, 0, 0, 0, 210, 0, 0, 0, 220, 0, 0, 0 }; + float expected[] { 10.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} + +TEST_CASE("ToFloatArraySigned64PerAxis") +{ + std::vector quantizationScales { 0.1f, 0.2f, 0.3f, 0.4f }; + unsigned int quantizationDim = 1; + + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::Signed64, quantizationScales, quantizationDim); + std::vector data { 100, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 0, + 140, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, + 170, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, + 200, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0 }; + float expected[] { 10.0f, 24.0f, 39.0f, 56.0f, 15.0f, 32.0f, 51.0f, 72.0f, 19.0f, 40.0f, 63.0f, 88.0f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} + +TEST_CASE("ToFloatArraySigned64") +{ + armnn::TensorInfo info({ 3, 4 }, armnn::DataType::Signed64, 0.1f); + std::vector data { 100, 0, 0, 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 130, 0, 0, 0, 0, 0, 0, 0, + 140, 0, 0, 0, 0, 0, 0, 0, 150, 0, 0, 0, 0, 0, 0, 0, 160, 0, 0, 0, 0, 0, 0, 0, + 170, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, + 200, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 0 }; + float expected[] { 10.0f, 12.0f, 13.0f, 14.0f, 15.0f, 16.0, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f }; + + std::unique_ptr result = ToFloatArray(data, info); + + for (uint i = 0; i < info.GetNumElements(); ++i) + { + CHECK_EQ(result[i], doctest::Approx(expected[i])); + } +} } -- cgit v1.2.1