[CPU] Ensure mathematical correctness of Convert node (#14174)
This commit is contained in:
1 parent
62aac52079
commit
541045b0ba
4 files changed
+84
-3
No files matched your search
@@ -36,7 +36,7 @@ class TRANSFORMATIONS_API ConvertPrecision;
|
||||
* For all operations from opset1-opset4 this conversions can be applied without adding Conversion operations.
|
||||
* That is possible because all operations that produces "FROM" type can produce "TO" type. And for this operations
|
||||
* we have created special fuse_type_into_<type> functoin (can be found in cpp file) that performs type fusion
|
||||
* into operation.
|
||||
* into operation. m_additional_type_to_fuse_map allows to rewrite existing type convertors.
|
||||
*
|
||||
* List of operations that are supported by this transformations for i64 -> i32 conversion:
|
||||
* opset4::Parameter
|
||||
|
||||
@@ -297,6 +297,10 @@ bool ov::pass::ConvertPrecision::run_on_model(const std::shared_ptr<ngraph::Func
|
||||
{opset10::Unique::get_type_info_static(), fuse_type_to_unique_v10},
|
||||
{opset8::RandomUniform::get_type_info_static(), fuse_type_to_random_uniform_v8}};
|
||||
|
||||
for (const auto& it : m_additional_type_to_fuse_map) {
|
||||
type_to_fuse[it.first] = it.second;
|
||||
}
|
||||
|
||||
type_to_fuse.insert(m_additional_type_to_fuse_map.begin(), m_additional_type_to_fuse_map.end());
|
||||
|
||||
static type_to_fuse_map type_to_extend{
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
#include <ngraph/opsets/opset4.hpp>
|
||||
#include <ngraph/opsets/opset5.hpp>
|
||||
#include <ngraph/opsets/opset6.hpp>
|
||||
#include <openvino/opsets/opset10.hpp>
|
||||
#include <ngraph/op/util/op_types.hpp>
|
||||
#include <ngraph/pass/manager.hpp>
|
||||
#include <ngraph/graph_util.hpp>
|
||||
@@ -261,6 +262,29 @@ Engine::~Engine() {
|
||||
executorManager()->clear("CPUCallbackExecutor");
|
||||
}
|
||||
|
||||
static bool fuse_type_to_convert(const std::shared_ptr<ngraph::Node>& node, ov::element::Type to, size_t idx) {
|
||||
if (auto convert = ov::as_type_ptr<ov::opset10::Convert>(node)) {
|
||||
// For Convert node, converting precision from floating point to boolean will lead to mathematical
|
||||
// error, because here the output precision boolean is replaced by u8. E.g. floating point value 0.01
|
||||
// is converted to be 1 for boolean, but 0 for u8. Thus an Abs and Ceil node should be added before the
|
||||
// Convert node for this scenario.
|
||||
if (convert->input(0).get_element_type().is_real() &&
|
||||
convert->get_convert_element_type() == ngraph::element::boolean && to.is_integral_number()) {
|
||||
auto abs = std::make_shared<ov::opset10::Abs>(convert->input_value(0).get_node_shared_ptr());
|
||||
auto ceil = std::make_shared<ov::opset10::Ceiling>(abs);
|
||||
auto new_convert = std::make_shared<ov::opset10::Convert>(ceil, to);
|
||||
new_convert->set_friendly_name(convert->get_friendly_name());
|
||||
ov::copy_runtime_info(convert, {abs, ceil, new_convert});
|
||||
ov::replace_node(convert, new_convert);
|
||||
return true;
|
||||
} else {
|
||||
convert->set_convert_element_type(to);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void TransformationUpToCPUSpecificOpSet(std::shared_ptr<ngraph::Function> nGraphFunc, const bool _enableLPT, const bool _enableBF16,
|
||||
const bool _enableSnippets, const bool isLegacyApi) {
|
||||
ngraph::pass::Manager manager;
|
||||
@@ -304,6 +328,7 @@ static void TransformationUpToCPUSpecificOpSet(std::shared_ptr<ngraph::Function>
|
||||
};
|
||||
|
||||
static const auto precisions = get_convert_precisions();
|
||||
type_to_fuse_map type_to_fuse = {{ov::opset10::Convert::get_type_info_static(), fuse_type_to_convert}};
|
||||
|
||||
manager.register_pass<ov::pass::AUGRUCellFusion>();
|
||||
manager.register_pass<ngraph::pass::CommonOptimizations>();
|
||||
@@ -330,7 +355,7 @@ static void TransformationUpToCPUSpecificOpSet(std::shared_ptr<ngraph::Function>
|
||||
manager.register_pass<ngraph::pass::low_precision::ConvertSubtractConstant>(defaultPrecisions);
|
||||
}
|
||||
manager.register_pass<ngraph::pass::Validate>();
|
||||
manager.register_pass<ngraph::pass::ConvertPrecision>(precisions);
|
||||
manager.register_pass<ngraph::pass::ConvertPrecision>(precisions, type_to_fuse);
|
||||
manager.register_pass<ngraph::pass::EliminateConvert>();
|
||||
manager.register_pass<SwapConvertTranspose>();
|
||||
manager.register_pass<ConvertToInteraction>();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
#include "shared_test_classes/base/layer_test_utils.hpp"
|
||||
#include "common_test_utils/ov_tensor_utils.hpp"
|
||||
#include "test_utils/cpu_test_utils.hpp"
|
||||
#include "ngraph_functions/builders.hpp"
|
||||
#include "shared_test_classes/base/ov_subgraph.hpp"
|
||||
@@ -47,7 +48,6 @@ protected:
|
||||
targetDevice = CommonTestUtils::DEVICE_CPU;
|
||||
|
||||
InputShape shapes;
|
||||
InferenceEngine::Precision inPrc, outPrc;
|
||||
CPUSpecificParams cpuParams;
|
||||
std::tie(shapes, inPrc, outPrc, cpuParams) = GetParam();
|
||||
|
||||
@@ -68,6 +68,45 @@ protected:
|
||||
|
||||
function = makeNgraphFunction(ngPrc, params, conversion, "ConversionCPU");
|
||||
}
|
||||
|
||||
void generate_inputs(const std::vector<ngraph::Shape>& targetInputStaticShapes) override {
|
||||
if (outPrc != Precision::BOOL) {
|
||||
SubgraphBaseTest::generate_inputs(targetInputStaticShapes);
|
||||
return;
|
||||
}
|
||||
|
||||
// In the scenario where input precision is floating point and output precision is boolean,
|
||||
// for CPU plugin, the output precision boolean will be converted to u8 during common transformation,
|
||||
// the elements in the output tensor will retain the format of u8 with the range [0, 255].
|
||||
// But the output precision in ngraph reference is literal boolean, the elements are either 0 or 1.
|
||||
// Here input floating points values are set to be in the range of [-1, 1], so no extra precision
|
||||
// converting between actual output and expected output will be needed from the side of single layer tests.
|
||||
inputs.clear();
|
||||
const auto& funcInputs = function->inputs();
|
||||
|
||||
auto shape = targetInputStaticShapes.front();
|
||||
size_t size = shape_size(shape);
|
||||
ov::Tensor tensor = ov::test::utils::create_and_fill_tensor(funcInputs[0].get_element_type(), shape, 2 * size);
|
||||
|
||||
if (inPrc == Precision::FP32) {
|
||||
auto *rawBlobDataPtr = static_cast<float *>(tensor.data());
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
rawBlobDataPtr[i] = rawBlobDataPtr[i] / size - 1;
|
||||
}
|
||||
} else if (inPrc == Precision::BF16) {
|
||||
auto *rawBlobDataPtr = static_cast<ngraph::bfloat16 *>(tensor.data());
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
rawBlobDataPtr[i] = rawBlobDataPtr[i] / size - 1;
|
||||
}
|
||||
} else {
|
||||
FAIL() << "Generating inputs with precision" << inPrc << " isn't supported, if output precision is boolean.";
|
||||
}
|
||||
|
||||
inputs.insert({funcInputs[0].get_node_shared_ptr(), tensor});
|
||||
}
|
||||
|
||||
private:
|
||||
InferenceEngine::Precision inPrc, outPrc;
|
||||
};
|
||||
|
||||
TEST_P(ConvertCPULayerTest, CompareWithRefs) {
|
||||
@@ -112,6 +151,11 @@ const std::vector<Precision> precisions = {
|
||||
Precision::BF16
|
||||
};
|
||||
|
||||
const std::vector<Precision> precisions_floating_point = {
|
||||
Precision::FP32,
|
||||
Precision::BF16
|
||||
};
|
||||
|
||||
std::vector<CPUSpecificParams> memForm4D = {
|
||||
CPUSpecificParams({nchw}, {nchw}, {}, {}),
|
||||
CPUSpecificParams({nhwc}, {nhwc}, {}, {}),
|
||||
@@ -127,4 +171,12 @@ INSTANTIATE_TEST_SUITE_P(smoke_ConvertCPULayerTest, ConvertCPULayerTest,
|
||||
::testing::ValuesIn(memForm4D)),
|
||||
ConvertCPULayerTest::getTestCaseName);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(smoke_ConvertCPULayerTest_BOOL, ConvertCPULayerTest,
|
||||
::testing::Combine(
|
||||
::testing::ValuesIn(inShapes_4D),
|
||||
::testing::ValuesIn(precisions_floating_point),
|
||||
::testing::Values(Precision::BOOL),
|
||||
::testing::Values(CPUSpecificParams({nchw}, {nchw}, {}, {}))),
|
||||
ConvertCPULayerTest::getTestCaseName);
|
||||
|
||||
} // namespace CPULayerTestsDefinitions
|
||||
Reference in new issue
Block a user