2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // See LICENSE file in the project root for full license information.
7 #include <armnn/TensorFwd.hpp>
8 #include <boost/test/unit_test.hpp>
9 #include <boost/multi_array.hpp>
13 #include <boost/assert.hpp>
14 #include <boost/test/tools/floating_point_comparison.hpp>
15 #include <boost/random/uniform_real_distribution.hpp>
16 #include <boost/random/mersenne_twister.hpp>
17 #include <boost/numeric/conversion/cast.hpp>
19 #include "armnn/Tensor.hpp"
21 #include "backends/test/QuantizeHelper.hpp"
25 constexpr float g_FloatCloseToZeroTolerance = 1.0e-6f;
27 template<typename T, bool isQuantized = true>
28 struct SelectiveComparer
30 static bool Compare(T a, T b)
32 return (std::max(a, b) - std::min(a, b)) <= 1;
38 struct SelectiveComparer<T, false>
40 static bool Compare(T a, T b)
42 // If a or b is zero, percent_tolerance does an exact match, so compare to a small, constant tolerance instead.
43 if (a == 0.0f || b == 0.0f)
45 return std::abs(a - b) <= g_FloatCloseToZeroTolerance;
47 // For unquantized floats we use a tolerance of 1%.
48 boost::math::fpc::close_at_tolerance<float> comparer(boost::math::fpc::percent_tolerance(1.0f));
49 return comparer(a, b);
54 bool SelectiveCompare(T a, T b)
56 return SelectiveComparer<T, armnn::IsQuantizedType<T>()>::Compare(a, b);
61 template <typename T, std::size_t n>
62 boost::test_tools::predicate_result CompareTensors(const boost::multi_array<T, n>& a,
63 const boost::multi_array<T, n>& b)
65 // Checks they are same shape.
66 for (unsigned int i=0; i<n; i++)
68 if (a.shape()[i] != b.shape()[i])
70 boost::test_tools::predicate_result res(false);
71 res.message() << "Different shapes ["
80 // Now compares element-wise.
82 // Fun iteration over n dimensions.
83 std::array<unsigned int, n> indices;
84 for (unsigned int i = 0; i < n; i++)
89 std::stringstream errorString;
90 int numFailedElements = 0;
91 constexpr int maxReportedDifferences = 3;
95 bool comparison = SelectiveCompare(a(indices), b(indices));
100 if (numFailedElements <= maxReportedDifferences)
102 if (numFailedElements >= 2)
107 for (unsigned int i = 0; i < n; ++i)
109 errorString << indices[i];
117 errorString << " (" << +a(indices) << " != " << +b(indices) << ")";
122 for (unsigned int i=n-1; i>0; i--)
124 if (indices[i] == a.shape()[i])
131 if (indices[0] == a.shape()[0])
137 boost::test_tools::predicate_result comparisonResult(true);
138 if (numFailedElements > 0)
140 comparisonResult = false;
141 comparisonResult.message() << numFailedElements << " different values at: ";
142 if (numFailedElements > maxReportedDifferences)
144 errorString << ", ... (and " << (numFailedElements - maxReportedDifferences) << " other differences)";
146 comparisonResult.message() << errorString.str();
149 return comparisonResult;
153 // Creates a boost::multi_array with the shape defined by the given TensorInfo.
154 template <typename T, std::size_t n>
155 boost::multi_array<T, n> MakeTensor(const armnn::TensorInfo& tensorInfo)
157 std::array<unsigned int, n> shape;
159 for (unsigned int i = 0; i < n; i++)
161 shape[i] = tensorInfo.GetShape()[i];
164 return boost::multi_array<T, n>(shape);
167 // Creates a boost::multi_array with the shape defined by the given TensorInfo and contents defined by the given vector.
168 template <typename T, std::size_t n>
169 boost::multi_array<T, n> MakeTensor(const armnn::TensorInfo& tensorInfo, const std::vector<T>& flat)
171 BOOST_ASSERT_MSG(flat.size() == tensorInfo.GetNumElements(), "Wrong number of components supplied to tensor");
173 std::array<unsigned int, n> shape;
175 for (unsigned int i = 0; i < n; i++)
177 shape[i] = tensorInfo.GetShape()[i];
180 boost::const_multi_array_ref<T, n> arrayRef(&flat[0], shape);
181 return boost::multi_array<T, n>(arrayRef);
184 template <typename T, std::size_t n>
185 boost::multi_array<T, n> MakeRandomTensor(const armnn::TensorInfo& tensorInfo,
190 boost::random::mt19937 gen(seed);
191 boost::random::uniform_real_distribution<float> dist(min, max);
193 std::vector<float> init(tensorInfo.GetNumElements());
194 for (unsigned int i = 0; i < init.size(); i++)
198 float qScale = tensorInfo.GetQuantizationScale();
199 int32_t qOffset = tensorInfo.GetQuantizationOffset();
200 return MakeTensor<T, n>(tensorInfo, QuantizedVector<T>(qScale, qOffset, init));