diff options
Diffstat (limited to 'reference_model')
-rw-r--r-- | reference_model/src/generate/generate_utils.cc | 7 | ||||
-rw-r--r-- | reference_model/src/verify/verify_ulp.cc | 37 | ||||
-rw-r--r-- | reference_model/src/verify/verify_utils.cc | 26 | ||||
-rw-r--r-- | reference_model/src/verify/verify_utils.h | 6 | ||||
-rw-r--r-- | reference_model/test/verify_tests.cpp | 6 |
5 files changed, 70 insertions, 12 deletions
diff --git a/reference_model/src/generate/generate_utils.cc b/reference_model/src/generate/generate_utils.cc index c889f7b..fd42f21 100644 --- a/reference_model/src/generate/generate_utils.cc +++ b/reference_model/src/generate/generate_utils.cc @@ -38,16 +38,23 @@ NLOHMANN_JSON_SERIALIZE_ENUM(DType, NLOHMANN_JSON_SERIALIZE_ENUM(Op, { { Op::Op_UNKNOWN, "UNKNOWN" }, + { Op::Op_ABS, "ABS" }, { Op::Op_ADD, "ADD" }, { Op::Op_ARGMAX, "ARGMAX" }, + { Op::Op_CEIL, "CEIL" }, { Op::Op_CONV2D, "CONV2D" }, + { Op::Op_FLOOR, "FLOOR" }, { Op::Op_FULLY_CONNECTED, "FULLY_CONNECTED" }, + { Op::Op_IDENTITY, "IDENTITY" }, { Op::Op_MATMUL, "MATMUL" }, { Op::Op_MAXIMUM, "MAXIMUM" }, { Op::Op_MAX_POOL2D, "MAX_POOL2D" }, { Op::Op_MINIMUM, "MINIMUM" }, { Op::Op_MUL, "MUL" }, + { Op::Op_NEGATE, "NEGATE" }, { Op::Op_PAD, "PAD" }, + { Op::Op_RECIPROCAL, "RECIPROCAL" }, + { Op::Op_RSQRT, "RSQRT" }, { Op::Op_REDUCE_MAX, "REDUCE_MAX" }, { Op::Op_REDUCE_MIN, "REDUCE_MIN" }, { Op::Op_REDUCE_SUM, "REDUCE_SUM" }, diff --git a/reference_model/src/verify/verify_ulp.cc b/reference_model/src/verify/verify_ulp.cc index 8c27191..2af0012 100644 --- a/reference_model/src/verify/verify_ulp.cc +++ b/reference_model/src/verify/verify_ulp.cc @@ -16,6 +16,7 @@ #include <limits> #include <memory> #include <type_traits> +#include <utility> #include "verifiers.h" @@ -36,9 +37,14 @@ bool tosaCheckULP(double referenceValue, float testValue, double ulpNum) // Start by sanitizing the input. - // The concept of ULP isn't defined for NaN's + // Both must be NaNs to be correct if (std::isnan(referenceValue) || std::isnan(testValue)) { + if (std::isnan(referenceValue) && std::isnan(testValue)) + { + return true; + } + WARNING("[Verfier][ULP] Non-matching NaN values - ref (%10f) versus test (%10f).", referenceValue, testValue); return false; } @@ -112,8 +118,8 @@ bool tosaCheckULP(double referenceValue, float testValue, double ulpNum) 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); + WARNING("[Verfier][ULP] value (%10.10f) is not in ULP %g range (%10.10f <= ref (%10.10f) <= %10.10f).", + testValue64, ulpNum, referenceMin, referenceValue, referenceMax); } return withinUlp; } @@ -126,8 +132,8 @@ bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTens TOSA_REF_REQUIRE(implementationTensor != nullptr, "[ULP] Implementation tensor is missing"); // Get number of elements - const auto elementCount = - numElements(std::vector<int32_t>(referenceTensor->shape, referenceTensor->shape + referenceTensor->num_dims)); + const std::vector<int32_t> refShape(referenceTensor->shape, referenceTensor->shape + referenceTensor->num_dims); + const auto elementCount = numElements(refShape); TOSA_REF_REQUIRE(elementCount > 0, "[ULP] Invalid shape for reference tensor"); const double ulp = ulpInfo.ulp; @@ -138,10 +144,23 @@ bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTens TOSA_REF_REQUIRE(refData != nullptr, "[ULP] Missing data for reference"); const auto* impData = reinterpret_cast<const float*>(implementationTensor->data); TOSA_REF_REQUIRE(impData != nullptr, "[ULP] Missing data for implementation"); - return std::equal(refData, std::next(refData, elementCount), impData, std::next(impData, elementCount), - [ulp](const auto& referenceValue, const auto& implementationValue) { - return tosaCheckULP(referenceValue, implementationValue, ulp); - }); + const auto* refDataEnd = std::next(refData, elementCount); + // Use mismatch to get the location of the first unequal value + auto pair = std::mismatch(refData, refDataEnd, impData, std::next(impData, elementCount), + [ulp](const auto& referenceValue, const auto& implementationValue) { + return tosaCheckULP(referenceValue, implementationValue, ulp); + }); + if (std::get<0>(pair) == refDataEnd) + { + // No mismatch found + return true; + } + else + { + auto pos = indexToPosition(std::get<0>(pair) - refData, refShape); + WARNING("[Verfier][ULP] Location %s", positionToString(pos).c_str()); + return false; + } } default: WARNING("[Verifier][ULP] Data-type not supported."); diff --git a/reference_model/src/verify/verify_utils.cc b/reference_model/src/verify/verify_utils.cc index 99cb0c1..9b20fb2 100644 --- a/reference_model/src/verify/verify_utils.cc +++ b/reference_model/src/verify/verify_utils.cc @@ -121,6 +121,32 @@ int64_t numElements(const std::vector<int32_t>& shape) return std::accumulate(std::begin(shape), std::end(shape), 1, std::multiplies<int64_t>()); } +std::vector<int32_t> indexToPosition(int64_t index, const std::vector<int32_t>& shape) +{ + std::vector<int32_t> pos; + for (auto d = shape.end() - 1; d >= shape.begin(); --d) + { + pos.insert(pos.begin(), index % *d); + index /= *d; + } + return pos; +} + +std::string positionToString(const std::vector<int32_t>& pos) +{ + std::string str = "["; + for (auto d = pos.begin(); d < pos.end(); ++d) + { + str.append(std::to_string(*d)); + if (pos.end() - d > 1) + { + str.append(","); + } + } + str.append("]"); + return str; +} + DType mapToDType(tosa_datatype_t dataType) { static std::map<tosa_datatype_t, DType> typeMap = { diff --git a/reference_model/src/verify/verify_utils.h b/reference_model/src/verify/verify_utils.h index 15d7ba5..24d65b0 100644 --- a/reference_model/src/verify/verify_utils.h +++ b/reference_model/src/verify/verify_utils.h @@ -91,6 +91,12 @@ std::optional<VerifyConfig> parseVerifyConfig(const char* tensorName, const char /// \brief Extract number of total elements int64_t numElements(const std::vector<int32_t>& shape); +/// \brief Convert a flat index to a shape position +std::vector<int32_t> indexToPosition(int64_t index, const std::vector<int32_t>& shape); + +/// \brief A string representing the shape or position +std::string positionToString(const std::vector<int32_t>& pos); + /// \brief Map API data-type to DType DType mapToDType(tosa_datatype_t dataType); diff --git a/reference_model/test/verify_tests.cpp b/reference_model/test/verify_tests.cpp index e7d6c4e..31e27c0 100644 --- a/reference_model/test/verify_tests.cpp +++ b/reference_model/test/verify_tests.cpp @@ -392,7 +392,7 @@ TEST_CASE("positive - ulp") const auto elementCount = std::accumulate(std::begin(shape), std::end(shape), 1, std::multiplies<>()); // Generate some random floats using the full range of fp32. - auto data_fp32 = generateRandomTensorData<float>(elementCount, false); + auto data_fp32 = generateRandomTensorData<float>(elementCount, true); std::vector<double> data_fp64(data_fp32.begin(), data_fp32.end()); SUBCASE("same") @@ -400,7 +400,7 @@ TEST_CASE("positive - ulp") // Generate some data that meets the ULP requirements of the result. auto otherData_fp32 = data_fp32; std::for_each(std::begin(otherData_fp32), std::end(otherData_fp32), [](auto& value) { - if (std::abs(value) != 0.0 && !std::isinf(value)) + if (std::abs(value) != 0.0 && !std::isinf(value) && !std::isnan(value)) value = increment(value, 5); }); const auto referenceTensor = @@ -415,7 +415,7 @@ TEST_CASE("positive - ulp") // Generate some data that exceeds a specified number of ULP for each value in the tensor. auto otherData_fp32 = data_fp32; std::for_each(std::begin(otherData_fp32), std::end(otherData_fp32), [](auto& value) { - if (std::abs(value) != 0.0 && !std::isinf(value)) + if (std::abs(value) != 0.0 && !std::isinf(value) && !std::isnan(value)) value = increment(value, 6); }); |