From afc599563ee3d9f154a0570cc9cfb0cca66d5aa9 Mon Sep 17 00:00:00 2001 From: Katarzyna Mitrus Date: Tue, 14 Nov 2023 21:22:45 +0100 Subject: [PATCH] [Opset13][FP8] Introduce FakeConvert op core (#20930) * FakeConvert op init * Update dest types names * Update op hpp * Update opset ops number * Init type_prop tests * Add attributes tests * Add op check test * Update namespace in fc cpp * Update getters * Refactor static member * Make destination_type lower case * Update type in test * Move get_valid_types out of class * Update ops number in opset * Remove apply_scale attribute * Additional constructor to make `shift` input optional --- src/core/include/openvino/op/fake_convert.hpp | 41 ++++++++++ src/core/include/openvino/op/ops.hpp | 1 + .../include/openvino/opsets/opset13_tbl.hpp | 1 + src/core/src/op/fake_convert.cpp | 75 +++++++++++++++++++ src/core/tests/opset.cpp | 2 +- src/core/tests/type_prop/fake_convert.cpp | 51 +++++++++++++ src/core/tests/visitors/op/fake_convert.cpp | 47 ++++++++++++ .../src/op_impl_check/single_op_graph.cpp | 9 +++ 8 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 src/core/include/openvino/op/fake_convert.hpp create mode 100644 src/core/src/op/fake_convert.cpp create mode 100644 src/core/tests/type_prop/fake_convert.cpp create mode 100644 src/core/tests/visitors/op/fake_convert.cpp diff --git a/src/core/include/openvino/op/fake_convert.hpp b/src/core/include/openvino/op/fake_convert.hpp new file mode 100644 index 00000000000000..0c63de608c70be --- /dev/null +++ b/src/core/include/openvino/op/fake_convert.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include "openvino/op/op.hpp" + +namespace ov { +namespace op { +namespace v13 { +/// \ingroup ov_ops_cpp_api +class OPENVINO_API FakeConvert : public Op { +public: + OPENVINO_OP("FakeConvert", "opset13"); + + FakeConvert() = default; + FakeConvert(const ov::Output& arg, + const ov::Output& scale, + std::string destination_type = "f8e4m3"); + + FakeConvert(const ov::Output& arg, + const ov::Output& scale, + const ov::Output& shift, + std::string destination_type = "f8e4m3"); + + void validate_and_infer_types() override; + std::shared_ptr clone_with_new_inputs(const ov::OutputVector& new_args) const override; + bool visit_attributes(ov::AttributeVisitor& visitor) override; + bool has_evaluate() const override; + + const std::string& get_destination_type() const; + +private: + void validate_type() const; + + std::string m_destination_type = "f8e4m3"; +}; +} // namespace v13 +} // namespace op +} // namespace ov diff --git a/src/core/include/openvino/op/ops.hpp b/src/core/include/openvino/op/ops.hpp index 5b28762933a1ec..575697779938ae 100644 --- a/src/core/include/openvino/op/ops.hpp +++ b/src/core/include/openvino/op/ops.hpp @@ -61,6 +61,7 @@ #include "openvino/op/experimental_detectron_topkrois.hpp" #include "openvino/op/extractimagepatches.hpp" #include "openvino/op/eye.hpp" +#include "openvino/op/fake_convert.hpp" #include "openvino/op/fake_quantize.hpp" #include "openvino/op/floor.hpp" #include "openvino/op/floor_mod.hpp" diff --git a/src/core/include/openvino/opsets/opset13_tbl.hpp b/src/core/include/openvino/opsets/opset13_tbl.hpp index 13b598eaca11f0..02597716a2ad93 100644 --- a/src/core/include/openvino/opsets/opset13_tbl.hpp +++ b/src/core/include/openvino/opsets/opset13_tbl.hpp @@ -216,3 +216,4 @@ _OPENVINO_OP_REG(BitwiseXor, ov::op::v13) _OPENVINO_OP_REG(NMSRotated, ov::op::v13) _OPENVINO_OP_REG(Multinomial, ov::op::v13) _OPENVINO_OP_REG(ScaledDotProductAttention, ov::op::v13) +_OPENVINO_OP_REG(FakeConvert, ov::op::v13) diff --git a/src/core/src/op/fake_convert.cpp b/src/core/src/op/fake_convert.cpp new file mode 100644 index 00000000000000..f32db7409dd63a --- /dev/null +++ b/src/core/src/op/fake_convert.cpp @@ -0,0 +1,75 @@ +// Copyright (C) 2018-2022 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/fake_convert.hpp" + +#include "itt.hpp" + +namespace ov { +namespace op { +namespace v13 { +namespace fake_convert { +static const std::vector& get_valid_types() { + static const std::vector valid_types{"f8e4m3", "f8e5m2"}; + return valid_types; +} +} // namespace fake_convert + +FakeConvert::FakeConvert(const ov::Output& arg, + const ov::Output& scale, + std::string destination_type) + : Op({arg, scale}), + m_destination_type(std::move(destination_type)) { + constructor_validate_and_infer_types(); +} + +FakeConvert::FakeConvert(const ov::Output& arg, + const ov::Output& scale, + const ov::Output& shift, + std::string destination_type) + : Op({arg, scale, shift}), + m_destination_type(std::move(destination_type)) { + constructor_validate_and_infer_types(); +} + +const std::string& FakeConvert::get_destination_type() const { + return m_destination_type; +} + +void FakeConvert::validate_and_infer_types() { + OV_OP_SCOPE(v13_FakeConvert_validate_and_infer_types); + validate_type(); + set_output_type(0, get_input_element_type(0), get_input_partial_shape(0)); +} + +std::shared_ptr FakeConvert::clone_with_new_inputs(const ov::OutputVector& new_args) const { + OV_OP_SCOPE(v13_FakeConvert_clone_with_new_inputs); + if (new_args.size() == 2) { + return std::make_shared(new_args.at(0), new_args.at(1), m_destination_type); + } else if (new_args.size() == 3) { + return std::make_shared(new_args.at(0), new_args.at(1), new_args.at(2), m_destination_type); + } else { + OPENVINO_THROW("Incorrect number of FakeConvert new arguments."); + } +} + +bool FakeConvert::visit_attributes(ov::AttributeVisitor& visitor) { + OV_OP_SCOPE(v13_FakeConvert_visit_attributes); + visitor.on_attribute("destination_type", m_destination_type); + return true; +} + +void FakeConvert::validate_type() const { + const auto& valid_types = fake_convert::get_valid_types(); + OPENVINO_ASSERT(std::find(valid_types.begin(), valid_types.end(), m_destination_type) != valid_types.end(), + "Bad format for f8 conversion type: " + m_destination_type); +} + +bool FakeConvert::has_evaluate() const { + return false; +} + +} // namespace v13 +} // namespace op +} // namespace ov diff --git a/src/core/tests/opset.cpp b/src/core/tests/opset.cpp index 29e9df2b4dab2c..37eb02e38429cf 100644 --- a/src/core/tests/opset.cpp +++ b/src/core/tests/opset.cpp @@ -71,7 +71,7 @@ INSTANTIATE_TEST_SUITE_P(opset, OpsetTestParams{ov::get_opset10, 177}, OpsetTestParams{ov::get_opset11, 177}, OpsetTestParams{ov::get_opset12, 178}, - OpsetTestParams{ov::get_opset13, 185}), + OpsetTestParams{ov::get_opset13, 186}), OpsetTestNameGenerator{}); class MyOpOld : public ov::op::Op { diff --git a/src/core/tests/type_prop/fake_convert.cpp b/src/core/tests/type_prop/fake_convert.cpp new file mode 100644 index 00000000000000..06976651b5a9a7 --- /dev/null +++ b/src/core/tests/type_prop/fake_convert.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/fake_convert.hpp" + +#include + +#include "common_test_utils/type_prop.hpp" + +using namespace ov; +using ov::op::v0::Parameter; + +TEST(type_prop, fake_convert_no_shift) { + const auto data = std::make_shared(element::f32, PartialShape{2, 3, 8, 6}); + const auto scale = std::make_shared(element::f32, PartialShape{}); + + const auto op = std::make_shared(data, scale); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{2, 3, 8, 6})); +} + +TEST(type_prop, fake_convert_basic_f32) { + const auto data = std::make_shared(element::f32, PartialShape{2, 3, 8, 6}); + const auto scale = std::make_shared(element::f32, PartialShape{}); + const auto shift = std::make_shared(element::f32, PartialShape{}); + + const auto op = std::make_shared(data, scale, shift); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{2, 3, 8, 6})); +} + +TEST(type_prop, fake_convert_basic_f16) { + const auto data = std::make_shared(element::f16, PartialShape{2, 3, 8, 6}); + const auto scale = std::make_shared(element::f16, PartialShape{}); + const auto shift = std::make_shared(element::f16, PartialShape{}); + + const auto op = std::make_shared(data, scale, shift); + EXPECT_EQ(op->get_output_element_type(0), element::f16); + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape{2, 3, 8, 6})); +} + +TEST(type_prop, fake_convert_dynamic_shape) { + const auto data = std::make_shared(element::f32, PartialShape::dynamic()); + const auto scale = std::make_shared(element::f32, PartialShape{}); + const auto shift = std::make_shared(element::f32, PartialShape{}); + + const auto op = std::make_shared(data, scale, shift); + EXPECT_EQ(op->get_output_element_type(0), element::f32); + EXPECT_EQ(op->get_output_partial_shape(0), (PartialShape::dynamic())); +} diff --git a/src/core/tests/visitors/op/fake_convert.cpp b/src/core/tests/visitors/op/fake_convert.cpp new file mode 100644 index 00000000000000..73580cacd7fe81 --- /dev/null +++ b/src/core/tests/visitors/op/fake_convert.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2018-2023 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "openvino/op/fake_convert.hpp" + +#include + +#include "visitors/visitors.hpp" + +using ov::Shape; +using ov::op::v0::Parameter; +using ov::test::NodeBuilder; + +TEST(attributes, fake_convert_v13_attributes_default) { + using ov::op::v13::FakeConvert; + NodeBuilder::get_ops().register_factory(); + const auto data = std::make_shared(ov::element::f32, ov::PartialShape{2, 3, 8, 6}); + const auto scale = std::make_shared(ov::element::f32, ov::PartialShape{}); + const auto shift = std::make_shared(ov::element::f32, ov::PartialShape{}); + + const auto op = std::make_shared(data, scale, shift); + + NodeBuilder builder(op, {data, scale, shift}); + auto g_op = ov::as_type_ptr(builder.create()); + + EXPECT_EQ(g_op->get_destination_type(), op->get_destination_type()); + EXPECT_EQ(g_op->get_output_element_type(0), op->get_output_element_type(0)); + EXPECT_EQ(g_op->get_output_partial_shape(0), op->get_output_partial_shape(0)); +} + +TEST(attributes, fake_convert_v13_attributes_custom) { + using ov::op::v13::FakeConvert; + NodeBuilder::get_ops().register_factory(); + const auto data = std::make_shared(ov::element::f32, ov::PartialShape{2, 3, 8, 6}); + const auto scale = std::make_shared(ov::element::f32, ov::PartialShape{}); + const auto shift = std::make_shared(ov::element::f32, ov::PartialShape{}); + + const auto op = std::make_shared(data, scale, shift, "f8e5m2"); + + NodeBuilder builder(op, {data, scale, shift}); + auto g_op = ov::as_type_ptr(builder.create()); + + EXPECT_EQ(g_op->get_destination_type(), op->get_destination_type()); + EXPECT_EQ(g_op->get_output_element_type(0), op->get_output_element_type(0)); + EXPECT_EQ(g_op->get_output_partial_shape(0), op->get_output_partial_shape(0)); +} diff --git a/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp b/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp index bf6ec48e210a3c..950138e2b7fb7f 100644 --- a/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp +++ b/src/tests/functional/plugin/conformance/test_runner/op_conformance_runner/src/op_impl_check/single_op_graph.cpp @@ -1291,6 +1291,15 @@ std::shared_ptr generate(const std::shared_ptr(results, ov::ParameterVector{param}, "BitwiseNotGraph"); } +std::shared_ptr generate(const std::shared_ptr& node) { + const auto data = std::make_shared(ov::element::f32, ov::PartialShape{2, 3, 8, 6}); + const auto scale = std::make_shared(ov::element::f32, ov::PartialShape{}); + const auto shift = std::make_shared(ov::element::f32, ov::PartialShape{}); + const auto op = std::make_shared(data, scale, shift, "f8e4m3"); + ov::ResultVector results{std::make_shared(op)}; + return std::make_shared(results, ov::ParameterVector{data, scale, shift}, "FakeConvert"); +} + std::shared_ptr generateArithmeticReductionKeepDims(const std::shared_ptr &node) { const auto data = std::make_shared(ov::element::f32, ov::PartialShape{3, 3}); const auto axes = ov::op::v0::Constant::create(ov::element::i32, {1}, {1});