From: Andrew Bakalin Date: Wed, 15 Jul 2020 10:48:57 +0000 (+0300) Subject: [IE Common][Tests] saturated_cast: refactoring & tests (#1304) X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=382b442ab379edb76594b97f0530dde59fa01d1f;p=platform%2Fupstream%2Fdldt.git [IE Common][Tests] saturated_cast: refactoring & tests (#1304) * [IE Common] Refactor saturated_cast * [IE Common][Tests] Add tests for saturated casts * [IE Common] Review fixes * [IE Common] Make enable_if check a template parameter --- diff --git a/inference-engine/src/legacy_api/src/net_pass.cpp b/inference-engine/src/legacy_api/src/net_pass.cpp index aa02087..36dc1a8 100644 --- a/inference-engine/src/legacy_api/src/net_pass.cpp +++ b/inference-engine/src/legacy_api/src/net_pass.cpp @@ -1330,28 +1330,13 @@ bool UnrollRNN_if(TensorIterator::Body& net, const std::function -bool isConversionNarrowing(FROM from) { - return from == (static_cast(static_cast(from))); -} - -template -TO saturatedCast(FROM from) { - FROM max = isConversionNarrowing(std::numeric_limits::max()) ? std::numeric_limits::max() : - static_cast(std::numeric_limits::max()); - FROM min = isConversionNarrowing(std::numeric_limits::min()) ? std::numeric_limits::min() : - static_cast(std::numeric_limits::min()); - - return static_cast(std::min(std::max(from, min), max)); -} - template void convertArrayPrecision(typename PrecisionTrait::value_type* dst, const typename PrecisionTrait::value_type* src, size_t nelem) { using dst_type = typename PrecisionTrait::value_type; for (size_t i = 0; i < nelem; i++) { - dst[i] = saturatedCast(src[i]); + dst[i] = PrecisionUtils::saturate_cast(src[i]); } } diff --git a/inference-engine/src/plugin_api/precision_utils.h b/inference-engine/src/plugin_api/precision_utils.h index 386f2a1..9e99add 100644 --- a/inference-engine/src/plugin_api/precision_utils.h +++ b/inference-engine/src/plugin_api/precision_utils.h @@ -12,6 +12,9 @@ #include #include +#include +#include +#include /** * @brief Inference Engine Plugin API namespace @@ -123,6 +126,67 @@ f16tof32Arrays(float* dst, const ie_fp16* src, size_t nelem, float scale = 1.f, INFERENCE_ENGINE_API_CPP(void) f32tof16Arrays(ie_fp16* dst, const float* src, size_t nelem, float scale = 1.f, float bias = 0.f); +/** + * @brief Converts one integral type to another saturating the result if the source value doesn't fit + * into destination type range + * @ingroup ie_dev_api_precision + * + * @param value Value to be converted + */ +template ::value && std::is_integral::value && + std::is_signed::value && + !std::is_same::value + >::type* = nullptr> +inline OutT saturate_cast(const InT& value) { + if (std::numeric_limits::max() > std::numeric_limits::max() && + std::numeric_limits::min() < std::numeric_limits::min()) { + return static_cast(value); + } + + const InT max = std::numeric_limits::max() < std::numeric_limits::max() ? std::numeric_limits::max() : + std::numeric_limits::max(); + const InT min = std::numeric_limits::min() > std::numeric_limits::min() ? std::numeric_limits::min() : + std::numeric_limits::min(); + + return std::min(std::max(value, min), max); +} + +/** + * @brief Converts one integral type to another saturating the result if the source value doesn't fit + * into destination type range + * @ingroup ie_dev_api_precision + * + * @param value Value to be converted + */ +template ::value && std::is_integral::value && + std::is_unsigned::value && + !std::is_same::value + >::type* = nullptr> +inline OutT saturate_cast(const InT& value) { + if (std::numeric_limits::max() > std::numeric_limits::max()) { + return static_cast(value); + } + + const InT max = std::numeric_limits::max() < std::numeric_limits::max() ? std::numeric_limits::max() : + std::numeric_limits::max(); + + return std::min(value, max); +} + +/** + * @brief Converts one integral type to another saturating the result if the source value doesn't fit + * into destination type range + * @ingroup ie_dev_api_precision + * + * @param value Value to be converted + */ +template +inline InT saturate_cast(const InT& value) { + return value; +} + } // namespace PrecisionUtils } // namespace InferenceEngine diff --git a/inference-engine/tests/unit/inference_engine/CMakeLists.txt b/inference-engine/tests/unit/inference_engine/CMakeLists.txt index 3c6a174..051dc00 100644 --- a/inference-engine/tests/unit/inference_engine/CMakeLists.txt +++ b/inference-engine/tests/unit/inference_engine/CMakeLists.txt @@ -4,11 +4,20 @@ set(TARGET_NAME ieUnitTests) +# Find OpenCV components if exist +find_package(OpenCV COMPONENTS imgcodecs videoio imgproc QUIET) +if(NOT OpenCV_FOUND) + message(ERROR "OPENCV is disabled or not found, " ${TARGET_NAME} " needs OpenCV for its build") +else() + add_definitions(-DUSE_OPENCV) +endif() + addIeTargetTest( NAME ${TARGET_NAME} ROOT ${CMAKE_CURRENT_SOURCE_DIR} LINK_LIBRARIES unitTestUtils + ${OpenCV_LIBRARIES} ADD_CPPLINT DEPENDENCIES mock_engine diff --git a/inference-engine/tests/unit/inference_engine/saturated_cast_test.cpp b/inference-engine/tests/unit/inference_engine/saturated_cast_test.cpp new file mode 100644 index 0000000..c89169e --- /dev/null +++ b/inference-engine/tests/unit/inference_engine/saturated_cast_test.cpp @@ -0,0 +1,114 @@ +// Copyright (C) 2020 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include +#include "common_test_utils/test_common.hpp" + +#include "precision_utils.h" +#include "ie_precision.hpp" + +#include + +using namespace InferenceEngine; + +class SaturateCastTestsI64ToI32 : public CommonTestUtils::TestsCommon { +public: + using fromType = typename PrecisionTrait::value_type; + using toType = typename PrecisionTrait::value_type; +}; + +TEST_F(SaturateCastTestsI64ToI32, I64ToI32NonNarrowingPositive) { + const auto value = fromType{42}; + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +TEST_F(SaturateCastTestsI64ToI32, I64ToI32NonNarrowingNegative) { + const auto value = fromType{-42}; + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingMaxToMax) { + const auto value = std::numeric_limits::max(); + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingNonMaxToMax) { + const auto value = std::numeric_limits::max() - 1; + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingMinToMin) { + const auto value = std::numeric_limits::min(); + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +TEST_F(SaturateCastTestsI64ToI32, I64ToI32NarrowingNonMinToMin) { + const auto value = std::numeric_limits::min() + 1; + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +class SaturateCastTestsU64ToI32 : public CommonTestUtils::TestsCommon { +public: + using fromType = typename PrecisionTrait::value_type; + using toType = typename PrecisionTrait::value_type; +}; + +TEST_F(SaturateCastTestsU64ToI32, U64ToI32NonNarrowing) { + const auto value = fromType{42}; + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +TEST_F(SaturateCastTestsU64ToI32, U64ToI32NarrowingMaxToMax) { + const auto value = std::numeric_limits::max(); + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +TEST_F(SaturateCastTestsU64ToI32, U64ToI32NarrowingNonMaxToMax) { + const auto value = std::numeric_limits::max() - 1; + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +class SaturateCastTestsBoolToU8 : public CommonTestUtils::TestsCommon { +public: + using fromType = typename PrecisionTrait::value_type; + using toType = typename PrecisionTrait::value_type; +}; + +TEST_F(SaturateCastTestsBoolToU8, BOOLtoU8MaxToNonMax) { + const auto value = std::numeric_limits::max(); + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +class SaturateCastTestsBoolToI32 : public CommonTestUtils::TestsCommon { +public: + using fromType = typename PrecisionTrait::value_type; + using toType = typename PrecisionTrait::value_type; +}; + +TEST_F(SaturateCastTestsBoolToI32, BOOLtoI32MaxToNonMax) { + const auto value = std::numeric_limits::max(); + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +class SaturateCastTestsU8ToI32 : public CommonTestUtils::TestsCommon { +public: + using fromType = typename PrecisionTrait::value_type; + using toType = typename PrecisionTrait::value_type; +}; + +TEST_F(SaturateCastTestsU8ToI32, U8toI32FMaxToNonMax) { + const auto value = std::numeric_limits::max(); + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +} + +class SaturateCastTestsU16ToI32 : public CommonTestUtils::TestsCommon { +public: + using fromType = typename PrecisionTrait::value_type; + using toType = typename PrecisionTrait::value_type; +}; + +TEST_F(SaturateCastTestsU16ToI32, U16toI32FMaxToNonMax) { + const auto value = std::numeric_limits::max(); + EXPECT_EQ(PrecisionUtils::saturate_cast(value), cv::saturate_cast(value)); +}