diff --git a/model-optimizer/mo/main.py b/model-optimizer/mo/main.py index 7b1ba2d47a0..d5b7657ce76 100644 --- a/model-optimizer/mo/main.py +++ b/model-optimizer/mo/main.py @@ -45,7 +45,7 @@ from mo.utils.versions_checker import check_requirements # pylint: disable=no-n from mo.utils.telemetry_utils import get_tid # pylint: disable=no-name-in-module,import-error -from ngraph.frontend import FrontEndManager +from ngraph.frontend import FrontEndManager, TelemetryExtension def replace_ext(name: str, old: str, new: str): @@ -316,13 +316,17 @@ def arguments_post_parsing(argv: argparse.Namespace): def prepare_ir(argv): argv = arguments_post_parsing(argv) + t = tm.Telemetry() graph = None ngraph_function = None moc_front_end, available_moc_front_ends = get_moc_frontends(argv) if moc_front_end: + t.send_event("mo", "conversion_method", moc_front_end.get_name() + "_frontend") + moc_front_end.add_extension(TelemetryExtension("mo", t.send_event, t.send_error, t.send_stack_trace)) ngraph_function = moc_pipeline(argv, moc_front_end) else: + t.send_event("mo", "conversion_method", "mo_legacy") graph = unified_pipeline(argv) return graph, ngraph_function diff --git a/src/bindings/python/src/compatibility/ngraph/frontend/__init__.py b/src/bindings/python/src/compatibility/ngraph/frontend/__init__.py index 72bd47445af..339887581e6 100644 --- a/src/bindings/python/src/compatibility/ngraph/frontend/__init__.py +++ b/src/bindings/python/src/compatibility/ngraph/frontend/__init__.py @@ -14,6 +14,8 @@ from _pyngraph import FrontEnd from _pyngraph import InputModel from _pyngraph import Place +from _pyngraph import TelemetryExtension + # exceptions from _pyngraph import NotImplementedFailure from _pyngraph import InitializationFailure diff --git a/src/bindings/python/src/compatibility/pyngraph/frontend/frontend.cpp b/src/bindings/python/src/compatibility/pyngraph/frontend/frontend.cpp index 1ced4b6fe02..e1233b36a40 100644 --- a/src/bindings/python/src/compatibility/pyngraph/frontend/frontend.cpp +++ b/src/bindings/python/src/compatibility/pyngraph/frontend/frontend.cpp @@ -2,27 +2,26 @@ // SPDX-License-Identifier: Apache-2.0 // +#include #include #include #include #include "common/frontend_exceptions.hpp" -#include "frontend_manager.hpp" +#include "common/telemetry_extension.hpp" #include "manager.hpp" -#include "pyngraph/function.hpp" namespace py = pybind11; +using namespace ov::frontend; + void regclass_pyngraph_FrontEnd(py::module m) { - py::class_> fem(m, - "FrontEnd", - py::dynamic_attr(), - py::module_local()); + py::class_> fem(m, "FrontEnd", py::dynamic_attr(), py::module_local()); fem.doc() = "ngraph.impl.FrontEnd wraps ngraph::frontend::FrontEnd"; fem.def( "load", - [](ov::frontend::FrontEnd& self, const std::string& s) { + [](FrontEnd& self, const std::string& s) { return self.load(s); }, py::arg("path"), @@ -40,12 +39,10 @@ void regclass_pyngraph_FrontEnd(py::module m) { Loaded input model. )"); - fem.def( - "convert", - static_cast (ov::frontend::FrontEnd::*)(ov::frontend::InputModel::Ptr) const>( - &ov::frontend::FrontEnd::convert), - py::arg("model"), - R"( + fem.def("convert", + static_cast (FrontEnd::*)(InputModel::Ptr) const>(&FrontEnd::convert), + py::arg("model"), + R"( Completely convert and normalize entire function, throws if it is not possible. Parameters @@ -60,8 +57,7 @@ void regclass_pyngraph_FrontEnd(py::module m) { )"); fem.def("convert", - static_cast) const>( - &ov::frontend::FrontEnd::convert), + static_cast) const>(&FrontEnd::convert), py::arg("function"), R"( Completely convert the remaining, not converted part of a function. @@ -78,7 +74,7 @@ void regclass_pyngraph_FrontEnd(py::module m) { )"); fem.def("convert_partially", - &ov::frontend::FrontEnd::convert_partially, + &FrontEnd::convert_partially, py::arg("model"), R"( Convert only those parts of the model that can be converted leaving others as-is. @@ -97,7 +93,7 @@ void regclass_pyngraph_FrontEnd(py::module m) { )"); fem.def("decode", - &ov::frontend::FrontEnd::decode, + &FrontEnd::decode, py::arg("model"), R"( Convert operations with one-to-one mapping with decoding nodes. @@ -116,7 +112,7 @@ void regclass_pyngraph_FrontEnd(py::module m) { )"); fem.def("normalize", - &ov::frontend::FrontEnd::normalize, + &FrontEnd::normalize, py::arg("function"), R"( Runs normalization passes on function that was loaded with partial conversion. @@ -128,7 +124,7 @@ void regclass_pyngraph_FrontEnd(py::module m) { )"); fem.def("get_name", - &ov::frontend::FrontEnd::get_name, + &FrontEnd::get_name, R"( Gets name of this FrontEnd. Can be used by clients if frontend is selected automatically by FrontEndManager::load_by_model. @@ -139,7 +135,33 @@ void regclass_pyngraph_FrontEnd(py::module m) { Current frontend name. Empty string if not implemented. )"); - fem.def("__repr__", [](const ov::frontend::FrontEnd& self) -> std::string { + fem.def("add_extension", + static_cast& extension)>(&FrontEnd::add_extension)); + + fem.def("__repr__", [](const FrontEnd& self) -> std::string { return ""; }); } + +void regclass_pyngraph_Extension(py::module m) { + py::class_> ext(m, "Extension", py::dynamic_attr()); +} + +void regclass_pyngraph_TelemetryExtension(py::module m) { + { + py::class_, ov::Extension> ext(m, + "TelemetryExtension", + py::dynamic_attr()); + + ext.def(py::init([](const std::string& event_category, + const TelemetryExtension::event_callback& send_event, + const TelemetryExtension::error_callback& send_error, + const TelemetryExtension::error_callback& send_stack_trace) { + return std::make_shared(event_category, send_event, send_error, send_stack_trace); + })); + + ext.def("send_event", &TelemetryExtension::send_event); + ext.def("send_error", &TelemetryExtension::send_error); + ext.def("send_stack_trace", &TelemetryExtension::send_stack_trace); + } +} diff --git a/src/bindings/python/src/compatibility/pyngraph/frontend/frontend.hpp b/src/bindings/python/src/compatibility/pyngraph/frontend/frontend.hpp index de28e950bb5..442cc3ffcd4 100644 --- a/src/bindings/python/src/compatibility/pyngraph/frontend/frontend.hpp +++ b/src/bindings/python/src/compatibility/pyngraph/frontend/frontend.hpp @@ -9,3 +9,5 @@ namespace py = pybind11; void regclass_pyngraph_FrontEnd(py::module m); +void regclass_pyngraph_Extension(py::module m); +void regclass_pyngraph_TelemetryExtension(py::module m); diff --git a/src/bindings/python/src/compatibility/pyngraph/pyngraph.cpp b/src/bindings/python/src/compatibility/pyngraph/pyngraph.cpp index bbd3dc049cc..5f5e0433315 100644 --- a/src/bindings/python/src/compatibility/pyngraph/pyngraph.cpp +++ b/src/bindings/python/src/compatibility/pyngraph/pyngraph.cpp @@ -50,6 +50,8 @@ PYBIND11_MODULE(_pyngraph, m) { regclass_pyngraph_NotImplementedFailureFrontEnd(m); regclass_pyngraph_FrontEndManager(m); regclass_pyngraph_FrontEnd(m); + regclass_pyngraph_Extension(m); + regclass_pyngraph_TelemetryExtension(m); regclass_pyngraph_InputModel(m); regclass_pyngraph_Input(m); regclass_pyngraph_Output(m); diff --git a/src/core/tests/frontend/onnx/telemetry.cpp b/src/core/tests/frontend/onnx/telemetry.cpp new file mode 100644 index 00000000000..a1f7fd3019e --- /dev/null +++ b/src/core/tests/frontend/onnx/telemetry.cpp @@ -0,0 +1,29 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "telemetry.hpp" + +#include "onnx_utils.hpp" + +using namespace ov::frontend; + +using ONNXTelemetryTest = FrontEndTelemetryTest; + +static TelemetryFEParam getTestData() { + TelemetryFEParam res; + res.m_frontEndName = ONNX_FE; + res.m_modelsPath = std::string(TEST_ONNX_MODELS_DIRNAME); + res.m_modelName = "controlflow/loop_2d_add.onnx"; + res.m_expected_events = { + std::make_tuple("mo", "op_count", "onnx_Loop", 1), + std::make_tuple("mo", "op_count", "onnx_Add", 1), + std::make_tuple("mo", "op_count", "onnx_Identity", 2), + }; + return res; +} + +INSTANTIATE_TEST_SUITE_P(ONNXTelemetryTest, + FrontEndTelemetryTest, + ::testing::Values(getTestData()), + FrontEndTelemetryTest::getTestCaseName); diff --git a/src/core/tests/frontend/paddlepaddle/telemetry.cpp b/src/core/tests/frontend/paddlepaddle/telemetry.cpp new file mode 100644 index 00000000000..9a7f22f6567 --- /dev/null +++ b/src/core/tests/frontend/paddlepaddle/telemetry.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "telemetry.hpp" + +#include "paddle_utils.hpp" + +using namespace ov::frontend; + +using PDPDTelemetryTest = FrontEndTelemetryTest; + +static TelemetryFEParam getTestData() { + TelemetryFEParam res; + res.m_frontEndName = PADDLE_FE; + res.m_modelsPath = std::string(TEST_PADDLE_MODELS_DIRNAME); + res.m_modelName = "relu/relu.pdmodel"; + res.m_expected_events = {std::make_tuple("mo", "op_count", "paddle_feed", 1), + std::make_tuple("mo", "op_count", "paddle_fetch", 1), + std::make_tuple("mo", "op_count", "paddle_relu", 1), + std::make_tuple("mo", "op_count", "paddle_scale", 1)}; + return res; +} + +INSTANTIATE_TEST_SUITE_P(PDPDTelemetryTest, + FrontEndTelemetryTest, + ::testing::Values(getTestData()), + FrontEndTelemetryTest::getTestCaseName); diff --git a/src/core/tests/frontend/shared/include/telemetry.hpp b/src/core/tests/frontend/shared/include/telemetry.hpp new file mode 100644 index 00000000000..770967455f2 --- /dev/null +++ b/src/core/tests/frontend/shared/include/telemetry.hpp @@ -0,0 +1,63 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include + +#include + +class TelemetryMock { +public: + TelemetryMock() = default; + ~TelemetryMock() = default; + + void send_event(const std::string& category, const std::string& action, const std::string& label, int value = 1) { + m_event_cnt++; + m_received_events.insert(std::make_tuple(category, action, label, value)); + } + + void send_error(const std::string& category, const std::string& error_message) { + m_error_cnt++; + m_last_error = std::make_tuple(category, error_message); + } + + void send_stack_trace(const std::string& category, const std::string& error_message) { + m_trace_cnt++; + m_last_trace = std::make_tuple(category, error_message); + } + + void clear() { + m_event_cnt = 0; + m_error_cnt = 0; + m_trace_cnt = 0; + m_received_events.clear(); + } + uint64_t m_event_cnt = 0, m_error_cnt = 0, m_trace_cnt = 0; + + std::set> m_received_events; + std::tuple m_last_error; + std::tuple m_last_trace; +}; + +struct TelemetryFEParam { + std::string m_frontEndName; + std::string m_modelsPath; + std::string m_modelName; + std::set> m_expected_events; +}; + +class FrontEndTelemetryTest : public ::testing::TestWithParam { +public: + TelemetryMock m_test_telemetry; + TelemetryFEParam m_param; + ov::frontend::FrontEndManager m_fem; + + static std::string getTestCaseName(const testing::TestParamInfo& obj); + + void SetUp() override; + +protected: + void initParamTest(); +}; diff --git a/src/core/tests/frontend/shared/src/telemetry.cpp b/src/core/tests/frontend/shared/src/telemetry.cpp new file mode 100644 index 00000000000..0802f8c8f98 --- /dev/null +++ b/src/core/tests/frontend/shared/src/telemetry.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "telemetry.hpp" + +#include + +#include "utils.hpp" + +using namespace ov::frontend; + +std::string FrontEndTelemetryTest::getTestCaseName(const testing::TestParamInfo& obj) { + std::string res = obj.param.m_frontEndName + "_" + obj.param.m_modelName; + return FrontEndTestUtils::fileToTestName(res); +} + +void FrontEndTelemetryTest::SetUp() { + FrontEndTestUtils::setupTestEnv(); + m_fem = FrontEndManager(); // re-initialize after setting up environment + initParamTest(); +} + +void FrontEndTelemetryTest::initParamTest() { + m_param = GetParam(); + m_param.m_modelName = FrontEndTestUtils::make_model_path(m_param.m_modelsPath + m_param.m_modelName); +} + +/////////////////////////////////////////////////////////////////// + +TEST_P(FrontEndTelemetryTest, TestTelemetryMock) { + std::shared_ptr function; + { + using namespace std::placeholders; + ov::frontend::FrontEnd::Ptr m_frontEnd; + ov::frontend::InputModel::Ptr m_inputModel; + m_frontEnd = m_fem.load_by_framework(m_param.m_frontEndName); + std::string category = "mo"; + auto telemetry_extension = std::make_shared( + category, + std::bind(&TelemetryMock::send_event, &m_test_telemetry, _1, _2, _3, _4), + std::bind(&TelemetryMock::send_error, &m_test_telemetry, _1, _2), + std::bind(&TelemetryMock::send_stack_trace, &m_test_telemetry, _1, _2)); + + std::string action = "test_action"; + std::string msg = "test_msg"; + int version = 2; + EXPECT_NO_THROW(telemetry_extension->send_event(action, msg, version)); + EXPECT_NO_THROW(telemetry_extension->send_error(msg)); + EXPECT_NO_THROW(telemetry_extension->send_stack_trace(msg)); + + EXPECT_EQ(m_test_telemetry.m_event_cnt, 1); + EXPECT_EQ(m_test_telemetry.m_error_cnt, 1); + EXPECT_EQ(m_test_telemetry.m_trace_cnt, 1); + + auto expected_res = std::set>{ + std::make_tuple(category, action, msg, version)}; + EXPECT_EQ(m_test_telemetry.m_received_events, expected_res); + EXPECT_EQ(m_test_telemetry.m_last_error, std::make_tuple(category, msg)); + EXPECT_EQ(m_test_telemetry.m_last_trace, std::make_tuple(category, msg)); + + m_test_telemetry.clear(); + + EXPECT_NO_THROW(m_frontEnd->add_extension(telemetry_extension)); + m_inputModel = m_frontEnd->load(m_param.m_modelName); + function = m_frontEnd->convert(m_inputModel); + EXPECT_EQ(m_test_telemetry.m_event_cnt, m_param.m_expected_events.size()); + EXPECT_EQ(m_test_telemetry.m_received_events, m_param.m_expected_events); + EXPECT_EQ(m_test_telemetry.m_trace_cnt, 0); + EXPECT_EQ(m_test_telemetry.m_error_cnt, 0); + + m_test_telemetry.clear(); + + EXPECT_NO_THROW(m_frontEnd->add_extension(telemetry_extension)); + m_inputModel = m_frontEnd->load(m_param.m_modelName); + function = m_frontEnd->decode(m_inputModel); + EXPECT_EQ(m_test_telemetry.m_event_cnt, m_param.m_expected_events.size()); + EXPECT_EQ(m_test_telemetry.m_received_events, m_param.m_expected_events); + EXPECT_EQ(m_test_telemetry.m_trace_cnt, 0); + EXPECT_EQ(m_test_telemetry.m_error_cnt, 0); + } +} diff --git a/src/core/tests/frontend/tensorflow/telemetry.cpp b/src/core/tests/frontend/tensorflow/telemetry.cpp new file mode 100644 index 00000000000..92d5108a8fa --- /dev/null +++ b/src/core/tests/frontend/tensorflow/telemetry.cpp @@ -0,0 +1,31 @@ +// Copyright (C) 2018-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "telemetry.hpp" + +#include "tf_utils.hpp" + +using namespace ov::frontend; + +using TFTelemetryTest = FrontEndTelemetryTest; + +static TelemetryFEParam getTestData() { + TelemetryFEParam res; + res.m_frontEndName = TF_FE; + res.m_modelsPath = std::string(TEST_TENSORFLOW_MODELS_DIRNAME); + res.m_modelName = "2in_2out/2in_2out.pb"; + + res.m_expected_events = {std::make_tuple("mo", "op_count", "tf_Add", 2), + std::make_tuple("mo", "op_count", "tf_Const", 2), + std::make_tuple("mo", "op_count", "tf_Conv2D", 2), + std::make_tuple("mo", "op_count", "tf_NoOp", 1), + std::make_tuple("mo", "op_count", "tf_Placeholder", 2), + std::make_tuple("mo", "op_count", "tf_Relu", 4)}; + return res; +} + +INSTANTIATE_TEST_SUITE_P(TFTelemetryTest, + FrontEndTelemetryTest, + ::testing::Values(getTestData()), + FrontEndTelemetryTest::getTestCaseName); diff --git a/src/frontends/common/include/common/telemetry_extension.hpp b/src/frontends/common/include/common/telemetry_extension.hpp new file mode 100644 index 00000000000..914ad41c4bb --- /dev/null +++ b/src/frontends/common/include/common/telemetry_extension.hpp @@ -0,0 +1,43 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#pragma once + +#include +#include +#include + +#include "frontend_defs.hpp" +#include "openvino/core/extension.hpp" +#include "openvino/pass/graph_rewrite.hpp" +#include "openvino/pass/manager.hpp" +#include "openvino/pass/pass.hpp" + +namespace ov { +namespace frontend { + +/// \brief Provides callback to report telemetry information back to Python code +class FRONTEND_API TelemetryExtension : public ov::Extension { +public: + using error_callback = std::function; + using event_callback = std::function< + void(const std::string& category, const std::string& action, const std::string& label, int value)>; + TelemetryExtension(const std::string& event_category, + const event_callback& send_event, + const error_callback& send_error, + const error_callback& send_stack_trace); + + void send_event(const std::string& action, const std::string& label, int value = 1); + void send_error(const std::string& error_message); + void send_stack_trace(const std::string& error_message); + +private: + std::string m_event_category; + event_callback m_send_event; + error_callback m_send_error; + error_callback m_send_stack_trace; +}; + +} // namespace frontend +} // namespace ov diff --git a/src/frontends/common/src/frontend_manager.cpp b/src/frontends/common/src/frontend_manager.cpp index 88fd8b7d262..313d1b56f4f 100644 --- a/src/frontends/common/src/frontend_manager.cpp +++ b/src/frontends/common/src/frontend_manager.cpp @@ -149,6 +149,7 @@ void FrontEnd::normalize(std::shared_ptr function) const { } void FrontEnd::add_extension(const std::shared_ptr& extension) { + // Left unimplemented intentionally. // Each frontend can support own set of extensions, so this method should be implemented on the frontend side } diff --git a/src/frontends/common/src/telemetry_extension.cpp b/src/frontends/common/src/telemetry_extension.cpp new file mode 100644 index 00000000000..134836ac701 --- /dev/null +++ b/src/frontends/common/src/telemetry_extension.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 +// + +#include "common/telemetry_extension.hpp" + +using namespace ov::frontend; + +ov::frontend::TelemetryExtension::TelemetryExtension(const std::string& event_category, + const TelemetryExtension::event_callback& send_event, + const TelemetryExtension::error_callback& send_error, + const TelemetryExtension::error_callback& send_stack_trace) + : m_event_category(event_category), + m_send_event(send_event), + m_send_error(send_error), + m_send_stack_trace(send_stack_trace) {} + +void ov::frontend::TelemetryExtension::send_event(const std::string& action, const std::string& label, int value) { + if (m_send_event) { + m_send_event(m_event_category, action, label, value); + } +} + +void ov::frontend::TelemetryExtension::send_error(const std::string& error_message) { + if (m_send_error) { + m_send_error(m_event_category, error_message); + } +} + +void ov::frontend::TelemetryExtension::send_stack_trace(const std::string& error_message) { + if (m_send_stack_trace) { + m_send_stack_trace(m_event_category, error_message); + } +} diff --git a/src/frontends/ir/include/ir_frontend/frontend.hpp b/src/frontends/ir/include/ir_frontend/frontend.hpp index 5497503d2bd..f5a85ea86c5 100644 --- a/src/frontends/ir/include/ir_frontend/frontend.hpp +++ b/src/frontends/ir/include/ir_frontend/frontend.hpp @@ -5,6 +5,7 @@ #pragma once #include "common/frontend.hpp" +#include "common/telemetry_extension.hpp" #include "openvino/core/variant.hpp" #include "utility.hpp" @@ -44,6 +45,7 @@ protected: private: std::vector> shared_objects; std::vector extensions; + std::shared_ptr m_telemetry; }; } // namespace frontend diff --git a/src/frontends/ir/src/frontend.cpp b/src/frontends/ir/src/frontend.cpp index d7a7cc15ba3..413c628d93b 100644 --- a/src/frontends/ir/src/frontend.cpp +++ b/src/frontends/ir/src/frontend.cpp @@ -100,13 +100,14 @@ bool FrontEndIR::supported_impl(const std::vector>& var } void FrontEndIR::add_extension(const ov::Extension::Ptr& ext) { - if (auto so_ext = std::dynamic_pointer_cast(ext)) { + if (auto telemetry = std::dynamic_pointer_cast(ext)) { + m_telemetry = telemetry; + } else if (auto so_ext = std::dynamic_pointer_cast(ext)) { if (std::dynamic_pointer_cast(so_ext->extension())) { shared_objects.emplace_back(so_ext->shared_object()); extensions.emplace_back(so_ext->extension()); } - } - if (std::dynamic_pointer_cast(ext)) + } else if (std::dynamic_pointer_cast(ext)) extensions.emplace_back(ext); } diff --git a/src/frontends/onnx/frontend/include/onnx_frontend/frontend.hpp b/src/frontends/onnx/frontend/include/onnx_frontend/frontend.hpp index ddd1ef66b4e..d35f3485daf 100644 --- a/src/frontends/onnx/frontend/include/onnx_frontend/frontend.hpp +++ b/src/frontends/onnx/frontend/include/onnx_frontend/frontend.hpp @@ -28,9 +28,13 @@ public: std::shared_ptr decode(InputModel::Ptr model) const override; std::string get_name() const override; bool supported_impl(const std::vector>& variants) const override; + void add_extension(const std::shared_ptr& extension) override; protected: InputModel::Ptr load_impl(const std::vector>& params) const override; + +private: + std::shared_ptr m_telemetry; }; } // namespace frontend diff --git a/src/frontends/onnx/frontend/src/core/graph.cpp b/src/frontends/onnx/frontend/src/core/graph.cpp index 51d1d3772b5..c57d434f53b 100644 --- a/src/frontends/onnx/frontend/src/core/graph.cpp +++ b/src/frontends/onnx/frontend/src/core/graph.cpp @@ -47,12 +47,16 @@ static std::string get_op_domain_and_name(const ONNX_NAMESPACE::NodeProto& node_ } } // namespace detail -Graph::Graph(std::shared_ptr model_proto) - : Graph(model_proto, common::make_unique()) {} +Graph::Graph(const std::shared_ptr& model_proto, + const std::shared_ptr& telemetry) + : Graph(model_proto, common::make_unique(), telemetry) {} -Graph::Graph(std::shared_ptr model_proto, std::unique_ptr&& cache) +Graph::Graph(const std::shared_ptr& model_proto, + std::unique_ptr&& cache, + const std::shared_ptr& telemetry) : m_model{common::make_unique(model_proto)}, - m_cache{std::move(cache)} { + m_cache{std::move(cache)}, + m_telemetry(telemetry) { std::map initializers; // Process all initializers in the graph for (const auto& initializer_tensor : m_model->get_graph().initializer()) { @@ -96,7 +100,11 @@ Graph::Graph(std::shared_ptr model_proto, std::uniqu // Verify that ONNX graph contains only nodes of available operator types std::map> unknown_operators; + std::map op_statistics; for (const auto& node_proto : m_model->get_graph().node()) { + if (telemetry) { + op_statistics[node_proto.op_type()]++; + } if (!m_model->is_operator_available(node_proto)) { unknown_operators.emplace(detail::get_op_domain_and_name(node_proto), node_proto); // If a node from an unregistered domain is detected, try registering that @@ -105,6 +113,12 @@ Graph::Graph(std::shared_ptr model_proto, std::uniqu } } + if (telemetry) { + for (const auto& op : op_statistics) { + telemetry->send_event("op_count", "onnx_" + op.first, op.second); + } + } + // Reverify wheter we still have any unavailable operators. auto it = std::begin(unknown_operators); while (it != std::end(unknown_operators)) { @@ -297,7 +311,7 @@ const OpsetImports& Graph::get_opset_imports() const { } Subgraph::Subgraph(std::shared_ptr model_proto, const Graph* parent_graph) - : Graph(model_proto, common::make_unique()), + : Graph(model_proto, common::make_unique(), parent_graph->get_telemetry()), m_parent_graph(parent_graph) {} bool Subgraph::is_ng_node_in_cache(const std::string& name) const { diff --git a/src/frontends/onnx/frontend/src/core/graph.hpp b/src/frontends/onnx/frontend/src/core/graph.hpp index 831710e9226..fd1f145b384 100644 --- a/src/frontends/onnx/frontend/src/core/graph.hpp +++ b/src/frontends/onnx/frontend/src/core/graph.hpp @@ -10,6 +10,7 @@ #include #include +#include "common/telemetry_extension.hpp" #include "core/graph_cache.hpp" #include "core/model.hpp" #include "ngraph/function.hpp" @@ -20,7 +21,8 @@ namespace ngraph { namespace onnx_import { class Graph : public std::enable_shared_from_this { public: - Graph(std::shared_ptr model_proto); + Graph(const std::shared_ptr& model_proto2, + const std::shared_ptr& telemetry = {}); Graph() = delete; Graph(const Graph&) = delete; @@ -43,8 +45,14 @@ public: const OpsetImports& get_opset_imports() const; virtual ~Graph() = default; + const std::shared_ptr& get_telemetry() const { + return m_telemetry; + } + protected: - Graph(std::shared_ptr model, std::unique_ptr&& cache); + Graph(const std::shared_ptr& model, + std::unique_ptr&& cache, + const std::shared_ptr& telemetry = {}); void set_friendly_names(const Node& onnx_node, const OutputVector& ng_node_vector) const; @@ -60,6 +68,7 @@ protected: private: std::vector m_nodes; + std::shared_ptr m_telemetry; }; /// \brief Representation of ONNX subgraph. It is used for example by ONNX Loop op. diff --git a/src/frontends/onnx/frontend/src/editor.cpp b/src/frontends/onnx/frontend/src/editor.cpp index 3ed788fb8e9..b0a5706cc27 100644 --- a/src/frontends/onnx/frontend/src/editor.cpp +++ b/src/frontends/onnx/frontend/src/editor.cpp @@ -220,22 +220,29 @@ struct onnx_editor::ONNXModelEditor::Impl { #endif }; -onnx_editor::ONNXModelEditor::ONNXModelEditor(const std::string& model_path) +onnx_editor::ONNXModelEditor::ONNXModelEditor(const std::string& model_path, + const std::shared_ptr& telemetry) : m_model_path{model_path}, + m_telemetry(telemetry), m_pimpl{new ONNXModelEditor::Impl{model_path}, [](Impl* impl) { delete impl; }} {} #if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32) -onnx_editor::ONNXModelEditor::ONNXModelEditor(const std::wstring& model_path) +onnx_editor::ONNXModelEditor::ONNXModelEditor(const std::wstring& model_path, + const std::shared_ptr& telemetry) : m_model_path{ngraph::file_util::wstring_to_string(model_path)}, + m_telemetry(telemetry), m_pimpl{new ONNXModelEditor::Impl{model_path}, [](Impl* impl) { delete impl; }} {} #endif -onnx_editor::ONNXModelEditor::ONNXModelEditor(std::istream& model_stream, const std::string& model_path) +onnx_editor::ONNXModelEditor::ONNXModelEditor(std::istream& model_stream, + const std::string& model_path, + const std::shared_ptr& telemetry) : m_model_path{model_path}, + m_telemetry(telemetry), m_pimpl{new ONNXModelEditor::Impl{model_stream}, [](Impl* impl) { delete impl; }} {} @@ -408,7 +415,7 @@ std::string onnx_editor::ONNXModelEditor::model_string() const { } std::shared_ptr onnx_editor::ONNXModelEditor::get_function() const { - return ngraph::onnx_import::detail::import_onnx_model(m_pimpl->m_model_proto, m_model_path); + return ngraph::onnx_import::detail::import_onnx_model(m_pimpl->m_model_proto, m_model_path, m_telemetry); } void onnx_editor::ONNXModelEditor::set_input_values( @@ -587,5 +594,5 @@ std::vector onnx_editor::ONNXModelEditor::get_output_ports(const Ed } std::shared_ptr onnx_editor::ONNXModelEditor::decode() { - return ngraph::onnx_import::detail::decode_to_framework_nodes(m_pimpl->m_model_proto, m_model_path); + return ngraph::onnx_import::detail::decode_to_framework_nodes(m_pimpl->m_model_proto, m_model_path, m_telemetry); } diff --git a/src/frontends/onnx/frontend/src/editor.hpp b/src/frontends/onnx/frontend/src/editor.hpp index 4d997d7ae61..05932132276 100644 --- a/src/frontends/onnx/frontend/src/editor.hpp +++ b/src/frontends/onnx/frontend/src/editor.hpp @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -28,9 +29,11 @@ public: /// is parsed and loaded into the m_model_proto member variable. /// /// \param model_path Path to the file containing the model. - ONNXModelEditor(const std::string& model_path); + ONNXModelEditor(const std::string& model_path, + const std::shared_ptr& telemetry = {}); #if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32) - ONNXModelEditor(const std::wstring& model_path); + ONNXModelEditor(const std::wstring& model_path, + const std::shared_ptr& telemetry = {}); #endif /// \brief Creates an editor from a model stream. The stream is parsed and loaded @@ -39,7 +42,9 @@ public: /// \param model_stream The stream containing the model. /// \param model_path Path to the file containing the model. This information can be used /// for ONNX external weights feature support. - ONNXModelEditor(std::istream& model_stream, const std::string& path = ""); + ONNXModelEditor(std::istream& model_stream, + const std::string& path = "", + const std::shared_ptr& telemetry = {}); /// \brief Modifies the in-memory representation of the model by setting /// custom input types for all inputs specified in the provided map. @@ -269,6 +274,7 @@ public: private: void update_mapper_if_needed() const; + std::shared_ptr m_telemetry; const std::string m_model_path; struct Impl; diff --git a/src/frontends/onnx/frontend/src/frontend.cpp b/src/frontends/onnx/frontend/src/frontend.cpp index 8f9b333a074..db73a7fde03 100644 --- a/src/frontends/onnx/frontend/src/frontend.cpp +++ b/src/frontends/onnx/frontend/src/frontend.cpp @@ -3,6 +3,7 @@ // #include +#include #include #include #include @@ -39,27 +40,27 @@ InputModel::Ptr FrontEndONNX::load_impl(const std::vector(variants[0])) { const auto path = ov::as_type_ptr(variants[0])->get(); - return std::make_shared(path); + return std::make_shared(path, m_telemetry); } #if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32) if (ov::is_type(variants[0])) { const auto path = ov::as_type_ptr(variants[0])->get(); - return std::make_shared(path); + return std::make_shared(path, m_telemetry); } #endif if (ov::is_type(variants[0])) { const auto stream = ov::as_type_ptr(variants[0])->get(); if (variants.size() > 1 && ov::is_type(variants[1])) { const auto path = ov::as_type_ptr(variants[1])->get(); - return std::make_shared(*stream, path); + return std::make_shared(*stream, path, m_telemetry); } #if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32) if (variants.size() > 1 && ov::is_type(variants[1])) { const auto path = ov::as_type_ptr(variants[1])->get(); - return std::make_shared(*stream, path); + return std::make_shared(*stream, path, m_telemetry); } #endif - return std::make_shared(*stream); + return std::make_shared(*stream, m_telemetry); } return nullptr; } @@ -134,3 +135,9 @@ bool FrontEndONNX::supported_impl(const std::vector>& v } return false; } + +void FrontEndONNX::add_extension(const std::shared_ptr& extension) { + if (auto telemetry = std::dynamic_pointer_cast(extension)) { + m_telemetry = telemetry; + } +} diff --git a/src/frontends/onnx/frontend/src/input_model.cpp b/src/frontends/onnx/frontend/src/input_model.cpp index 7e461f02253..e0ffcf29e3b 100644 --- a/src/frontends/onnx/frontend/src/input_model.cpp +++ b/src/frontends/onnx/frontend/src/input_model.cpp @@ -14,23 +14,30 @@ using namespace ov::frontend; NGRAPH_SUPPRESS_DEPRECATED_START -InputModelONNX::InputModelONNX(const std::string& path) - : m_editor{std::make_shared(path)} {} +InputModelONNX::InputModelONNX(const std::string& path, + const std::shared_ptr& telemetry) + : m_editor{std::make_shared(path, telemetry)} {} #if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32) -InputModelONNX::InputModelONNX(const std::wstring& path) - : m_editor{std::make_shared(path)} {} +InputModelONNX::InputModelONNX(const std::wstring& path, + const std::shared_ptr& telemetry) + : m_editor{std::make_shared(path, telemetry)} {} #endif -InputModelONNX::InputModelONNX(std::istream& model_stream) - : m_editor{std::make_shared(model_stream)} {} +InputModelONNX::InputModelONNX(std::istream& model_stream, + const std::shared_ptr& telemetry) + : m_editor{std::make_shared(model_stream, "", telemetry)} {} -InputModelONNX::InputModelONNX(std::istream& model_stream, const std::string& path) - : m_editor{std::make_shared(model_stream, path)} {} +InputModelONNX::InputModelONNX(std::istream& model_stream, + const std::string& path, + const std::shared_ptr& telemetry) + : m_editor{std::make_shared(model_stream, path, telemetry)} {} #ifdef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT -InputModelONNX::InputModelONNX(std::istream& model_stream, const std::wstring& path) - : InputModelONNX(model_stream, ov::util::wstring_to_string(path)) {} +InputModelONNX::InputModelONNX(std::istream& model_stream, + const std::wstring& path, + const std::shared_ptr& telemetry) + : InputModelONNX(model_stream, ov::util::wstring_to_string(path), telemetry) {} #endif std::vector InputModelONNX::get_inputs() const { diff --git a/src/frontends/onnx/frontend/src/input_model.hpp b/src/frontends/onnx/frontend/src/input_model.hpp index 65b0802b02d..27cd34ec0bb 100644 --- a/src/frontends/onnx/frontend/src/input_model.hpp +++ b/src/frontends/onnx/frontend/src/input_model.hpp @@ -12,16 +12,20 @@ namespace ov { namespace frontend { class InputModelONNX : public InputModel { public: - InputModelONNX(const std::string& path); + InputModelONNX(const std::string& path, const std::shared_ptr& telemetry = {}); #if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32) - InputModelONNX(const std::wstring& path); + InputModelONNX(const std::wstring& path, const std::shared_ptr& telemetry = {}); #endif - InputModelONNX(std::istream& model_stream); + InputModelONNX(std::istream& model_stream, const std::shared_ptr& telemetry = {}); // The path can be required even if the model is passed as a stream because it is necessary // for ONNX external data feature - InputModelONNX(std::istream& model_stream, const std::string& path); + InputModelONNX(std::istream& model_stream, + const std::string& path, + const std::shared_ptr& telemetry = {}); #ifdef OPENVINO_ENABLE_UNICODE_PATH_SUPPORT - InputModelONNX(std::istream& model_stream, const std::wstring& path); + InputModelONNX(std::istream& model_stream, + const std::wstring& path, + const std::shared_ptr& telemetry = {}); #endif std::vector get_inputs() const override; diff --git a/src/frontends/onnx/frontend/src/utils/onnx_internal.cpp b/src/frontends/onnx/frontend/src/utils/onnx_internal.cpp index 4263806c796..930c8fab619 100644 --- a/src/frontends/onnx/frontend/src/utils/onnx_internal.cpp +++ b/src/frontends/onnx/frontend/src/utils/onnx_internal.cpp @@ -81,16 +81,19 @@ void convert_decoded_function(std::shared_ptr function) { } std::shared_ptr import_onnx_model(std::shared_ptr model_proto, - const std::string& model_path) { + const std::string& model_path, + const std::shared_ptr& telemetry) { apply_transformations(*model_proto, model_path); - Graph graph{model_proto}; + Graph graph{model_proto, telemetry}; return graph.convert(); } -std::shared_ptr decode_to_framework_nodes(std::shared_ptr model_proto, - const std::string& model_path) { +std::shared_ptr decode_to_framework_nodes( + std::shared_ptr model_proto, + const std::string& model_path, + const std::shared_ptr& telemetry) { apply_transformations(*model_proto, model_path); - auto graph = std::make_shared(model_proto); + auto graph = std::make_shared(model_proto, telemetry); return graph->decode(); } } // namespace detail diff --git a/src/frontends/onnx/frontend/src/utils/onnx_internal.hpp b/src/frontends/onnx/frontend/src/utils/onnx_internal.hpp index fcc463b467f..9813e82fa4b 100644 --- a/src/frontends/onnx/frontend/src/utils/onnx_internal.hpp +++ b/src/frontends/onnx/frontend/src/utils/onnx_internal.hpp @@ -7,6 +7,7 @@ #include #include +#include "common/telemetry_extension.hpp" #include "ngraph/function.hpp" namespace ONNX_NAMESPACE { @@ -32,7 +33,8 @@ namespace detail { /// \return An nGraph function that represents a single output from the created /// graph. std::shared_ptr import_onnx_model(std::shared_ptr model_proto, - const std::string& model_path); + const std::string& model_path, + const std::shared_ptr& telemetry = {}); /// \brief Decode ONNX model to nGraph function with ONNXFrameworkNode(s) /// @@ -42,8 +44,10 @@ std::shared_ptr import_onnx_model(std::shared_ptr decode_to_framework_nodes(std::shared_ptr model_proto, - const std::string& model_path); +std::shared_ptr decode_to_framework_nodes( + std::shared_ptr model_proto, + const std::string& model_path, + const std::shared_ptr& telemetry = {}); /// \brief Converts a nGraph function (onnx model decoded to function with /// ONNXFrameworkNode(s)) diff --git a/src/frontends/paddlepaddle/CMakeLists.txt b/src/frontends/paddlepaddle/CMakeLists.txt index e4d064b2388..71c82e3cdc7 100644 --- a/src/frontends/paddlepaddle/CMakeLists.txt +++ b/src/frontends/paddlepaddle/CMakeLists.txt @@ -5,5 +5,4 @@ ov_add_frontend(NAME paddlepaddle LINKABLE_FRONTEND PROTOBUF_LITE - FILEDESCRIPTION "FrontEnd to load and convert PaddlePaddle file format" - LINK_LIBRARIES ngraph::builder) + FILEDESCRIPTION "FrontEnd to load and convert PaddlePaddle file format") diff --git a/src/frontends/paddlepaddle/include/paddlepaddle_frontend/frontend.hpp b/src/frontends/paddlepaddle/include/paddlepaddle_frontend/frontend.hpp index 55275c4b6a3..2020aa00fee 100644 --- a/src/frontends/paddlepaddle/include/paddlepaddle_frontend/frontend.hpp +++ b/src/frontends/paddlepaddle/include/paddlepaddle_frontend/frontend.hpp @@ -4,6 +4,7 @@ #pragma once +#include #include #include "exceptions.hpp" @@ -47,6 +48,8 @@ public: /// \return Paddle frontend name. std::string get_name() const override; + void add_extension(const std::shared_ptr& extension) override; + protected: /// \brief Check if FrontEndPDPD can recognize model from given parts /// \param params Can be path to folder which contains __model__ file or path to @@ -66,6 +69,7 @@ private: const std::shared_ptr& model, std::function(const std::map>&, const std::shared_ptr&)> func); + std::shared_ptr m_telemetry; }; } // namespace frontend diff --git a/src/frontends/paddlepaddle/include/paddlepaddle_frontend/model.hpp b/src/frontends/paddlepaddle/include/paddlepaddle_frontend/model.hpp index abd51f0956c..8cc63a5540a 100644 --- a/src/frontends/paddlepaddle/include/paddlepaddle_frontend/model.hpp +++ b/src/frontends/paddlepaddle/include/paddlepaddle_frontend/model.hpp @@ -4,6 +4,7 @@ #pragma once +#include #include #include "paddlepaddle_frontend/utility.hpp" @@ -22,11 +23,12 @@ class PDPD_API InputModelPDPD : public InputModel { std::map> get_tensor_values() const; public: - explicit InputModelPDPD(const std::string& path); + explicit InputModelPDPD(const std::string& path, const std::shared_ptr& telemetry = {}); #if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32) - explicit InputModelPDPD(const std::wstring& path); + explicit InputModelPDPD(const std::wstring& path, const std::shared_ptr& telemetry = {}); #endif - explicit InputModelPDPD(const std::vector& streams); + explicit InputModelPDPD(const std::vector& streams, + const std::shared_ptr& telemetry = {}); std::vector get_inputs() const override; std::vector get_outputs() const override; Place::Ptr get_place_by_tensor_name(const std::string& tensorName) const override; diff --git a/src/frontends/paddlepaddle/src/frontend.cpp b/src/frontends/paddlepaddle/src/frontend.cpp index 113e57632c7..e366eb85e90 100644 --- a/src/frontends/paddlepaddle/src/frontend.cpp +++ b/src/frontends/paddlepaddle/src/frontend.cpp @@ -249,19 +249,19 @@ InputModel::Ptr FrontEndPDPD::load_impl(const std::vector>(variants[0])) { std::string m_path = ov::as_type_ptr>(variants[0])->get(); - return std::make_shared(m_path); + return std::make_shared(m_path, m_telemetry); } #if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32) else if (ov::is_type>(variants[0])) { std::wstring m_path = ov::as_type_ptr>(variants[0])->get(); - return std::make_shared(m_path); + return std::make_shared(m_path, m_telemetry); } #endif // The case with only model stream provided and no weights. This means model has // no learnable weights else if (ov::is_type>(variants[0])) { auto p_model_stream = ov::as_type_ptr>(variants[0])->get(); - return std::make_shared(std::vector{p_model_stream}); + return std::make_shared(std::vector{p_model_stream}, m_telemetry); } } else if (variants.size() == 2) { // The case when .pdmodel and .pdparams files are provided @@ -270,7 +270,8 @@ InputModel::Ptr FrontEndPDPD::load_impl(const std::vector(std::vector{p_model_stream, p_weights_stream}); + return std::make_shared(std::vector{p_model_stream, p_weights_stream}, + m_telemetry); } } PDPD_THROW("Model can be loaded either from 1 or 2 files/streams"); @@ -326,6 +327,13 @@ std::shared_ptr FrontEndPDPD::decode(InputModel::Ptr model) const std::string FrontEndPDPD::get_name() const { return "paddle"; } + +void FrontEndPDPD::add_extension(const std::shared_ptr& extension) { + if (auto telemetry = std::dynamic_pointer_cast(extension)) { + m_telemetry = telemetry; + } +} + } // namespace frontend } // namespace ov diff --git a/src/frontends/paddlepaddle/src/model.cpp b/src/frontends/paddlepaddle/src/model.cpp index 0cd4c7376a8..e089e836048 100644 --- a/src/frontends/paddlepaddle/src/model.cpp +++ b/src/frontends/paddlepaddle/src/model.cpp @@ -27,8 +27,12 @@ using namespace paddle::framework::proto; class InputModelPDPD::InputModelPDPDImpl { public: template - InputModelPDPDImpl(const std::basic_string& path, const InputModel& input_model); - InputModelPDPDImpl(const std::vector& streams, const InputModel& input_model); + InputModelPDPDImpl(const std::basic_string& path, + const InputModel& input_model, + const std::shared_ptr& telemetry); + InputModelPDPDImpl(const std::vector& streams, + const InputModel& input_model, + const std::shared_ptr& telemetry); std::vector getInputs() const; std::vector getOutputs() const; Place::Ptr getPlaceByTensorName(const std::string& tensorName) const; @@ -63,6 +67,8 @@ private: std::vector m_outputs; std::map> m_tensor_values; + std::shared_ptr m_telemetry; + // shows if some nodes might be deleted from graph bool m_graph_changed = false; }; @@ -70,6 +76,7 @@ private: void InputModelPDPD::InputModelPDPDImpl::loadPlaces() { const int cnt_of_blocks = m_fw_ptr->blocks_size(); const auto& blocks = m_fw_ptr->blocks(); + std::map op_statistics; for (int block_idx = 0; block_idx < cnt_of_blocks; block_idx++) { const auto& block = blocks[block_idx]; @@ -80,6 +87,11 @@ void InputModelPDPD::InputModelPDPDImpl::loadPlaces() { for (const auto& op : block.ops()) { auto op_place = std::make_shared(m_input_model, op); + + if (m_telemetry) { + op_statistics[op.type()]++; + } + m_op_places.push_back(op_place); for (const auto& output : op.outputs()) { @@ -128,6 +140,11 @@ void InputModelPDPD::InputModelPDPDImpl::loadPlaces() { } } } + if (m_telemetry) { + for (const auto& op : op_statistics) { + m_telemetry->send_event("op_count", "paddle_" + op.first, op.second); + } + } } namespace { @@ -281,10 +298,13 @@ void InputModelPDPD::InputModelPDPDImpl::loadConsts(const std::basic_string& } template -InputModelPDPD::InputModelPDPDImpl::InputModelPDPDImpl(const std::basic_string& path, const InputModel& input_model) +InputModelPDPD::InputModelPDPDImpl::InputModelPDPDImpl(const std::basic_string& path, + const InputModel& input_model, + const std::shared_ptr& telemetry) : m_fw_ptr{std::make_shared()}, - m_input_model(input_model) { - std::string empty_str = ""; + m_input_model(input_model), + m_telemetry(telemetry) { + std::string empty_str; std::ifstream weights_stream; std::ifstream pb_stream(get_model_path(path, &weights_stream), std::ios::in | std::ifstream::binary); @@ -307,9 +327,11 @@ InputModelPDPD::InputModelPDPDImpl::InputModelPDPDImpl(const std::basic_string& streams, - const InputModel& input_model) + const InputModel& input_model, + const std::shared_ptr& telemetry) : m_fw_ptr{std::make_shared()}, - m_input_model(input_model) { + m_input_model(input_model), + m_telemetry(telemetry) { if (streams.size() != 1) { FRONT_END_GENERAL_CHECK(streams.size() == 2, "Two streams are needed to load a model: model and weights streams"); @@ -402,14 +424,17 @@ void InputModelPDPD::InputModelPDPDImpl::setTensorValue(Place::Ptr place, const m_tensor_values[name] = constant; } -InputModelPDPD::InputModelPDPD(const std::string& path) : _impl{std::make_shared(path, *this)} {} +InputModelPDPD::InputModelPDPD(const std::string& path, const std::shared_ptr& telemetry) + : _impl{std::make_shared(path, *this, telemetry)} {} #if defined(OPENVINO_ENABLE_UNICODE_PATH_SUPPORT) && defined(_WIN32) -InputModelPDPD::InputModelPDPD(const std::wstring& path) : _impl{std::make_shared(path, *this)} {} +InputModelPDPD::InputModelPDPD(const std::wstring& path, const std::shared_ptr& telemetry) + : _impl{std::make_shared(path, *this, telemetry)} {} #endif -InputModelPDPD::InputModelPDPD(const std::vector& streams) - : _impl{std::make_shared(streams, *this)} {} +InputModelPDPD::InputModelPDPD(const std::vector& streams, + const std::shared_ptr& telemetry) + : _impl{std::make_shared(streams, *this, telemetry)} {} std::vector> InputModelPDPD::get_op_places() const { return _impl->get_op_places(); diff --git a/src/frontends/tensorflow/include/tensorflow_frontend/frontend.hpp b/src/frontends/tensorflow/include/tensorflow_frontend/frontend.hpp index ab4a8062904..2a34b501abb 100644 --- a/src/frontends/tensorflow/include/tensorflow_frontend/frontend.hpp +++ b/src/frontends/tensorflow/include/tensorflow_frontend/frontend.hpp @@ -9,6 +9,7 @@ #include "common/frontend.hpp" #include "common/input_model.hpp" +#include "common/telemetry_extension.hpp" #include "openvino/core/any.hpp" #include "openvino/core/node_vector.hpp" #include "openvino/core/variant.hpp" @@ -67,6 +68,8 @@ public: return "tf"; } + void add_extension(const std::shared_ptr& extension) override; + protected: /// \brief Check if FrontEndTensorflow can recognize model from given parts bool supported_impl(const std::vector>& variants) const override; @@ -79,6 +82,8 @@ private: bool fail_fast, bool no_conversion, std::shared_ptr& ng_function) const; + + std::shared_ptr m_telemetry; }; } // namespace frontend } // namespace ov diff --git a/src/frontends/tensorflow/src/frontend.cpp b/src/frontends/tensorflow/src/frontend.cpp index c2392c76e90..5c6c83fb9d9 100644 --- a/src/frontends/tensorflow/src/frontend.cpp +++ b/src/frontends/tensorflow/src/frontend.cpp @@ -295,11 +295,12 @@ ov::frontend::InputModel::Ptr FrontEndTF::load_impl(const std::vector>(variants[0])->get(); if (ov::util::ends_with(model_path, suffix.c_str())) { return std::make_shared( - std::make_shared<::ov::frontend::tf::GraphIteratorProto>(model_path)); + std::make_shared<::ov::frontend::tf::GraphIteratorProto>(model_path), + m_telemetry); } } else if (ov::is_type>(variants[0])) { auto graph_iterator = ov::as_type_ptr>(variants[0])->get(); - return std::make_shared(graph_iterator); + return std::make_shared(graph_iterator, m_telemetry); } } return nullptr; @@ -348,3 +349,9 @@ void FrontEndTF::normalize(std::shared_ptr function) const { manager.register_pass(); manager.run_passes(function); } + +void FrontEndTF::add_extension(const std::shared_ptr& extension) { + if (auto telemetry = std::dynamic_pointer_cast(extension)) { + m_telemetry = telemetry; + } +} diff --git a/src/frontends/tensorflow/src/model.cpp b/src/frontends/tensorflow/src/model.cpp index 99de7b9f3e2..695217d22e4 100644 --- a/src/frontends/tensorflow/src/model.cpp +++ b/src/frontends/tensorflow/src/model.cpp @@ -53,6 +53,9 @@ void extract_operation_name_and_port(const std::string& port_name, class InputModelTF::InputModelTFImpl { public: InputModelTFImpl(const GraphIterator::Ptr& graph_iterator, const ov::frontend::InputModel& input_model); + InputModelTFImpl(const GraphIterator::Ptr& graph_iterator, + const ov::frontend::InputModel& input_model, + const std::shared_ptr& telemetry); std::vector getInputs() const; std::vector getOutputs() const; ov::frontend::Place::Ptr getPlaceByTensorName(const std::string& tensorName) const; @@ -87,6 +90,8 @@ private: std::shared_ptr m_graph_iterator; const ov::frontend::InputModel& m_input_model; + std::shared_ptr m_telemetry; + // shows if some nodes might be deleted from graph bool m_graph_changed = false; }; @@ -94,12 +99,18 @@ private: void InputModelTF::InputModelTFImpl::loadPlaces() { std::set all_op_names; std::set op_names_with_consumers; + std::map op_statistics; m_inputs.clear(); for (; !m_graph_iterator->is_end(); m_graph_iterator->next()) { auto node_decoder = m_graph_iterator->get_decoder(); auto op_name = node_decoder->get_op_name(); auto op_type = node_decoder->get_op_type(); + + if (m_telemetry) { + op_statistics[op_type]++; + } + auto op_place = std::make_shared(m_input_model, node_decoder); all_op_names.insert(op_name); m_op_places.push_back(op_place); @@ -128,6 +139,13 @@ void InputModelTF::InputModelTFImpl::loadPlaces() { } } } + + if (m_telemetry) { + for (const auto& op : op_statistics) { + m_telemetry->send_event("op_count", "tf_" + op.first, op.second); + } + } + std::set op_names_without_consumers; std::set_difference(all_op_names.begin(), all_op_names.end(), @@ -240,6 +258,16 @@ InputModelTF::InputModelTFImpl::InputModelTFImpl(const GraphIterator::Ptr& graph loadPlaces(); } +InputModelTF::InputModelTFImpl::InputModelTFImpl(const GraphIterator::Ptr& graph_iterator, + const InputModel& input_model, + const std::shared_ptr& telemetry) + : m_input_model(input_model), + m_graph_iterator(graph_iterator), + m_telemetry(telemetry) { + FRONT_END_GENERAL_CHECK(m_graph_iterator, "Null pointer specified for GraphIterator"); + loadPlaces(); +} + std::vector InputModelTF::InputModelTFImpl::getInputs() const { return m_inputs; } @@ -325,8 +353,9 @@ void InputModelTF::InputModelTFImpl::setTensorValue(ov::frontend::Place::Ptr pla m_tensor_values[name] = constant; } -InputModelTF::InputModelTF(const GraphIterator::Ptr& graph_iterator) - : _impl{std::make_shared(graph_iterator, *this)} {} +InputModelTF::InputModelTF(const GraphIterator::Ptr& graph_iterator, + const std::shared_ptr& telemetry) + : _impl{std::make_shared(graph_iterator, *this, telemetry)} {} std::vector> InputModelTF::get_op_places() const { return _impl->get_op_places(); diff --git a/src/frontends/tensorflow/src/model.hpp b/src/frontends/tensorflow/src/model.hpp index 7312e827f3a..d2edc1dc5d3 100644 --- a/src/frontends/tensorflow/src/model.hpp +++ b/src/frontends/tensorflow/src/model.hpp @@ -6,6 +6,7 @@ #include "common/input_model.hpp" #include "common/place.hpp" +#include "common/telemetry_extension.hpp" #include "tensorflow_frontend/graph_iterator.hpp" namespace ov { @@ -24,7 +25,8 @@ class InputModelTF : public ov::frontend::InputModel { std::map> get_tensor_values() const; public: - explicit InputModelTF(const GraphIterator::Ptr& graph_iterator); + explicit InputModelTF(const GraphIterator::Ptr& graph_iterator, + const std::shared_ptr& telemetry = {}); std::vector get_inputs() const override; std::vector get_outputs() const override;