Fix 'NV12 batch case' (was sporadic failure) (#7790)

Introduced 'absolute threshold' for LayerTests and BaseReferenceTests to consistently catch absolute differences
Previously, when set 'threshold=1.f' it was treated as 'allowed difference is 100%", so there was no way to allow absolute difference as 1.f
This commit is contained in:
Mikhail Nosov 2021-10-01 20:21:52 +03:00 committed by GitHub
parent 5b39e407d9
commit f8ed195841
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 94 additions and 84 deletions

View File

@ -85,73 +85,73 @@ void CommonReferenceTest::ValidateBlobs(const ov::runtime::Tensor& refBlob, cons
case ov::element::bf16:
LayerTestsUtils::LayerTestsCommon::Compare<ov::bfloat16, ov::bfloat16>(
refBlob.data<const ov::bfloat16>(), outBlob.data<const ov::bfloat16>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::f16:
LayerTestsUtils::LayerTestsCommon::Compare<ov::float16, ov::float16>(
refBlob.data<const ov::float16>(), outBlob.data<const ov::float16>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::f32:
LayerTestsUtils::LayerTestsCommon::Compare<float, float>(
refBlob.data<const float>(), outBlob.data<const float>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::i8:
LayerTestsUtils::LayerTestsCommon::Compare<int8_t, int8_t>(
refBlob.data<const int8_t>(), outBlob.data<const int8_t>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::i16:
LayerTestsUtils::LayerTestsCommon::Compare<int16_t, int16_t>(
refBlob.data<const int16_t>(), outBlob.data<const int16_t>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::i32:
LayerTestsUtils::LayerTestsCommon::Compare<int32_t, int32_t>(
refBlob.data<const int32_t>(), outBlob.data<const int32_t>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::i64:
LayerTestsUtils::LayerTestsCommon::Compare<int64_t, int64_t>(
refBlob.data<const int64_t>(), outBlob.data<const int64_t>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::boolean:
LayerTestsUtils::LayerTestsCommon::Compare<bool, bool>(
refBlob.data<const bool>(), outBlob.data<const bool>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::u8:
LayerTestsUtils::LayerTestsCommon::Compare<uint8_t, uint8_t>(
refBlob.data<const uint8_t>(), outBlob.data<const uint8_t>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::u16:
LayerTestsUtils::LayerTestsCommon::Compare<uint16_t, uint16_t>(
refBlob.data<const uint16_t>(), outBlob.data<const uint16_t>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::u32:
LayerTestsUtils::LayerTestsCommon::Compare<uint32_t, uint32_t>(
refBlob.data<const uint32_t>(), outBlob.data<const uint32_t>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::u64:
LayerTestsUtils::LayerTestsCommon::Compare<uint64_t, uint64_t>(
refBlob.data<const uint64_t>(), outBlob.data<const uint64_t>(),
refBlob.get_size(), threshold);
refBlob.get_size(), threshold, abs_threshold);
break;
case ov::element::i4:
case ov::element::u4:
LayerTestsUtils::LayerTestsCommon::Compare<int8_t, int8_t>(
refBlob.data<const int8_t>(), outBlob.data<const int8_t>(),
refBlob.get_size() / 2, threshold);
refBlob.get_size() / 2, threshold, abs_threshold);
break;
case ov::element::u1:
LayerTestsUtils::LayerTestsCommon::Compare<int8_t, int8_t>(
refBlob.data<const int8_t>(), outBlob.data<const int8_t>(),
refBlob.get_size() / 8, threshold);
refBlob.get_size() / 8, threshold, abs_threshold);
break;
default:
FAIL() << "Comparator for " << element_type << " element type isn't supported";

View File

@ -32,7 +32,8 @@ protected:
ov::runtime::InferRequest inferRequest;
std::vector<ov::runtime::Tensor> inputData;
std::vector<ov::runtime::Tensor> refOutData;
float threshold = 1e-2f;
float threshold = 1e-2f; // Relative diff
float abs_threshold = -1.f; // Absolute diff (not used when negative)
};
template <class T>

View File

@ -10,6 +10,7 @@
#include <openvino/op/nv12_to_bgr.hpp>
#include "base_reference_test.hpp"
#include "functional_test_utils/skip_tests_config.hpp"
using namespace ov;
using namespace InferenceEngine;
@ -18,6 +19,9 @@ using namespace reference_tests;
class ReferenceConvertColorNV12LayerTest : public testing::Test, public CommonReferenceTest {
public:
void SetUp() override {
SKIP_IF_CURRENT_TEST_IS_DISABLED()
abs_threshold = 2.f; // allow R, G, B absolute deviation to 2 (of max 255)
threshold = 1.f; // Ignore relative comparison (100%)
}
public:
@ -72,7 +76,6 @@ TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_color_u8_sin
}
TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_g_fp32_single_rgb) {
threshold = 2.f;
auto input = std::vector<float> {145.f, 145.f, 145.f, 145.f, 34.f, 54.f};
auto input_shape = Shape{1, 3, 2, 1};
auto exp_out = std::vector<float> {0, 255.f, 0, 0, 255.f, 0, 0, 255.f, 0, 0, 255.f, 0};
@ -89,45 +92,42 @@ TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_g_fp32_singl
Exec();
}
// Issue 62174
//TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_batch_fp32_two_bgr) {
// threshold = 2.f;
// auto input_y = std::vector<float> {81.f, 81.f, 81.f, 81.f,
// 145.f, 145.f, 145.f, 145.f,
// 41.f, 41.f, 41.f, 41.f};
// auto input_shape_y = Shape{3, 2, 2, 1};
//
// auto input_uv = std::vector<float> {240., 90.,
// 34., 54.,
// 110., 240.};
// auto input_shape_uv = Shape{3, 1, 1, 2};
//
// auto exp_out = std::vector<float> {0, 0, 255., 0, 0, 255., 0, 0, 255., 0, 0, 255.,
// 0, 255., 0, 0, 255., 0, 0, 255., 0, 0, 255., 0,
// 255., 0, 0, 255., 0, 0, 255., 0, 0, 255., 0, 0};
// auto out_shape = Shape{3, 2, 2, 3};
//
// Tensor inp_tensor_y(input_shape_y, element::f32, input_y);
// Tensor inp_tensor_uv(input_shape_uv, element::f32, input_uv);
// inputData = {inp_tensor_y.data, inp_tensor_uv.data};
//
// Tensor exp_tensor(out_shape, element::f32, exp_out);
// refOutData = {exp_tensor.data};
//
// function = CreateFunction2<op::v8::NV12toBGR>(inp_tensor_y, inp_tensor_uv);
//
// Exec();
//}
TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_batch_fp32_two_bgr) {
auto input_y = std::vector<float> {81.f, 81.f, 81.f, 81.f,
145.f, 145.f, 145.f, 145.f,
41.f, 41.f, 41.f, 41.f};
auto input_shape_y = Shape{3, 2, 2, 1};
auto input_uv = std::vector<float> {240., 90.,
34., 54.,
110., 240.};
auto input_shape_uv = Shape{3, 1, 1, 2};
auto exp_out = std::vector<float> {0, 0, 255., 0, 0, 255., 0, 0, 255., 0, 0, 255.,
0, 255., 0, 0, 255., 0, 0, 255., 0, 0, 255., 0,
255., 0, 0, 255., 0, 0, 255., 0, 0, 255., 0, 0};
auto out_shape = Shape{3, 2, 2, 3};
Tensor inp_tensor_y(input_shape_y, element::f32, input_y);
Tensor inp_tensor_uv(input_shape_uv, element::f32, input_uv);
inputData = {inp_tensor_y.data, inp_tensor_uv.data};
Tensor exp_tensor(out_shape, element::f32, exp_out);
refOutData = {exp_tensor.data};
function = CreateFunction2<op::v8::NV12toBGR>(inp_tensor_y, inp_tensor_uv);
Exec();
}
TEST_F(ReferenceConvertColorNV12LayerTest, CompareWithHardcodedRefs_color2x2_f32_two_rgb) {
threshold = 2.f;
auto input_y = std::vector<float> {235, 81, 235, 81};
auto input_shape_y = Shape{1, 2, 2, 1};
auto input_uv = std::vector<float> {184, 109};
auto input_shape_uv = Shape{1, 1, 1, 2};
auto exp_out = std::vector<float> {164, 37, 37, 216, 215, 255, 164, 37, 37, 216, 215, 255};
auto exp_out = std::vector<float> {164, 37, 37, 255, 216, 215, 164, 37, 37, 255, 216, 215};
auto out_shape = Shape{1, 2, 2, 3};
Tensor inp_tensor_y(input_shape_y, element::f32, input_y);

View File

@ -21,7 +21,5 @@ std::vector<std::string> disabledTestPatterns() {
R"(.*InferRequestPreprocessDynamicallyInSetBlobTest.*oPRC=0.*oLT=1.*)",
// CVS-58963: Not implemented yet
R"(.*Behavior.*InferRequest.*OutOfFirstOutIsInputForSecondNetwork.*)",
// Issue 62174
R"(.*CompareWithHardcodedRefs_batch_fp32_two_bgr.*)",
};
}

View File

@ -30,6 +30,7 @@ struct RefPreprocessParams {
class ReferencePreprocessTest : public testing::TestWithParam<RefPreprocessParams>, public CommonReferenceTest {
public:
void SetUp() override {
SKIP_IF_CURRENT_TEST_IS_DISABLED()
const auto& params = GetParam();
function = params.function();
for (const auto& inp : params.inputs) {

View File

@ -61,11 +61,13 @@ public:
static void Compare(const std::vector<std::pair<ngraph::element::Type, std::vector<std::uint8_t>>> &expected,
const std::vector<InferenceEngine::Blob::Ptr> &actual,
float threshold);
float threshold,
float abs_threshold = -1.f);
static void Compare(const std::pair<ngraph::element::Type, std::vector<std::uint8_t>> &expected,
const InferenceEngine::Blob::Ptr &actual,
float threshold);
float threshold,
float abs_threshold = -1.f);
virtual void Compare(const std::vector<std::pair<ngraph::element::Type, std::vector<std::uint8_t>>> &expectedOutputs,
const std::vector<InferenceEngine::Blob::Ptr> &actualOutputs);
@ -90,11 +92,16 @@ public:
#endif
template<class T_IE, class T_NGRAPH>
static void Compare(const T_NGRAPH *expected, const T_IE *actual, std::size_t size, float threshold) {
static void Compare(const T_NGRAPH *expected, const T_IE *actual, std::size_t size, float threshold, float abs_threshold = -1.f) {
for (std::size_t i = 0; i < size; ++i) {
const T_NGRAPH &ref = expected[i];
const auto &res = actual[i];
const auto absoluteDifference = CommonTestUtils::ie_abs(res - ref);
if (abs_threshold > 0.f && absoluteDifference > abs_threshold) {
IE_THROW() << "Absolute comparison of values expected: " << std::to_string(ref) << " and actual: " << std::to_string(res)
<< " at index " << i << " with absolute threshold " << abs_threshold
<< " failed";
}
if (absoluteDifference <= threshold) {
continue;
}
@ -144,6 +151,7 @@ protected:
InferenceEngine::ExecutableNetwork executableNetwork;
std::vector<InferenceEngine::Blob::Ptr> inputs;
float threshold;
float abs_threshold;
InferenceEngine::CNNNetwork cnnNetwork;
std::shared_ptr<InferenceEngine::Core> core;

View File

@ -22,7 +22,7 @@
namespace LayerTestsUtils {
LayerTestsCommon::LayerTestsCommon() : threshold(1e-2f) {
LayerTestsCommon::LayerTestsCommon() : threshold(1e-2f), abs_threshold(-1.f) {
core = PluginCache::get().ie(targetDevice);
}
@ -114,67 +114,67 @@ InferenceEngine::Blob::Ptr LayerTestsCommon::GenerateInput(const InferenceEngine
void LayerTestsCommon::Compare(const std::vector<std::pair<ngraph::element::Type, std::vector<std::uint8_t>>> &expectedOutputs,
const std::vector<InferenceEngine::Blob::Ptr> &actualOutputs,
float threshold) {
float threshold, float abs_threshold) {
for (std::size_t outputIndex = 0; outputIndex < expectedOutputs.size(); ++outputIndex) {
const auto &expected = expectedOutputs[outputIndex];
const auto &actual = actualOutputs[outputIndex];
Compare(expected, actual, threshold);
Compare(expected, actual, threshold, abs_threshold);
}
}
template <typename T_IE>
inline void callCompare(const std::pair<ngraph::element::Type, std::vector<std::uint8_t>> &expected,
const T_IE* actualBuffer, size_t size, float threshold) {
const T_IE* actualBuffer, size_t size, float threshold, float abs_threshold) {
auto expectedBuffer = expected.second.data();
switch (expected.first) {
case ngraph::element::Type_t::i64:
LayerTestsCommon::Compare<T_IE, int64_t>(reinterpret_cast<const int64_t *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::i32:
LayerTestsCommon::Compare<T_IE, int32_t>(reinterpret_cast<const int32_t *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::i16:
LayerTestsCommon::Compare<T_IE, int16_t>(reinterpret_cast<const int16_t *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::i8:
LayerTestsCommon::Compare<T_IE, int8_t>(reinterpret_cast<const int8_t *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::u64:
LayerTestsCommon::Compare<T_IE, uint64_t>(reinterpret_cast<const uint64_t *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::u32:
LayerTestsCommon::Compare<T_IE, uint32_t>(reinterpret_cast<const uint32_t *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::u16:
LayerTestsCommon::Compare<T_IE, uint16_t>(reinterpret_cast<const uint16_t *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::boolean:
case ngraph::element::Type_t::u8:
LayerTestsCommon::Compare<T_IE, uint8_t>(reinterpret_cast<const uint8_t *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::f64:
LayerTestsCommon::Compare<T_IE, double>(reinterpret_cast<const double *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::f32:
LayerTestsCommon::Compare<T_IE, float>(reinterpret_cast<const float *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::f16:
LayerTestsCommon::Compare<T_IE, ngraph::float16>(reinterpret_cast<const ngraph::float16 *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::bf16:
LayerTestsCommon::Compare<T_IE, ngraph::bfloat16>(reinterpret_cast<const ngraph::bfloat16 *>(expectedBuffer),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
case ngraph::element::Type_t::i4: {
auto expectedOut = ngraph::helpers::convertOutputPrecision(
@ -183,7 +183,7 @@ inline void callCompare(const std::pair<ngraph::element::Type, std::vector<std::
ngraph::element::Type_t::i8,
size);
LayerTestsCommon::Compare<T_IE, int8_t>(reinterpret_cast<const int8_t *>(expectedOut.data()),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
}
case ngraph::element::Type_t::u4: {
@ -193,12 +193,12 @@ inline void callCompare(const std::pair<ngraph::element::Type, std::vector<std::
ngraph::element::Type_t::u8,
size);
LayerTestsCommon::Compare<T_IE, uint8_t>(reinterpret_cast<const uint8_t *>(expectedOut.data()),
actualBuffer, size, threshold);
actualBuffer, size, threshold, abs_threshold);
break;
}
case ngraph::element::Type_t::dynamic:
case ngraph::element::Type_t::undefined:
LayerTestsCommon::Compare<T_IE, T_IE>(reinterpret_cast<const T_IE *>(expectedBuffer), actualBuffer, size, threshold);
LayerTestsCommon::Compare<T_IE, T_IE>(reinterpret_cast<const T_IE *>(expectedBuffer), actualBuffer, size, threshold, abs_threshold);
break;
default: FAIL() << "Comparator for " << expected.first << " precision isn't supported";
}
@ -207,7 +207,8 @@ inline void callCompare(const std::pair<ngraph::element::Type, std::vector<std::
void LayerTestsCommon::Compare(const std::pair<ngraph::element::Type, std::vector<std::uint8_t>> &expected,
const InferenceEngine::Blob::Ptr &actual,
float threshold) {
float threshold,
float abs_threshold) {
const auto &precision = actual->getTensorDesc().getPrecision();
auto k = static_cast<float>(expected.first.size()) / precision.size();
// W/A for int4, uint4
@ -226,35 +227,35 @@ void LayerTestsCommon::Compare(const std::pair<ngraph::element::Type, std::vecto
const auto &size = actual->size();
switch (precision) {
case InferenceEngine::Precision::FP32:
callCompare<float>(expected, reinterpret_cast<const float *>(actualBuffer), size, threshold);
callCompare<float>(expected, reinterpret_cast<const float *>(actualBuffer), size, threshold, abs_threshold);
break;
case InferenceEngine::Precision::I32:
callCompare<int32_t>(expected, reinterpret_cast<const int32_t *>(actualBuffer), size, threshold);
callCompare<int32_t>(expected, reinterpret_cast<const int32_t *>(actualBuffer), size, threshold, abs_threshold);
break;
case InferenceEngine::Precision::I64:
callCompare<int64_t>(expected, reinterpret_cast<const int64_t *>(actualBuffer), size, threshold);
callCompare<int64_t>(expected, reinterpret_cast<const int64_t *>(actualBuffer), size, threshold, abs_threshold);
break;
case InferenceEngine::Precision::I8:
callCompare<int8_t>(expected, reinterpret_cast<const int8_t *>(actualBuffer), size, threshold);
callCompare<int8_t>(expected, reinterpret_cast<const int8_t *>(actualBuffer), size, threshold, abs_threshold);
break;
case InferenceEngine::Precision::U16:
callCompare<uint16_t>(expected, reinterpret_cast<const uint16_t *>(actualBuffer), size, threshold);
callCompare<uint16_t>(expected, reinterpret_cast<const uint16_t *>(actualBuffer), size, threshold, abs_threshold);
break;
case InferenceEngine::Precision::I16:
callCompare<int16_t>(expected, reinterpret_cast<const int16_t *>(actualBuffer), size, threshold);
callCompare<int16_t>(expected, reinterpret_cast<const int16_t *>(actualBuffer), size, threshold, abs_threshold);
break;
case InferenceEngine::Precision::BOOL:
case InferenceEngine::Precision::U8:
callCompare<uint8_t>(expected, reinterpret_cast<const uint8_t *>(actualBuffer), size, threshold);
callCompare<uint8_t>(expected, reinterpret_cast<const uint8_t *>(actualBuffer), size, threshold, abs_threshold);
break;
case InferenceEngine::Precision::U64:
callCompare<uint64_t>(expected, reinterpret_cast<const uint64_t *>(actualBuffer), size, threshold);
callCompare<uint64_t>(expected, reinterpret_cast<const uint64_t *>(actualBuffer), size, threshold, abs_threshold);
break;
case InferenceEngine::Precision::BF16:
callCompare<ngraph::bfloat16>(expected, reinterpret_cast<const ngraph::bfloat16 *>(actualBuffer), size, threshold);
callCompare<ngraph::bfloat16>(expected, reinterpret_cast<const ngraph::bfloat16 *>(actualBuffer), size, threshold, abs_threshold);
break;
case InferenceEngine::Precision::FP16:
callCompare<ngraph::float16>(expected, reinterpret_cast<const ngraph::float16 *>(actualBuffer), size, threshold);
callCompare<ngraph::float16>(expected, reinterpret_cast<const ngraph::float16 *>(actualBuffer), size, threshold, abs_threshold);
break;
default:
FAIL() << "Comparator for " << precision << " precision isn't supported";

View File

@ -27,7 +27,8 @@ void ConvertColorNV12LayerTest::SetUp() {
ov::Shape inputShape;
ov::element::Type ngPrc;
bool conversionToRGB, singlePlane;
threshold = 2.0f; // NV12 color conversion can use various of algorithms, thus some deviation is allowed
abs_threshold = 2.0f; // NV12 conversion can use various algorithms, thus some absolute deviation is allowed
threshold = 1.f; // Ignore relative comparison for NV12 convert (allow 100% relative deviation)
std::tie(inputShape, ngPrc, conversionToRGB, singlePlane, targetDevice) = GetParam();
if (singlePlane) {
inputShape[1] = inputShape[1] * 3 / 2;

View File

@ -32,7 +32,7 @@ void color_convert_nv12(const T* arg_y,
};
auto is_little_endian = little_endian();
for (int batch = 0; batch < batch_size; batch++) {
T* out = out_ptr + batch * image_w * image_h;
T* out = out_ptr + batch * image_w * image_h * 3;
auto y_ptr = arg_y + batch * stride_y;
auto uv_ptr = arg_uv + batch * stride_uv;
for (int h = 0; h < image_h; h++) {