[OV20] Enable OpenCV tests and support 'u8' type for Interpolate op (#8182)
* Interpolate reference implementation: - Support u8 and other numeric types - For integral types - round result to nearest integer (don't cast) Preprocessing: enable OpenCV tests and add resize conformance tests with OpenCV * Revert changes in interpolate.cpp, making them minimal needed (added u8 resize)
This commit is contained in:
parent
f34e1e332f
commit
a2a8969201
@ -21,16 +21,14 @@ addIeTargetTest(
|
|||||||
TEMPLATE
|
TEMPLATE
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ENABLE_TEMPLATE_OPENCV_TESTS)
|
find_package(OpenCV QUIET COMPONENTS core imgproc)
|
||||||
find_package(OpenCV QUIET COMPONENTS core imgproc)
|
|
||||||
|
|
||||||
if(OpenCV_FOUND)
|
if(OpenCV_FOUND)
|
||||||
message("-- Reference preprocessing: OpenCV tests are enabled")
|
message("-- Reference preprocessing: OpenCV tests are enabled")
|
||||||
target_compile_definitions(${TARGET_NAME} PRIVATE OPENCV_TEMPLATE_TESTS)
|
target_compile_definitions(${TARGET_NAME} PRIVATE OPENCV_TEMPLATE_TESTS)
|
||||||
target_link_libraries(${TARGET_NAME} PRIVATE opencv_imgproc opencv_core)
|
target_link_libraries(${TARGET_NAME} PRIVATE opencv_imgproc opencv_core)
|
||||||
else()
|
else()
|
||||||
message("-- Reference preprocessing: OpenCV tests are disabled")
|
message("-- Reference preprocessing: OpenCV tests are disabled")
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# [cmake:functional_tests]
|
# [cmake:functional_tests]
|
||||||
|
@ -26,6 +26,10 @@ public:
|
|||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
SKIP_IF_CURRENT_TEST_IS_DISABLED()
|
SKIP_IF_CURRENT_TEST_IS_DISABLED()
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PreprocessOpenCVReferenceTest_NV12 : public PreprocessOpenCVReferenceTest {
|
||||||
|
public:
|
||||||
void Validate() override {
|
void Validate() override {
|
||||||
threshold = 1.f;
|
threshold = 1.f;
|
||||||
abs_threshold = 1.f;
|
abs_threshold = 1.f;
|
||||||
@ -40,7 +44,7 @@ public:
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
static std::shared_ptr<Function> create_simple_function_nv12(element::Type type, const PartialShape& shape) {
|
static std::shared_ptr<Function> create_simple_function(element::Type type, const PartialShape& shape) {
|
||||||
auto data1 = std::make_shared<op::v0::Parameter>(type, shape);
|
auto data1 = std::make_shared<op::v0::Parameter>(type, shape);
|
||||||
data1->set_friendly_name("input1");
|
data1->set_friendly_name("input1");
|
||||||
data1->get_output_tensor(0).set_names({"tensor_input1", "input1"});
|
data1->get_output_tensor(0).set_names({"tensor_input1", "input1"});
|
||||||
@ -49,11 +53,11 @@ static std::shared_ptr<Function> create_simple_function_nv12(element::Type type,
|
|||||||
op->set_friendly_name("Add0");
|
op->set_friendly_name("Add0");
|
||||||
auto res = std::make_shared<op::v0::Result>(op);
|
auto res = std::make_shared<op::v0::Result>(op);
|
||||||
res->set_friendly_name("Result1");
|
res->set_friendly_name("Result1");
|
||||||
res->get_output_tensor(0).set_names({"tensor_output1", "Result1", "Convert1"});
|
res->get_output_tensor(0).set_names({"tensor_output1", "Result1"});
|
||||||
return std::make_shared<ov::Function>(ResultVector{res}, ParameterVector{data1});
|
return std::make_shared<ov::Function>(ResultVector{res}, ParameterVector{data1});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_full_color_range) {
|
TEST_F(PreprocessOpenCVReferenceTest_NV12, convert_nv12_full_color_range) {
|
||||||
size_t height = 64; // 64/2 = 32 values for R
|
size_t height = 64; // 64/2 = 32 values for R
|
||||||
size_t width = 64; // 64/2 = 32 values for G
|
size_t width = 64; // 64/2 = 32 values for G
|
||||||
int b_step = 5;
|
int b_step = 5;
|
||||||
@ -64,7 +68,7 @@ TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_full_color_range) {
|
|||||||
|
|
||||||
auto full_height = height * b_dim;
|
auto full_height = height * b_dim;
|
||||||
auto func_shape = Shape{1, full_height, width, 3};
|
auto func_shape = Shape{1, full_height, width, 3};
|
||||||
function = create_simple_function_nv12(element::u8, func_shape);
|
function = create_simple_function(element::u8, func_shape);
|
||||||
|
|
||||||
inputData.clear();
|
inputData.clear();
|
||||||
|
|
||||||
@ -90,10 +94,10 @@ TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_full_color_range) {
|
|||||||
Exec();
|
Exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_colored) {
|
TEST_F(PreprocessOpenCVReferenceTest_NV12, convert_nv12_colored) {
|
||||||
auto input_yuv = std::vector<uint8_t> {235, 81, 235, 81, 109, 184};
|
auto input_yuv = std::vector<uint8_t> {235, 81, 235, 81, 109, 184};
|
||||||
auto func_shape = Shape{1, 2, 2, 3};
|
auto func_shape = Shape{1, 2, 2, 3};
|
||||||
function = create_simple_function_nv12(element::u8, func_shape);
|
function = create_simple_function(element::u8, func_shape);
|
||||||
|
|
||||||
inputData.clear();
|
inputData.clear();
|
||||||
|
|
||||||
@ -116,4 +120,136 @@ TEST_F(PreprocessOpenCVReferenceTest, convert_nv12_colored) {
|
|||||||
Exec();
|
Exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PreprocessOpenCVReferenceTest, resize_u8_simple_linear) {
|
||||||
|
auto input_shape = Shape{1, 1, 2, 2};
|
||||||
|
auto func_shape = Shape{1, 1, 1, 1};
|
||||||
|
auto input_img = std::vector<uint8_t> {5, 5, 5, 4};
|
||||||
|
function = create_simple_function(element::u8, func_shape);
|
||||||
|
|
||||||
|
inputData.clear();
|
||||||
|
|
||||||
|
function = PrePostProcessor().input(InputInfo()
|
||||||
|
.tensor(InputTensorInfo().set_spatial_static_shape(2, 2))
|
||||||
|
.preprocess(PreProcessSteps().resize(ResizeAlgorithm::RESIZE_LINEAR))
|
||||||
|
.network(InputNetworkInfo().set_layout("NCHW"))
|
||||||
|
)
|
||||||
|
.build(function);
|
||||||
|
|
||||||
|
const auto ¶m = function->get_parameters()[0];
|
||||||
|
inputData.emplace_back(param->get_element_type(), param->get_shape(), input_img.data());
|
||||||
|
|
||||||
|
// Calculate reference expected values from OpenCV
|
||||||
|
cv::Mat cvPic = cv::Mat(2, 2, CV_8UC1, input_img.data());
|
||||||
|
cv::Mat cvPicResized;
|
||||||
|
cv::resize(cvPic, cvPicResized, cv::Size(1, 1), cv::INTER_NEAREST);
|
||||||
|
refOutData.emplace_back(param->get_element_type(), func_shape, cvPicResized.data);
|
||||||
|
// Exec now
|
||||||
|
Exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PreprocessOpenCVReferenceTest, resize_u8_large_picture_linear) {
|
||||||
|
threshold = 1.f;
|
||||||
|
abs_threshold = 1.f; // Some pixels still have deviations of 1 step
|
||||||
|
const size_t input_height = 50;
|
||||||
|
const size_t input_width = 50;
|
||||||
|
const size_t func_height = 37;
|
||||||
|
const size_t func_width = 31;
|
||||||
|
auto input_shape = Shape{1, 1, input_height, input_width};
|
||||||
|
auto func_shape = Shape{1, 1, func_height, func_width};
|
||||||
|
auto input_img = std::vector<uint8_t> (shape_size(input_shape));
|
||||||
|
std::default_random_engine random(0); // hard-coded seed to make test results predictable
|
||||||
|
std::uniform_int_distribution<int> distrib(0, 255);
|
||||||
|
for (std::size_t i = 0; i < shape_size(input_shape); i++) {
|
||||||
|
auto v = distrib(random);
|
||||||
|
input_img[i] = static_cast<uint8_t>(v);
|
||||||
|
}
|
||||||
|
function = create_simple_function(element::u8, func_shape);
|
||||||
|
|
||||||
|
inputData.clear();
|
||||||
|
|
||||||
|
function = PrePostProcessor().input(InputInfo()
|
||||||
|
.tensor(InputTensorInfo().set_spatial_static_shape(input_height, input_width))
|
||||||
|
.preprocess(PreProcessSteps().resize(ResizeAlgorithm::RESIZE_LINEAR))
|
||||||
|
.network(InputNetworkInfo().set_layout("NCHW"))
|
||||||
|
)
|
||||||
|
.build(function);
|
||||||
|
|
||||||
|
const auto ¶m = function->get_parameters()[0];
|
||||||
|
inputData.emplace_back(param->get_element_type(), param->get_shape(), input_img.data());
|
||||||
|
|
||||||
|
// Calculate reference expected values from OpenCV
|
||||||
|
cv::Mat cvPic = cv::Mat(input_height, input_width, CV_8UC1, input_img.data());
|
||||||
|
cv::Mat cvPicResized;
|
||||||
|
cv::resize(cvPic, cvPicResized, cv::Size(func_width, func_height), cv::INTER_LINEAR_EXACT);
|
||||||
|
refOutData.emplace_back(param->get_element_type(), func_shape, cvPicResized.data);
|
||||||
|
// Exec now
|
||||||
|
Exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PreprocessOpenCVReferenceTest, resize_f32_large_picture_linear) {
|
||||||
|
threshold = 0.01f;
|
||||||
|
abs_threshold = 0.01f;
|
||||||
|
const size_t input_height = 50;
|
||||||
|
const size_t input_width = 50;
|
||||||
|
const size_t func_height = 37;
|
||||||
|
const size_t func_width = 31;
|
||||||
|
auto input_shape = Shape{1, 1, input_height, input_width};
|
||||||
|
auto func_shape = Shape{1, 1, func_height, func_width};
|
||||||
|
auto input_img = std::vector<float> (shape_size(input_shape));
|
||||||
|
std::default_random_engine random(0); // hard-coded seed to make test results predictable
|
||||||
|
std::uniform_int_distribution<int> distrib(0, 255);
|
||||||
|
for (std::size_t i = 0; i < shape_size(input_shape); i++) {
|
||||||
|
input_img[i] = static_cast<float>(distrib(random));
|
||||||
|
}
|
||||||
|
function = create_simple_function(element::f32, func_shape);
|
||||||
|
|
||||||
|
inputData.clear();
|
||||||
|
|
||||||
|
function = PrePostProcessor().input(InputInfo()
|
||||||
|
.tensor(InputTensorInfo().set_spatial_static_shape(input_height, input_width))
|
||||||
|
.preprocess(PreProcessSteps().resize(ResizeAlgorithm::RESIZE_LINEAR))
|
||||||
|
.network(InputNetworkInfo().set_layout("NCHW"))
|
||||||
|
)
|
||||||
|
.build(function);
|
||||||
|
|
||||||
|
const auto ¶m = function->get_parameters()[0];
|
||||||
|
inputData.emplace_back(param->get_element_type(), param->get_shape(), input_img.data());
|
||||||
|
|
||||||
|
// Calculate reference expected values from OpenCV
|
||||||
|
cv::Mat cvPic = cv::Mat(input_height, input_width, CV_32FC1, input_img.data());
|
||||||
|
cv::Mat cvPicResized;
|
||||||
|
cv::resize(cvPic, cvPicResized, cv::Size(func_width, func_height), cv::INTER_LINEAR_EXACT);
|
||||||
|
refOutData.emplace_back(param->get_element_type(), func_shape, cvPicResized.data);
|
||||||
|
// Exec now
|
||||||
|
Exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PreprocessOpenCVReferenceTest, DISABLED_resize_f32_large_picture_cubic_small) {
|
||||||
|
const size_t input_height = 4;
|
||||||
|
const size_t input_width = 4;
|
||||||
|
const size_t func_height = 3;
|
||||||
|
const size_t func_width = 3;
|
||||||
|
auto input_shape = Shape{1, 1, input_height, input_width};
|
||||||
|
auto func_shape = Shape{1, 1, func_height, func_width};
|
||||||
|
auto element_type = element::f32;
|
||||||
|
auto input_img = std::vector<float> {1.f, 2.f, 3.f, 4.f, 4.f, 3.f, 2.f, 1.f, 1.f, 2.f, 3.f, 4.f, 4.f, 3.f, 2.f, 1.f};
|
||||||
|
function = create_simple_function(element_type, func_shape);
|
||||||
|
function = PrePostProcessor().input(InputInfo()
|
||||||
|
.tensor(InputTensorInfo().set_spatial_static_shape(input_height, input_width))
|
||||||
|
.preprocess(PreProcessSteps().resize(ResizeAlgorithm::RESIZE_CUBIC))
|
||||||
|
.network(InputNetworkInfo().set_layout("NCHW"))
|
||||||
|
)
|
||||||
|
.build(function);
|
||||||
|
|
||||||
|
inputData.emplace_back(element_type, input_shape, input_img.data());
|
||||||
|
|
||||||
|
// Calculate reference expected values from OpenCV
|
||||||
|
cv::Mat cvPic = cv::Mat(input_height, input_width, CV_32FC1, input_img.data());
|
||||||
|
cv::Mat cvPicResized;
|
||||||
|
cv::resize(cvPic, cvPicResized, cv::Size(func_width, func_height), cv::INTER_CUBIC);
|
||||||
|
refOutData.emplace_back(element_type, func_shape, cvPicResized.data);
|
||||||
|
// Exec now
|
||||||
|
Exec();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // OPENCV_TEMPLATE_TESTS
|
#endif // OPENCV_TEMPLATE_TESTS
|
@ -371,10 +371,15 @@ void InterpolateEval<T>::linear_func(const T* input_data, T* out) {
|
|||||||
|
|
||||||
if (wsum == 0.0f) {
|
if (wsum == 0.0f) {
|
||||||
out[output_transform.index(output_coord)] = T{};
|
out[output_transform.index(output_coord)] = T{};
|
||||||
|
} else {
|
||||||
|
if (std::is_integral<T>()) {
|
||||||
|
// Round value for integral return types
|
||||||
|
out[output_transform.index(output_coord)] = static_cast<T>(std::round(summa / wsum));
|
||||||
} else {
|
} else {
|
||||||
out[output_transform.index(output_coord)] = static_cast<T>(summa / wsum);
|
out[output_transform.index(output_coord)] = static_cast<T>(summa / wsum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
NGRAPH_SUPPRESS_DEPRECATED_END
|
NGRAPH_SUPPRESS_DEPRECATED_END
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,10 +201,10 @@ ov::PartialShape op::v4::Interpolate::get_padded_input_shape(const ov::PartialSh
|
|||||||
void op::v4::Interpolate::validate_and_infer_types() {
|
void op::v4::Interpolate::validate_and_infer_types() {
|
||||||
NGRAPH_OP_SCOPE(v4_Interpolate_validate_and_infer_types);
|
NGRAPH_OP_SCOPE(v4_Interpolate_validate_and_infer_types);
|
||||||
element::Type input_et = get_input_element_type(0);
|
element::Type input_et = get_input_element_type(0);
|
||||||
NODE_VALIDATION_CHECK(
|
NODE_VALIDATION_CHECK(this,
|
||||||
this,
|
input_et == element::f32 || input_et == element::f16 || input_et == element::i8 ||
|
||||||
input_et == element::f32 || input_et == element::f16 || input_et == element::i8 || input_et == element::bf16,
|
input_et == element::bf16 || input_et == element::u8,
|
||||||
"Input element type must be f32, f16, bf16 or i8");
|
"Input element type must be f32, f16, bf16, i8 or u8");
|
||||||
|
|
||||||
element::Type sizes_et = get_input_element_type(1);
|
element::Type sizes_et = get_input_element_type(1);
|
||||||
NODE_VALIDATION_CHECK(
|
NODE_VALIDATION_CHECK(
|
||||||
@ -454,6 +454,14 @@ bool op::v4::Interpolate::evaluate_interpolate(const HostTensorVector& outputs,
|
|||||||
outputs[0]->get_data_ptr<int8_t>(),
|
outputs[0]->get_data_ptr<int8_t>(),
|
||||||
out_shape,
|
out_shape,
|
||||||
m_attrs);
|
m_attrs);
|
||||||
|
case element::Type_t::u8:
|
||||||
|
ngraph::runtime::reference::interpolate<uint8_t>(reinterpret_cast<uint8_t*>(padded_data_ptr),
|
||||||
|
padded_input_shape,
|
||||||
|
scales,
|
||||||
|
axes,
|
||||||
|
outputs[0]->get_data_ptr<uint8_t>(),
|
||||||
|
out_shape,
|
||||||
|
m_attrs);
|
||||||
break;
|
break;
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
@ -469,6 +477,7 @@ bool op::v4::Interpolate::evaluate(const HostTensorVector& outputs, const HostTe
|
|||||||
bool op::v4::Interpolate::has_evaluate() const {
|
bool op::v4::Interpolate::has_evaluate() const {
|
||||||
NGRAPH_OP_SCOPE(v4_Interpolate_has_evaluate);
|
NGRAPH_OP_SCOPE(v4_Interpolate_has_evaluate);
|
||||||
switch (get_input_element_type(0)) {
|
switch (get_input_element_type(0)) {
|
||||||
|
case ngraph::element::i8:
|
||||||
case ngraph::element::u8:
|
case ngraph::element::u8:
|
||||||
case ngraph::element::f16:
|
case ngraph::element::f16:
|
||||||
case ngraph::element::f32:
|
case ngraph::element::f32:
|
||||||
|
Loading…
Reference in New Issue
Block a user