// // Copyright © 2017 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include constexpr float g_FloatCloseToZeroTolerance = 1.0e-6f; template struct SelectiveComparer { static bool Compare(T a, T b) { return (std::max(a, b) - std::min(a, b)) <= 1; } }; template struct SelectiveComparer { 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%. boost::math::fpc::close_at_tolerance comparer(boost::math::fpc::percent_tolerance(1.0f)); return comparer(a, b); } }; template bool SelectiveCompare(T a, T b) { return SelectiveComparer()>::Compare(a, b); }; template boost::test_tools::predicate_result CompareTensors(const boost::multi_array& a, const boost::multi_array& b) { // Checks they are same shape. for (unsigned int i=0; i indices; for (unsigned int i = 0; i < n; i++) { indices[i] = 0; } std::stringstream errorString; int numFailedElements = 0; constexpr int maxReportedDifferences = 3; while (true) { bool comparison = SelectiveCompare(a(indices), b(indices)); if (!comparison) { ++numFailedElements; if (numFailedElements <= maxReportedDifferences) { if (numFailedElements >= 2) { errorString << ", "; } errorString << "["; for (unsigned int i = 0; i < n; ++i) { errorString << indices[i]; if (i != n - 1) { errorString << ","; } } errorString << "]"; errorString << " (" << +a(indices) << " != " << +b(indices) << ")"; } } ++indices[n - 1]; for (unsigned int i=n-1; i>0; i--) { if (indices[i] == a.shape()[i]) { indices[i] = 0; ++indices[i - 1]; } } if (indices[0] == a.shape()[0]) { break; } } boost::test_tools::predicate_result comparisonResult(true); if (numFailedElements > 0) { comparisonResult = false; comparisonResult.message() << numFailedElements << " different values at: "; if (numFailedElements > maxReportedDifferences) { errorString << ", ... (and " << (numFailedElements - maxReportedDifferences) << " other differences)"; } comparisonResult.message() << errorString.str(); } return comparisonResult; } // Creates a boost::multi_array with the shape defined by the given TensorInfo. template boost::multi_array MakeTensor(const armnn::TensorInfo& tensorInfo) { std::array shape; for (unsigned int i = 0; i < n; i++) { shape[i] = tensorInfo.GetShape()[i]; } return boost::multi_array(shape); } // Creates a boost::multi_array with the shape defined by the given TensorInfo and contents defined by the given vector. template boost::multi_array MakeTensor(const armnn::TensorInfo& tensorInfo, const std::vector& flat) { BOOST_ASSERT_MSG(flat.size() == tensorInfo.GetNumElements(), "Wrong number of components supplied to tensor"); std::array shape; for (unsigned int i = 0; i < n; i++) { shape[i] = tensorInfo.GetShape()[i]; } boost::const_multi_array_ref arrayRef(&flat[0], shape); return boost::multi_array(arrayRef); } template boost::multi_array MakeRandomTensor(const armnn::TensorInfo& tensorInfo, unsigned int seed, float min = -10.0f, float max = 10.0f) { boost::random::mt19937 gen(seed); boost::random::uniform_real_distribution dist(min, max); std::vector init(tensorInfo.GetNumElements()); for (unsigned int i = 0; i < init.size(); i++) { init[i] = dist(gen); } float qScale = tensorInfo.GetQuantizationScale(); int32_t qOffset = tensorInfo.GetQuantizationOffset(); return MakeTensor(tensorInfo, QuantizedVector(qScale, qOffset, init)); }