aboutsummaryrefslogtreecommitdiff
path: root/include/armnnTestUtils/TensorHelpers.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/armnnTestUtils/TensorHelpers.hpp')
-rw-r--r--include/armnnTestUtils/TensorHelpers.hpp235
1 files changed, 235 insertions, 0 deletions
diff --git a/include/armnnTestUtils/TensorHelpers.hpp b/include/armnnTestUtils/TensorHelpers.hpp
new file mode 100644
index 0000000000..ca17e621c3
--- /dev/null
+++ b/include/armnnTestUtils/TensorHelpers.hpp
@@ -0,0 +1,235 @@
+//
+// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#pragma once
+
+#include <armnnTestUtils/PredicateResult.hpp>
+
+#include <armnn/Tensor.hpp>
+#include <armnn/utility/Assert.hpp>
+#include <armnnUtils/FloatingPointComparison.hpp>
+
+#include <armnnUtils/QuantizeHelper.hpp>
+
+#include <doctest/doctest.h>
+
+#include <array>
+#include <cmath>
+#include <random>
+#include <vector>
+
+constexpr float g_FloatCloseToZeroTolerance = 1.0e-6f;
+
+template<typename T, bool isQuantized = true>
+struct SelectiveComparer
+{
+ static bool Compare(T a, T b)
+ {
+ return (std::max(a, b) - std::min(a, b)) <= 1;
+ }
+
+};
+
+template<typename T>
+struct SelectiveComparer<T, false>
+{
+ static bool Compare(T a, T b)
+ {
+ // If a or b is zero, percent_tolerance does an exact match, so compare to a small, constant tolerance instead.
+ if (a == 0.0f || b == 0.0f)
+ {
+ return std::abs(a - b) <= g_FloatCloseToZeroTolerance;
+ }
+
+ if (std::isinf(a) && a == b)
+ {
+ return true;
+ }
+
+ if (std::isnan(a) && std::isnan(b))
+ {
+ return true;
+ }
+
+ // For unquantized floats we use a tolerance of 1%.
+ return armnnUtils::within_percentage_tolerance(a, b);
+ }
+};
+
+template<typename T>
+bool SelectiveCompare(T a, T b)
+{
+ return SelectiveComparer<T, armnn::IsQuantizedType<T>()>::Compare(a, b);
+};
+
+template<typename T>
+bool SelectiveCompareBoolean(T a, T b)
+{
+ return (((a == 0) && (b == 0)) || ((a != 0) && (b != 0)));
+};
+
+template <typename T>
+armnn::PredicateResult CompareTensors(const std::vector<T>& actualData,
+ const std::vector<T>& expectedData,
+ const armnn::TensorShape& actualShape,
+ const armnn::TensorShape& expectedShape,
+ bool compareBoolean = false,
+ bool isDynamic = false)
+{
+ if (actualData.size() != expectedData.size())
+ {
+ armnn::PredicateResult res(false);
+ res.Message() << "Different data size ["
+ << actualData.size()
+ << "!="
+ << expectedData.size()
+ << "]";
+ return res;
+ }
+
+ if (actualShape.GetNumDimensions() != expectedShape.GetNumDimensions())
+ {
+ armnn::PredicateResult res(false);
+ res.Message() << "Different number of dimensions ["
+ << actualShape.GetNumDimensions()
+ << "!="
+ << expectedShape.GetNumDimensions()
+ << "]";
+ return res;
+ }
+
+ if (actualShape.GetNumElements() != expectedShape.GetNumElements())
+ {
+ armnn::PredicateResult res(false);
+ res.Message() << "Different number of elements ["
+ << actualShape.GetNumElements()
+ << "!="
+ << expectedShape.GetNumElements()
+ << "]";
+ return res;
+ }
+
+ unsigned int numberOfDimensions = actualShape.GetNumDimensions();
+
+ if (!isDynamic)
+ {
+ // Checks they are same shape.
+ for (unsigned int i = 0; i < numberOfDimensions; ++i)
+ {
+ if (actualShape[i] != expectedShape[i])
+ {
+ armnn::PredicateResult res(false);
+ res.Message() << "Different shapes ["
+ << actualShape[i]
+ << "!="
+ << expectedShape[i]
+ << "]";
+ return res;
+ }
+ }
+ }
+
+ // Fun iteration over n dimensions.
+ std::vector<unsigned int> indices;
+ for (unsigned int i = 0; i < numberOfDimensions; i++)
+ {
+ indices.emplace_back(0);
+ }
+
+ std::stringstream errorString;
+ int numFailedElements = 0;
+ constexpr int maxReportedDifferences = 3;
+ unsigned int index = 0;
+
+ // Compare data element by element.
+ while (true)
+ {
+ bool comparison;
+ // As true for uint8_t is non-zero (1-255) we must have a dedicated compare for Booleans.
+ if(compareBoolean)
+ {
+ comparison = SelectiveCompareBoolean(actualData[index], expectedData[index]);
+ }
+ else
+ {
+ comparison = SelectiveCompare(actualData[index], expectedData[index]);
+ }
+
+ if (!comparison)
+ {
+ ++numFailedElements;
+
+ if (numFailedElements <= maxReportedDifferences)
+ {
+ if (numFailedElements >= 2)
+ {
+ errorString << ", ";
+ }
+ errorString << "[";
+ for (unsigned int i = 0; i < numberOfDimensions; ++i)
+ {
+ errorString << indices[i];
+ if (i != numberOfDimensions - 1)
+ {
+ errorString << ",";
+ }
+ }
+ errorString << "]";
+
+ errorString << " (" << +actualData[index] << " != " << +expectedData[index] << ")";
+ }
+ }
+
+ ++indices[numberOfDimensions - 1];
+ for (unsigned int i=numberOfDimensions-1; i>0; i--)
+ {
+ if (indices[i] == actualShape[i])
+ {
+ indices[i] = 0;
+ ++indices[i - 1];
+ }
+ }
+ if (indices[0] == actualShape[0])
+ {
+ break;
+ }
+
+ index++;
+ }
+
+ armnn::PredicateResult comparisonResult(true);
+ if (numFailedElements > 0)
+ {
+ comparisonResult.SetResult(false);
+ comparisonResult.Message() << numFailedElements << " different values at: ";
+ if (numFailedElements > maxReportedDifferences)
+ {
+ errorString << ", ... (and " << (numFailedElements - maxReportedDifferences) << " other differences)";
+ }
+ comparisonResult.Message() << errorString.str();
+ }
+
+ return comparisonResult;
+}
+
+template <typename T>
+std::vector<T> MakeRandomTensor(const armnn::TensorInfo& tensorInfo,
+ unsigned int seed,
+ float min = -10.0f,
+ float max = 10.0f)
+{
+ std::mt19937 gen(seed);
+ std::uniform_real_distribution<float> dist(min, max);
+
+ std::vector<float> init(tensorInfo.GetNumElements());
+ for (unsigned int i = 0; i < init.size(); i++)
+ {
+ init[i] = dist(gen);
+ }
+
+ const float qScale = tensorInfo.GetQuantizationScale();
+ const int32_t qOffset = tensorInfo.GetQuantizationOffset();
+
+ return armnnUtils::QuantizedVector<T>(init, qScale, qOffset);
+}