From a4d907e8686791dd84ed987d0d79325c4d908b73 Mon Sep 17 00:00:00 2001 From: Jeremy Johnson Date: Thu, 26 Oct 2023 13:53:14 +0100 Subject: Main compliance testing support for MUL Update verify ULP mode to allow fractions (e.g. 0.5). Update pseudo generator to accept ranges. Fix up pseudo random distribution based on ranges. Change-Id: I9168c5f7d37722678c0f1f9e906953c8cec367b1 Signed-off-by: Jeremy Johnson --- reference_model/src/verify/verifiers.h | 2 +- reference_model/src/verify/verify_dot_product.cc | 1 - reference_model/src/verify/verify_entry.cc | 2 +- reference_model/src/verify/verify_ulp.cc | 47 ++++++++++++------------ reference_model/src/verify/verify_utils.cc | 20 +++++++++- reference_model/src/verify/verify_utils.h | 10 +++-- 6 files changed, 49 insertions(+), 33 deletions(-) (limited to 'reference_model/src/verify') diff --git a/reference_model/src/verify/verifiers.h b/reference_model/src/verify/verifiers.h index dd97122..fcfb3b3 100644 --- a/reference_model/src/verify/verifiers.h +++ b/reference_model/src/verify/verifiers.h @@ -58,7 +58,7 @@ bool verifyReduceProduct(const CTensor* referenceTensor, const CTensor* implemen /// \param ulp The ULP tolerence for the comparison of the two tensors /// /// \return True if compliant else false -bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTensor, uint64_t ulp); +bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTensor, const UlpInfo& ulpInfo); }; // namespace TosaReference diff --git a/reference_model/src/verify/verify_dot_product.cc b/reference_model/src/verify/verify_dot_product.cc index 233c072..863640f 100644 --- a/reference_model/src/verify/verify_dot_product.cc +++ b/reference_model/src/verify/verify_dot_product.cc @@ -14,7 +14,6 @@ #include "func_debug.h" #include "verifiers.h" -#include "verify_utils.h" #include #include diff --git a/reference_model/src/verify/verify_entry.cc b/reference_model/src/verify/verify_entry.cc index 67eb7df..4da3bde 100644 --- a/reference_model/src/verify/verify_entry.cc +++ b/reference_model/src/verify/verify_entry.cc @@ -38,7 +38,7 @@ bool verify(const CTensor* ref, const CTensor* refBnd, const CTensor* imp, const return verifyReduceProduct(ref, imp, cfg.reduceProductInfo.m, cfg.reduceProductInfo.n); } case VerifyMode::Ulp: { - return verifyULP(ref, imp, cfg.ulpInfo.ulp); + return verifyULP(ref, imp, cfg.ulpInfo); } default: { WARNING("[Verifier] Unsupported verification mode."); diff --git a/reference_model/src/verify/verify_ulp.cc b/reference_model/src/verify/verify_ulp.cc index 486c0ff..8c27191 100644 --- a/reference_model/src/verify/verify_ulp.cc +++ b/reference_model/src/verify/verify_ulp.cc @@ -31,7 +31,7 @@ static_assert(std::numeric_limits::is_iec559, "TOSA Reference Model has not been built with standard IEE574 64-bit float support; ULP based " "verifcation is invalid"); -bool tosaCheckULP(float testValue, double referenceValue, int64_t ulpCount) +bool tosaCheckULP(double referenceValue, float testValue, double ulpNum) { // Start by sanitizing the input. @@ -71,57 +71,55 @@ bool tosaCheckULP(float testValue, double referenceValue, int64_t ulpCount) else { // Find the exponent of the reference value. - int referenceExponent; - std::frexp(referenceValue, &referenceExponent); + int32_t referenceExponent = ilog2(referenceValue); // Work out the values magnitude - by raising 2 to the power of the // exponent and taking the normalized minimum for denormal values - const double referencePower2 = - std::max(std::ldexp(1.0, referenceExponent), static_cast(std::numeric_limits::min())); + const double referencePower2 = std::max(exp2(referenceExponent), AccPrecision::normal_min); // Get the value of changing the last bit - by shifting the least significant bit to this magnitude // i.e. the ULP. - double ulpValue = referencePower2 * std::ldexp(1.0, -23); - - // It is possible that within one ULP we cross a boundary where we need to change the exponent, - // if this happens we will take the ULP for the larger exponent. - if (referenceValue + ulpValue > 2 * referencePower2) - { - ulpValue = 2 * ulpValue; - } + double ulpValue = referencePower2 * exp2(-AccPrecision::normal_frac); // Scale by the number of ULPs requested by the user. - referenceMax = referenceValue + ulpValue * ulpCount; - referenceMin = referenceValue - ulpValue * ulpCount; + referenceMax = referenceValue + ulpValue * ulpNum; + referenceMin = referenceValue - ulpValue * ulpNum; // Handle the overflow cases. - if (referenceMax > std::numeric_limits::max()) + if (referenceMax > AccPrecision::normal_max) { referenceMax = std::numeric_limits::infinity(); } - if (referenceMin > std::numeric_limits::max()) + if (referenceMin > AccPrecision::normal_max) { referenceMin = std::numeric_limits::infinity(); } // And the underflow cases. - if (referenceMax < std::numeric_limits::min()) + if (referenceMax < AccPrecision::normal_min) { - referenceMax = std::numeric_limits::min(); + referenceMax = AccPrecision::normal_min; } - if (referenceMin < std::numeric_limits::min()) + if (referenceMin < AccPrecision::normal_min) { - referenceMin = 0; + referenceMin = 0.0; } } // And finally... Do the comparison. - return static_cast(testValue) >= referenceMin && static_cast(testValue) <= referenceMax; + double testValue64 = static_cast(testValue); + bool withinUlp = testValue64 >= referenceMin && testValue64 <= referenceMax; + if (!withinUlp) + { + WARNING("[Verfier][ULP] value (%10f) is not in ULP %g range (%10f <= ref (%10f) <= %10f).", testValue64, ulpNum, + referenceMin, referenceValue, referenceMax); + } + return withinUlp; } } // namespace -bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTensor, uint64_t ulp) +bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTensor, const UlpInfo& ulpInfo) { // Validate that tensors are provided TOSA_REF_REQUIRE(referenceTensor != nullptr, "[ULP] Reference tensor is missing"); @@ -132,10 +130,11 @@ bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTens numElements(std::vector(referenceTensor->shape, referenceTensor->shape + referenceTensor->num_dims)); TOSA_REF_REQUIRE(elementCount > 0, "[ULP] Invalid shape for reference tensor"); + const double ulp = ulpInfo.ulp; switch (implementationTensor->data_type) { case tosa_datatype_fp32_t: { - const auto* refData = reinterpret_cast(referenceTensor->data); + const auto* refData = reinterpret_cast(referenceTensor->data); TOSA_REF_REQUIRE(refData != nullptr, "[ULP] Missing data for reference"); const auto* impData = reinterpret_cast(implementationTensor->data); TOSA_REF_REQUIRE(impData != nullptr, "[ULP] Missing data for implementation"); diff --git a/reference_model/src/verify/verify_utils.cc b/reference_model/src/verify/verify_utils.cc index 43ecbe7..99cb0c1 100644 --- a/reference_model/src/verify/verify_utils.cc +++ b/reference_model/src/verify/verify_utils.cc @@ -50,7 +50,6 @@ NLOHMANN_JSON_SERIALIZE_ENUM(VerifyMode, { VerifyMode::DotProduct, "DOT_PRODUCT" }, { VerifyMode::ReduceProduct, "REDUCE_PRODUCT" }, { VerifyMode::FpSpecial, "FP_SPECIAL" }, - { VerifyMode::Round, "ROUND" }, }) void from_json(const nlohmann::json& j, UlpInfo& ulpInfo) @@ -144,7 +143,24 @@ DType mapToDType(tosa_datatype_t dataType) // Like const_exp2 but for use during runtime double exp2(int32_t n) { - TOSA_REF_REQUIRE(-1022 <= n && n <= 1023, " Invalid exponent value (%d)", n); + TOSA_REF_REQUIRE(-1022 <= n && n <= 1023, " Invalid exponent value (%d) in exp2", n); return const_exp2(n); } + +int32_t ilog2(double v) +{ + TOSA_REF_REQUIRE(0.0 < v && v < std::numeric_limits::infinity(), " Value out of range (%g) in ilog2", v); + int32_t n = 0; + while (v >= 2.0) + { + v = v / 2.0; + n++; + } + while (v < 1.0) + { + v = v * 2.0; + n--; + } + return n; +} } // namespace TosaReference diff --git a/reference_model/src/verify/verify_utils.h b/reference_model/src/verify/verify_utils.h index 486ce19..15d7ba5 100644 --- a/reference_model/src/verify/verify_utils.h +++ b/reference_model/src/verify/verify_utils.h @@ -44,8 +44,7 @@ enum class VerifyMode Ulp, DotProduct, ReduceProduct, - FpSpecial, - Round + FpSpecial }; /// \brief ULP verification meta-data @@ -53,7 +52,7 @@ struct UlpInfo { UlpInfo() = default; - uint64_t ulp; + double ulp; }; /// \brief Dot-product verification meta-data @@ -95,7 +94,7 @@ int64_t numElements(const std::vector& shape); /// \brief Map API data-type to DType DType mapToDType(tosa_datatype_t dataType); -/// \brief Raise a value by the power of N or -N +/// \brief Return 2 to the power of N or -N // For use during compile time - as no range check constexpr double const_exp2(int32_t n) { @@ -116,6 +115,9 @@ constexpr double const_exp2(int32_t n) /// \brief Same as const_exp2 but with runtime range check of N double exp2(int32_t n); +/// \brief Return the base-2 exponent of V +int32_t ilog2(double v); + /// \brief Accuracy precision information template struct AccPrecision; -- cgit v1.2.1