diff options
Diffstat (limited to 'reference_model')
-rw-r--r-- | reference_model/CMakeLists.txt | 2 | ||||
-rw-r--r-- | reference_model/src/generate/generate_utils.cc | 2 | ||||
-rw-r--r-- | reference_model/src/main.cpp | 22 | ||||
-rw-r--r-- | reference_model/src/ops/ewise_binary.cc | 13 | ||||
-rw-r--r-- | reference_model/src/ops/ewise_unary.cc | 10 | ||||
-rw-r--r-- | reference_model/src/verify/verifiers.h | 9 | ||||
-rw-r--r-- | reference_model/src/verify/verify_abs_error.cc | 74 | ||||
-rw-r--r-- | reference_model/src/verify/verify_entry.cc | 3 | ||||
-rw-r--r-- | reference_model/src/verify/verify_ulp.cc | 94 | ||||
-rw-r--r-- | reference_model/src/verify/verify_utils.cc | 96 | ||||
-rw-r--r-- | reference_model/src/verify/verify_utils.h | 6 | ||||
-rw-r--r-- | reference_model/test/verify_tests.cpp | 61 |
12 files changed, 294 insertions, 98 deletions
diff --git a/reference_model/CMakeLists.txt b/reference_model/CMakeLists.txt index 24467c8..d36167a 100644 --- a/reference_model/CMakeLists.txt +++ b/reference_model/CMakeLists.txt @@ -76,6 +76,7 @@ set(CXX_SOURCE src/generate/generate_pseudo_random.cc src/generate/generate_entry.cc src/generate/generate_utils.cc + src/verify/verify_abs_error.cc src/verify/verify_dot_product.cc src/verify/verify_entry.cc src/verify/verify_exact.cc @@ -148,6 +149,7 @@ set_target_properties(tosa_reference_model_lib PROPERTIES PUBLIC_HEADER "${PUBLI # Build TOSA verification library add_library(tosa_reference_verify_lib SHARED + src/verify/verify_abs_error.cc src/verify/verify_dot_product.cc src/verify/verify_entry.cc src/verify/verify_exact.cc diff --git a/reference_model/src/generate/generate_utils.cc b/reference_model/src/generate/generate_utils.cc index fd42f21..3b00ba1 100644 --- a/reference_model/src/generate/generate_utils.cc +++ b/reference_model/src/generate/generate_utils.cc @@ -43,6 +43,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Op, { Op::Op_ARGMAX, "ARGMAX" }, { Op::Op_CEIL, "CEIL" }, { Op::Op_CONV2D, "CONV2D" }, + { Op::Op_EXP, "EXP" }, { Op::Op_FLOOR, "FLOOR" }, { Op::Op_FULLY_CONNECTED, "FULLY_CONNECTED" }, { Op::Op_IDENTITY, "IDENTITY" }, @@ -53,6 +54,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(Op, { Op::Op_MUL, "MUL" }, { Op::Op_NEGATE, "NEGATE" }, { Op::Op_PAD, "PAD" }, + { Op::Op_POW, "POW" }, { Op::Op_RECIPROCAL, "RECIPROCAL" }, { Op::Op_RSQRT, "RSQRT" }, { Op::Op_REDUCE_MAX, "REDUCE_MAX" }, diff --git a/reference_model/src/main.cpp b/reference_model/src/main.cpp index 6970bb1..80125ee 100644 --- a/reference_model/src/main.cpp +++ b/reference_model/src/main.cpp @@ -41,7 +41,7 @@ int writeVariableTensors(SubgraphTraverser& gt, json test_desc); int loadGraph(TosaSerializationHandler& tsh, json& test_desc); void parse_value(const std::string& text, tosa_level_t& value); const std::string getResultFilenamePrefix(); -bool isComplianceModeDotProduct(json& test_desc); +bool isComplianceAbsModeNeeded(json& test_desc); int main(int argc, char** argv) { @@ -90,10 +90,10 @@ int main(int argc, char** argv) GraphStatus status = GraphStatus::TOSA_VALID; - if (isComplianceModeDotProduct(test_desc) && !g_func_config.precise_mode) + if (isComplianceAbsModeNeeded(test_desc) && !g_func_config.precise_mode) { - // Warn about precise mode for dot product compliance - DEBUG_INFO(CONFIG, "DOT_PRODUCT compliance: NOTE - enable precise mode for compliance results") + // Warn about precise mode for dot product or abs error compliance + DEBUG_INFO(CONFIG, "DOT_PRODUCT/ABS_ERROR compliance: NOTE - enable precise mode for compliance results") } // max of 2 runs, second run only happens when precise_mode is set, to do an abs_mode run @@ -220,10 +220,10 @@ int main(int argc, char** argv) } if (run == 0 && status == GraphStatus::TOSA_VALID && g_func_config.precise_mode && g_func_config.eval && - isComplianceModeDotProduct(test_desc)) + isComplianceAbsModeNeeded(test_desc)) { - // first run result is valid and precise mode and eval is true: turn on abs_mode for second run - DEBUG_INFO(CONFIG, "DOT_PRODUCT compliance: Evaluating the graph again to produce bounds results") + // when first run result is valid and precise mode and eval is true: turn on abs_mode for second run + DEBUG_INFO(CONFIG, "DOT_PRODUCT/ABS_ERROR compliance: Evaluating the graph again to produce bounds results") g_func_config.abs_mode = true; continue; } @@ -361,17 +361,17 @@ const std::string getResultFilenamePrefix() return g_func_config.abs_mode ? "bounds_" : ""; } -// returns true iff test_desc contains a "meta" object containing a "compliance" +// returns true if test_desc contains a "meta" object containing a "compliance" // object which contains "tensors" and one of those has a "mode" whose value is -// "DOT_PRODUCT" -bool isComplianceModeDotProduct(json& test_desc) +// "DOT_PRODUCT" or "ABS_ERROR" +bool isComplianceAbsModeNeeded(json& test_desc) { if (test_desc.contains("meta") && test_desc["meta"].contains("compliance") && test_desc["meta"]["compliance"].contains("tensors")) { for (auto t : test_desc["meta"]["compliance"]["tensors"]) { - if (t.contains("mode") && t["mode"] == "DOT_PRODUCT") + if (t.contains("mode") && (t["mode"] == "DOT_PRODUCT" || t["mode"] == "ABS_ERROR")) { return true; } diff --git a/reference_model/src/ops/ewise_binary.cc b/reference_model/src/ops/ewise_binary.cc index be621cb..fab221d 100644 --- a/reference_model/src/ops/ewise_binary.cc +++ b/reference_model/src/ops/ewise_binary.cc @@ -514,7 +514,18 @@ int OpPow<Rank, Dtype>::register_fcn() this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return fpTrunc<OutDtype>(powf(a, b)); }; break; case TOSA_REF_TYPE_FP64: - this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return pow(a, b); }; + if (g_func_config.abs_mode) + { + // ABS_ERROR bounds return (1+abs(log(abs(a))*b)) + this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { + OutEigenType c = log(a > (InEigenType)0 ? a : (-a)) * b; + return 1.0 + (c > (OutEigenType)0 ? c : (-c)); + }; + } + else + { + this->fcn = [](InEigenType a, InEigenType b) -> OutEigenType { return pow(a, b); }; + } break; default: ERROR_IF(true, "unsupported TOSA_REF_TYPE %s", EnumNameTOSAREFTYPE(Dtype)); diff --git a/reference_model/src/ops/ewise_unary.cc b/reference_model/src/ops/ewise_unary.cc index 05c1f4b..d92cde1 100644 --- a/reference_model/src/ops/ewise_unary.cc +++ b/reference_model/src/ops/ewise_unary.cc @@ -172,7 +172,15 @@ int OpExp<Rank, Dtype>::register_fcn() this->fcn = [](InEigenType a) -> OutEigenType { return fpTrunc<Dtype>(expf(a)); }; break; case TOSA_REF_TYPE_FP64: - this->fcn = [](InEigenType a) -> OutEigenType { return exp(a); }; + if (g_func_config.abs_mode) + { + // ABS_ERROR bounds return (1+abs(a)) + this->fcn = [](InEigenType a) -> OutEigenType { return 1.0 + (a > (InEigenType)0 ? a : (-a)); }; + } + else + { + this->fcn = [](InEigenType a) -> OutEigenType { return exp(a); }; + } break; default: ERROR_IF(true, "unsupported TOSA_REF_TYPE %s", EnumNameTOSAREFTYPE(Dtype)); diff --git a/reference_model/src/verify/verifiers.h b/reference_model/src/verify/verifiers.h index fcfb3b3..f2590cb 100644 --- a/reference_model/src/verify/verifiers.h +++ b/reference_model/src/verify/verifiers.h @@ -60,6 +60,15 @@ bool verifyReduceProduct(const CTensor* referenceTensor, const CTensor* implemen /// \return True if compliant else false bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTensor, const UlpInfo& ulpInfo); +/// \brief Perform abs-error based verification +/// +/// \param ref Reference tensor +/// \param refBnd Reference bounds tensor (according to op) +/// \param imp Implementation resulting tensor +/// +/// \return True if compliant else false +bool verifyAbsError(const CTensor* ref, const CTensor* refBnd, const CTensor* imp); + }; // namespace TosaReference #endif // VERIFIERS_H_ diff --git a/reference_model/src/verify/verify_abs_error.cc b/reference_model/src/verify/verify_abs_error.cc new file mode 100644 index 0000000..1afa7fd --- /dev/null +++ b/reference_model/src/verify/verify_abs_error.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2023, ARM Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <cmath> +#include <limits> +#include <memory> +#include <type_traits> +#include <utility> + +#include "verifiers.h" + +namespace TosaReference +{ + +namespace +{ +bool validateData(const double* ref, const double* bnd, const float* imp, const std::vector<int32_t>& shape) +{ + const size_t T = static_cast<size_t>(numElements(shape)); + TOSA_REF_REQUIRE(T > 0, "[AE] Invalid shape for reference tensor"); + + for (size_t i = 0; i < T; ++i) + { + double errBound = ref[i] * exp2(-AccPrecision<float>::normal_frac) * bnd[i]; + bool valid = tosaCheckFloatBound(imp[i], ref[i], errBound); + if (!valid) + { + auto pos = indexToPosition(T, shape); + WARNING("[Verifier][AE] Location %s", positionToString(pos).c_str()); + return false; + } + } + return true; +} +} // namespace +bool verifyAbsError(const CTensor* ref, const CTensor* refBnd, const CTensor* imp) +{ + // Validate that tensors are provided + TOSA_REF_REQUIRE(ref != nullptr, "[AE] Reference tensor is missing"); + TOSA_REF_REQUIRE(refBnd != nullptr, "[AE] Reference bounds tensor is missing"); + TOSA_REF_REQUIRE(imp != nullptr, "[AE] Implementation tensor is missing"); + + const std::vector<int32_t> refShape(ref->shape, ref->shape + ref->num_dims); + + const double* refData = reinterpret_cast<const double*>(ref->data); + const double* refBndData = reinterpret_cast<const double*>(refBnd->data); + TOSA_REF_REQUIRE(refData != nullptr && refBndData != nullptr, "[AE] Missing data for reference or bounds tensors"); + + switch (imp->data_type) + { + case tosa_datatype_fp32_t: { + const float* impData = reinterpret_cast<const float*>(imp->data); + TOSA_REF_REQUIRE(impData != nullptr, "[AE] Missing data for implementation"); + return validateData(refData, refBndData, impData, refShape); + } + default: + WARNING("[Verifier][AE] Data-type not supported."); + break; + } + + return false; +} +} // namespace TosaReference diff --git a/reference_model/src/verify/verify_entry.cc b/reference_model/src/verify/verify_entry.cc index 4da3bde..a37dff7 100644 --- a/reference_model/src/verify/verify_entry.cc +++ b/reference_model/src/verify/verify_entry.cc @@ -40,6 +40,9 @@ bool verify(const CTensor* ref, const CTensor* refBnd, const CTensor* imp, const case VerifyMode::Ulp: { return verifyULP(ref, imp, cfg.ulpInfo); } + case VerifyMode::AbsError: { + return verifyAbsError(ref, refBnd, imp); + } default: { WARNING("[Verifier] Unsupported verification mode."); break; diff --git a/reference_model/src/verify/verify_ulp.cc b/reference_model/src/verify/verify_ulp.cc index 2af0012..b333810 100644 --- a/reference_model/src/verify/verify_ulp.cc +++ b/reference_model/src/verify/verify_ulp.cc @@ -25,57 +25,18 @@ namespace TosaReference namespace { -static_assert(std::numeric_limits<float>::is_iec559, - "TOSA Reference Model has not been built with standard IEE574 32-bit float support; ULP based " - "verifcation is invalid"); -static_assert(std::numeric_limits<double>::is_iec559, - "TOSA Reference Model has not been built with standard IEE574 64-bit float support; ULP based " - "verifcation is invalid"); - -bool tosaCheckULP(double referenceValue, float testValue, double ulpNum) +bool tosaCheckULP(float testValue, double referenceValue, double ulpNum) { - - // Start by sanitizing the input. - - // Both must be NaNs to be correct - if (std::isnan(referenceValue) || std::isnan(testValue)) + double errorBound = 0.0; + if (std::isfinite(referenceValue) && std::abs(referenceValue) != 0.0) { - if (std::isnan(referenceValue) && std::isnan(testValue)) + // Make the sign of the reference value positive + // and adjust the test value appropriately. + if (referenceValue < 0) { - return true; + referenceValue = -referenceValue; + testValue = -testValue; } - WARNING("[Verfier][ULP] Non-matching NaN values - ref (%10f) versus test (%10f).", referenceValue, testValue); - return false; - } - - // Make the sign of the reference value positive - // and adjust the test value appropriately. - if (referenceValue < 0) - { - referenceValue = -referenceValue; - testValue = -testValue; - } - - // At this point we are ready to calculate the ULP bounds for the reference value. - double referenceMin, referenceMax; - - // If the reference is infinity e.g. the result of an overflow the test value must - // be infinity of an appropriate sign. - if (std::isinf(referenceValue)) - { - // We already canonicalized the input such that the reference value is positive - // so no need to check again here. - referenceMin = std::numeric_limits<float>::infinity(); - referenceMax = std::numeric_limits<float>::infinity(); - } - else if (referenceValue == 0) - { - // For zero we require that the results match exactly with the correct sign. - referenceMin = 0; - referenceMax = 0; - } - else - { // Find the exponent of the reference value. int32_t referenceExponent = ilog2(referenceValue); @@ -86,42 +47,9 @@ bool tosaCheckULP(double referenceValue, float testValue, double ulpNum) // i.e. the ULP. double ulpValue = referencePower2 * exp2(-AccPrecision<float>::normal_frac); - // Scale by the number of ULPs requested by the user. - referenceMax = referenceValue + ulpValue * ulpNum; - referenceMin = referenceValue - ulpValue * ulpNum; - - // Handle the overflow cases. - if (referenceMax > AccPrecision<float>::normal_max) - { - referenceMax = std::numeric_limits<float>::infinity(); - } - - if (referenceMin > AccPrecision<float>::normal_max) - { - referenceMin = std::numeric_limits<float>::infinity(); - } - - // And the underflow cases. - if (referenceMax < AccPrecision<float>::normal_min) - { - referenceMax = AccPrecision<float>::normal_min; - } - - if (referenceMin < AccPrecision<float>::normal_min) - { - referenceMin = 0.0; - } - } - - // And finally... Do the comparison. - double testValue64 = static_cast<double>(testValue); - bool withinUlp = testValue64 >= referenceMin && testValue64 <= referenceMax; - if (!withinUlp) - { - WARNING("[Verfier][ULP] value (%10.10f) is not in ULP %g range (%10.10f <= ref (%10.10f) <= %10.10f).", - testValue64, ulpNum, referenceMin, referenceValue, referenceMax); + errorBound = ulpValue * ulpNum; } - return withinUlp; + return tosaCheckFloatBound(testValue, referenceValue, errorBound); } } // namespace @@ -148,7 +76,7 @@ bool verifyULP(const CTensor* referenceTensor, const CTensor* implementationTens // 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); + return tosaCheckULP(implementationValue, referenceValue, ulp); }); if (std::get<0>(pair) == refDataEnd) { diff --git a/reference_model/src/verify/verify_utils.cc b/reference_model/src/verify/verify_utils.cc index 9b20fb2..414f7d7 100644 --- a/reference_model/src/verify/verify_utils.cc +++ b/reference_model/src/verify/verify_utils.cc @@ -48,8 +48,9 @@ NLOHMANN_JSON_SERIALIZE_ENUM(VerifyMode, { VerifyMode::Exact, "EXACT" }, { VerifyMode::Ulp, "ULP" }, { VerifyMode::DotProduct, "DOT_PRODUCT" }, - { VerifyMode::ReduceProduct, "REDUCE_PRODUCT" }, { VerifyMode::FpSpecial, "FP_SPECIAL" }, + { VerifyMode::ReduceProduct, "REDUCE_PRODUCT" }, + { VerifyMode::AbsError, "ABS_ERROR" }, }) void from_json(const nlohmann::json& j, UlpInfo& ulpInfo) @@ -189,4 +190,97 @@ int32_t ilog2(double v) } return n; } + +static_assert(std::numeric_limits<float>::is_iec559, + "TOSA Reference Model has not been built with standard IEEE 754 32-bit float support; Bounds based " + "verification is invalid"); +static_assert(std::numeric_limits<double>::is_iec559, + "TOSA Reference Model has not been built with standard IEEE 754 64-bit float support; Bounds based " + "verification is invalid"); + +bool tosaCheckFloatBound(float testValue, double referenceValue, double errorBound) +{ + // Both must be NaNs to be correct + if (std::isnan(referenceValue) || std::isnan(testValue)) + { + if (std::isnan(referenceValue) && std::isnan(testValue)) + { + return true; + } + WARNING("[Verifier][Bound] Non-matching NaN values - ref (%10f) versus test (%10f).", referenceValue, + testValue); + return false; + } + + // Make the sign of the reference value positive + // and adjust the test value appropriately. + if (referenceValue < 0) + { + referenceValue = -referenceValue; + testValue = -testValue; + } + if (errorBound < 0) + { + errorBound = -errorBound; + } + + // At this point we are ready to calculate the ULP bounds for the reference value. + double referenceMin, referenceMax; + + // If the reference is infinity e.g. the result of an overflow the test value must + // be infinity of an appropriate sign. + if (std::isinf(referenceValue)) + { + // We already canonicalized the input such that the reference value is positive + // so no need to check again here. + referenceMin = std::numeric_limits<float>::infinity(); + referenceMax = std::numeric_limits<float>::infinity(); + } + else if (referenceValue == 0) + { + // For zero we require that the results match exactly with the correct sign. + referenceMin = 0; + referenceMax = 0; + } + else + { + + // Scale by the number of ULPs requested by the user. + referenceMax = referenceValue + errorBound; + referenceMin = referenceValue - errorBound; + + // Handle the overflow cases. + if (referenceMax > AccPrecision<float>::normal_max) + { + referenceMax = std::numeric_limits<float>::infinity(); + } + + if (referenceMin > AccPrecision<float>::normal_max) + { + referenceMin = std::numeric_limits<float>::infinity(); + } + + // And the underflow cases. + if (referenceMax < AccPrecision<float>::normal_min) + { + referenceMax = AccPrecision<float>::normal_min; + } + + if (referenceMin < AccPrecision<float>::normal_min) + { + referenceMin = 0.0; + } + } + + // And finally... Do the comparison. + double testValue64 = static_cast<double>(testValue); + bool withinBound = testValue64 >= referenceMin && testValue64 <= referenceMax; + if (!withinBound) + { + WARNING( + "[Verifier][Bound] value (%10.10f) is not in error bound %g range (%10.10f <= ref (%10.10f) <= %10.10f).", + testValue64, errorBound, referenceMin, referenceValue, referenceMax); + } + return withinBound; +} } // namespace TosaReference diff --git a/reference_model/src/verify/verify_utils.h b/reference_model/src/verify/verify_utils.h index 24d65b0..a58950e 100644 --- a/reference_model/src/verify/verify_utils.h +++ b/reference_model/src/verify/verify_utils.h @@ -43,8 +43,9 @@ enum class VerifyMode Exact, Ulp, DotProduct, + FpSpecial, ReduceProduct, - FpSpecial + AbsError }; /// \brief ULP verification meta-data @@ -135,6 +136,9 @@ struct AccPrecision<float> static constexpr int32_t normal_frac = 23; }; +/// \brief Error bounds check for ULP and ABS_ERROR modes +bool tosaCheckFloatBound(float testValue, double referenceValue, double errorBound); + }; // namespace TosaReference #endif // VERIFY_UTILS_H_ diff --git a/reference_model/test/verify_tests.cpp b/reference_model/test/verify_tests.cpp index 31e27c0..f92792a 100644 --- a/reference_model/test/verify_tests.cpp +++ b/reference_model/test/verify_tests.cpp @@ -428,4 +428,65 @@ TEST_CASE("positive - ulp") } } +TEST_CASE("positive - abs error") +{ + std::string jsonCfg = R"({ + "tensors" : { + "out1" : { + "mode": "ABS_ERROR", + "data_type": "FP32" + } + } + })"; + + const auto shape = std::vector<int32_t>{ 4, 4, 4 }; + 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, true); + std::vector<double> data_fp64(data_fp32.begin(), data_fp32.end()); + + // Set up simple bounds of the input to 2.0 + std::vector<double> bounds_fp64(elementCount); + std::for_each(std::begin(bounds_fp64), std::end(bounds_fp64), [](auto& value) { value = 2.0; }); + constexpr float insideErrBound = 1.0e-7 * 2; // v.approx exp2(-23) * bounds[] + constexpr float outsideErrBound = 1.0e-7 * 3; + + SUBCASE("inside") + { + // Generate some data that meets the ABS_ERROR requirements of the result. + auto otherData_fp32 = data_fp32; + std::for_each(std::begin(otherData_fp32), std::end(otherData_fp32), [insideErrBound](auto& value) { + if (std::abs(value) != 0.0 && !std::isinf(value) && !std::isnan(value)) + value += value * insideErrBound; + }); + const auto referenceTensor = + TosaTensor("out1", tosa_datatype_fp64_t, shape, reinterpret_cast<uint8_t*>(data_fp64.data())); + const auto boundsTensor = + TosaTensor("out1", tosa_datatype_fp64_t, shape, reinterpret_cast<uint8_t*>(bounds_fp64.data())); + const auto implementationTensor = + TosaTensor("out1", tosa_datatype_fp32_t, shape, reinterpret_cast<uint8_t*>(otherData_fp32.data())); + REQUIRE(tvf_verify_data(referenceTensor.cTensor(), boundsTensor.cTensor(), implementationTensor.cTensor(), + jsonCfg.c_str())); + } + + SUBCASE("outside") + { + // 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), [outsideErrBound](auto& value) { + if (std::abs(value) != 0.0 && !std::isinf(value) && !std::isnan(value)) + value += value * outsideErrBound; + }); + + const auto referenceTensor = + TosaTensor("out1", tosa_datatype_fp64_t, shape, reinterpret_cast<uint8_t*>(data_fp64.data())); + const auto boundsTensor = + TosaTensor("out1", tosa_datatype_fp64_t, shape, reinterpret_cast<uint8_t*>(bounds_fp64.data())); + const auto implementationTensor = + TosaTensor("out1", tosa_datatype_fp32_t, shape, reinterpret_cast<uint8_t*>(otherData_fp32.data())); + REQUIRE_FALSE(tvf_verify_data(referenceTensor.cTensor(), boundsTensor.cTensor(), implementationTensor.cTensor(), + jsonCfg.c_str())); + } +} TEST_SUITE_END(); // verify |