Files
openvino/docs/template_plugin/src/template_plugin.cpp
T

256 lines
12 KiB
C++
Raw Normal View History

// Copyright (C) 2018-2021 Intel Corporation
2020-05-22 22:34:00 +03:00
// SPDX-License-Identifier: Apache-2.0
//
2021-05-25 10:32:48 +03:00
// clang-format off
2020-05-22 22:34:00 +03:00
#include <ie_metric_helpers.hpp>
#include <ie_plugin_config.hpp>
#include <ie_algorithm.hpp>
2020-07-29 19:56:24 +03:00
#include <hetero/hetero_plugin_config.hpp>
2020-05-22 22:34:00 +03:00
#include <threading/ie_executor_manager.hpp>
2020-07-29 19:56:24 +03:00
#include <ngraph/op/util/op_types.hpp>
#include <ngraph/graph_util.hpp>
#include <ngraph/pass/manager.hpp>
#include <ngraph/opsets/opset.hpp>
#include <transformations/common_optimizations/common_optimizations.hpp>
#include <transformations/rt_info/fused_names_attribute.hpp>
#include <transformations/convert_precision.hpp>
2020-07-29 19:56:24 +03:00
#include "template/template_config.hpp"
2021-01-28 20:04:52 +03:00
#include "template_itt.hpp"
2020-05-22 22:34:00 +03:00
#include "template_plugin.hpp"
#include "template_executable_network.hpp"
#include "template_infer_request.hpp"
#include "transformations/template_pattern_transformation.hpp"
#include "transformations/preprocessing/preprocessing.hpp"
2021-05-25 10:32:48 +03:00
// clang-format on
2020-05-22 22:34:00 +03:00
using namespace TemplatePlugin;
// ! [plugin:ctor]
Plugin::Plugin() {
2020-07-29 19:56:24 +03:00
// TODO: fill with actual device name, backend engine
2020-05-22 22:34:00 +03:00
_pluginName = "TEMPLATE";
2020-07-29 19:56:24 +03:00
// create ngraph backend which performs inference using ngraph reference implementations
ngraph::runtime::Backend::set_backend_shared_library_search_directory("");
_backend = ngraph::runtime::Backend::create("INTERPRETER");
2020-07-29 19:56:24 +03:00
// create default stream executor with a given name
_waitExecutor = InferenceEngine::ExecutorManager::getInstance()->getIdleCPUStreamsExecutor({"TemplateWaitExecutor"});
2020-05-22 22:34:00 +03:00
}
// ! [plugin:ctor]
// ! [plugin:dtor]
Plugin::~Plugin() {
// Plugin should remove executors from executor cache to avoid threads number growth in the whole application
InferenceEngine::ExecutorManager::getInstance()->clear("TemplateStreamsExecutor");
InferenceEngine::ExecutorManager::getInstance()->clear("TemplateWaitExecutor");
// NOTE: Uncomment this if Inference Engine Executor cache is used to create callback executor
// ExecutorManager::getInstance()->clear("TemplateCallbackExecutor");
}
// ! [plugin:dtor]
2020-07-29 19:56:24 +03:00
// ! [plugin:transform_network]
2021-05-25 10:32:48 +03:00
std::shared_ptr<ngraph::Function> TransformNetwork(const std::shared_ptr<const ngraph::Function>& function, const InferenceEngine::InputsDataMap& inputInfoMap,
const InferenceEngine::OutputsDataMap& outputsInfoMap) {
2020-07-29 19:56:24 +03:00
// 1. Copy ngraph::Function first to apply some transformations which modify original ngraph::Function
auto transformedNetwork = ngraph::clone_function(*function);
// 2. Perform common optimizations and device-specific transformations
ngraph::pass::Manager passManager;
// Example: register transformation to convert preprocessing information to graph nodes
passManager.register_pass<ngraph::pass::AddPreprocessing>(inputInfoMap);
// TODO: add post-processing based on outputsInfoMap
// Example: register CommonOptimizations transformation from transformations library
passManager.register_pass<ngraph::pass::CommonOptimizations>();
// Template plugin handles only FP32 networks
2021-05-25 10:32:48 +03:00
passManager.register_pass<ngraph::pass::ConvertPrecision>(precisions_array {{ngraph::element::f16, ngraph::element::f32}});
// Example: register plugin specific transformation
passManager.register_pass<ngraph::pass::DecomposeDivideMatcher>();
passManager.register_pass<ngraph::pass::ReluReluFusionMatcher>();
// Register any other transformations
// ..
// After `run_passes`, we have the transformed function, where operations match device operations,
2020-07-29 19:56:24 +03:00
// and we can create device backend-dependent graph
passManager.run_passes(transformedNetwork);
2020-07-29 19:56:24 +03:00
return transformedNetwork;
}
2020-07-29 19:56:24 +03:00
// ! [plugin:transform_network]
2020-05-22 22:34:00 +03:00
// ! [plugin:load_exe_network_impl]
2021-05-25 10:32:48 +03:00
InferenceEngine::ExecutableNetworkInternal::Ptr Plugin::LoadExeNetworkImpl(const InferenceEngine::CNNNetwork& network, const ConfigMap& config) {
2021-01-28 20:04:52 +03:00
OV_ITT_SCOPED_TASK(itt::domains::TemplatePlugin, "Plugin::LoadExeNetworkImpl");
InferenceEngine::InputsDataMap networkInputs = network.getInputsInfo();
InferenceEngine::OutputsDataMap networkOutputs = network.getOutputsInfo();
2021-05-25 10:32:48 +03:00
auto fullConfig = Configuration {config, _cfg};
return std::make_shared<ExecutableNetwork>(network.getFunction(), networkInputs, networkOutputs, fullConfig,
std::static_pointer_cast<Plugin>(shared_from_this()));
2020-05-22 22:34:00 +03:00
}
// ! [plugin:load_exe_network_impl]
// ! [plugin:import_network_impl]
2021-05-25 10:32:48 +03:00
InferenceEngine::ExecutableNetworkInternal::Ptr Plugin::ImportNetworkImpl(std::istream& modelStream, const std::map<std::string, std::string>& config) {
2021-01-28 20:04:52 +03:00
OV_ITT_SCOPED_TASK(itt::domains::TemplatePlugin, "Plugin::ImportNetworkImpl");
2020-05-22 22:34:00 +03:00
2021-05-25 10:32:48 +03:00
auto fullConfig = Configuration {config, _cfg};
return std::make_shared<ExecutableNetwork>(modelStream, fullConfig, std::static_pointer_cast<Plugin>(shared_from_this()));
2020-05-22 22:34:00 +03:00
}
// ! [plugin:import_network_impl]
// ! [plugin:query_network]
2021-05-25 10:32:48 +03:00
InferenceEngine::QueryNetworkResult Plugin::QueryNetwork(const InferenceEngine::CNNNetwork& network, const ConfigMap& config) const {
2021-01-28 20:04:52 +03:00
OV_ITT_SCOPED_TASK(itt::domains::TemplatePlugin, "Plugin::QueryNetwork");
2021-05-25 10:32:48 +03:00
Configuration fullConfig {config, _cfg, false};
auto function = network.getFunction();
2020-07-29 19:56:24 +03:00
// 1. First of all we should store initial input operation set
std::unordered_set<std::string> originalOps;
2020-12-16 12:17:29 +03:00
std::map<std::string, ngraph::NodeTypeInfo> friendlyNameToType;
for (auto&& node : function->get_ops()) {
originalOps.emplace(node->get_friendly_name());
2020-12-16 12:17:29 +03:00
friendlyNameToType[node->get_friendly_name()] = node->get_type_info();
}
2020-07-29 19:56:24 +03:00
// 2. It is needed to apply all transformations as it is done in LoadExeNetworkImpl
auto transformedFunction = TransformNetwork(function, network.getInputsInfo(), network.getOutputsInfo());
2020-07-29 19:56:24 +03:00
// 3. The same input node can be transformed into supported and unsupported backend node
2020-12-16 12:17:29 +03:00
// So we need store as supported either unsupported node sets
std::unordered_set<std::string> supported;
std::unordered_set<std::string> unsupported;
auto opset = ngraph::get_opset4();
for (auto&& node : transformedFunction->get_ops()) {
// Extract transformation history from transformed node as list of nodes
for (auto&& fusedLayerName : ngraph::getFusedNamesVector(node)) {
// Filter just nodes from original operation set
// TODO: fill with actual decision rules based on whether kernel is supported by backend
if (InferenceEngine::details::contains(originalOps, fusedLayerName)) {
2020-12-16 12:17:29 +03:00
if (opset.contains_type(friendlyNameToType[fusedLayerName])) {
supported.emplace(fusedLayerName);
} else {
unsupported.emplace(fusedLayerName);
}
2020-05-22 22:34:00 +03:00
}
}
}
2020-07-29 19:56:24 +03:00
2020-12-16 12:17:29 +03:00
// 4. The result set should contain just nodes from supported set
for (auto&& unsupportedNode : unsupported) {
supported.erase(unsupportedNode);
}
for (auto&& node : function->get_ops()) {
// 5. If some housekeeping nodes were not added - add them.
if (InferenceEngine::details::contains(supported, node->get_friendly_name())) {
for (auto&& inputNodeOutput : node->input_values()) {
if (ngraph::op::is_constant(inputNodeOutput.get_node()) || ngraph::op::is_parameter(inputNodeOutput.get_node())) {
supported.emplace(inputNodeOutput.get_node()->get_friendly_name());
}
}
for (auto&& outputs : node->outputs()) {
for (auto&& outputNodeInput : outputs.get_target_inputs()) {
if (ngraph::op::is_output(outputNodeInput.get_node())) {
supported.emplace(outputNodeInput.get_node()->get_friendly_name());
}
}
}
}
2020-12-16 12:17:29 +03:00
// 6. Eliminate subgraphs that consist of housekeeping nodes only
if (ngraph::op::is_constant(node) || ngraph::op::is_parameter(node)) {
if (!InferenceEngine::details::contains(supported, node->output(0).get_target_inputs().begin()->get_node()->get_friendly_name())) {
supported.erase(node->get_friendly_name());
}
} else if (ngraph::op::is_output(node)) {
if (!InferenceEngine::details::contains(supported, node->input_values().begin()->get_node()->get_friendly_name())) {
supported.erase(node->get_friendly_name());
}
}
}
// 7. Produce the result
InferenceEngine::QueryNetworkResult res;
2020-12-16 12:17:29 +03:00
for (auto&& layerName : supported) {
res.supportedLayersMap.emplace(layerName, GetName());
2020-09-15 14:03:24 +03:00
}
2020-10-13 17:22:51 +03:00
return res;
2020-05-22 22:34:00 +03:00
}
// ! [plugin:query_network]
// ! [plugin:add_extension]
void Plugin::AddExtension(InferenceEngine::IExtensionPtr /*extension*/) {
// TODO: add extensions if plugin supports extensions
2021-03-23 18:57:12 +03:00
IE_THROW(NotImplemented);
2020-05-22 22:34:00 +03:00
}
// ! [plugin:add_extension]
// ! [plugin:set_config]
2021-05-25 10:32:48 +03:00
void Plugin::SetConfig(const ConfigMap& config) {
_cfg = Configuration {config, _cfg};
2020-05-22 22:34:00 +03:00
}
// ! [plugin:set_config]
// ! [plugin:get_config]
2021-05-25 10:32:48 +03:00
InferenceEngine::Parameter Plugin::GetConfig(const std::string& name, const std::map<std::string, InferenceEngine::Parameter>& /*options*/) const {
2020-05-22 22:34:00 +03:00
return _cfg.Get(name);
}
// ! [plugin:get_config]
// ! [plugin:get_metric]
2021-05-25 10:32:48 +03:00
InferenceEngine::Parameter Plugin::GetMetric(const std::string& name, const std::map<std::string, InferenceEngine::Parameter>& options) const {
2020-05-22 22:34:00 +03:00
if (METRIC_KEY(SUPPORTED_METRICS) == name) {
2021-05-25 10:32:48 +03:00
std::vector<std::string> supportedMetrics = {METRIC_KEY(AVAILABLE_DEVICES), METRIC_KEY(SUPPORTED_METRICS),
METRIC_KEY(SUPPORTED_CONFIG_KEYS), METRIC_KEY(FULL_DEVICE_NAME),
METRIC_KEY(IMPORT_EXPORT_SUPPORT), METRIC_KEY(DEVICE_ARCHITECTURE),
METRIC_KEY(OPTIMIZATION_CAPABILITIES), METRIC_KEY(RANGE_FOR_ASYNC_INFER_REQUESTS)};
2020-05-22 22:34:00 +03:00
IE_SET_METRIC_RETURN(SUPPORTED_METRICS, supportedMetrics);
} else if (METRIC_KEY(SUPPORTED_CONFIG_KEYS) == name) {
2021-05-25 10:32:48 +03:00
std::vector<std::string> configKeys = {CONFIG_KEY(DEVICE_ID), CONFIG_KEY(PERF_COUNT), TEMPLATE_CONFIG_KEY(THROUGHPUT_STREAMS)};
auto streamExecutorConfigKeys = InferenceEngine::IStreamsExecutor::Config {}.SupportedKeys();
for (auto&& configKey : streamExecutorConfigKeys) {
if (configKey != InferenceEngine::PluginConfigParams::KEY_CPU_THROUGHPUT_STREAMS) {
configKeys.emplace_back(configKey);
}
}
IE_SET_METRIC_RETURN(SUPPORTED_CONFIG_KEYS, configKeys);
2020-05-22 22:34:00 +03:00
} else if (METRIC_KEY(AVAILABLE_DEVICES) == name) {
// TODO: fill list of available devices
2021-05-25 10:32:48 +03:00
std::vector<std::string> availableDevices = {""};
2020-05-22 22:34:00 +03:00
IE_SET_METRIC_RETURN(AVAILABLE_DEVICES, availableDevices);
} else if (METRIC_KEY(FULL_DEVICE_NAME) == name) {
std::string name = "Template Device Full Name";
IE_SET_METRIC_RETURN(FULL_DEVICE_NAME, name);
} else if (METRIC_KEY(IMPORT_EXPORT_SUPPORT) == name) {
IE_SET_METRIC_RETURN(IMPORT_EXPORT_SUPPORT, true);
} else if (METRIC_KEY(DEVICE_ARCHITECTURE) == name) {
// TODO: return device architecture for device specified by DEVICE_ID config
std::string arch = "TEMPLATE";
IE_SET_METRIC_RETURN(DEVICE_ARCHITECTURE, arch);
2020-05-22 22:34:00 +03:00
} else if (METRIC_KEY(OPTIMIZATION_CAPABILITIES) == name) {
// TODO: fill actual list of supported capabilities: e.g. Template device supports only FP32
2021-05-25 10:32:48 +03:00
std::vector<std::string> capabilities = {METRIC_VALUE(FP32) /*, TEMPLATE_METRIC_VALUE(HARDWARE_CONVOLUTION)*/};
2020-05-22 22:34:00 +03:00
IE_SET_METRIC_RETURN(OPTIMIZATION_CAPABILITIES, capabilities);
} else if (METRIC_KEY(RANGE_FOR_ASYNC_INFER_REQUESTS) == name) {
// TODO: fill with actual values
using uint = unsigned int;
2021-05-25 10:32:48 +03:00
IE_SET_METRIC_RETURN(RANGE_FOR_ASYNC_INFER_REQUESTS, std::make_tuple(uint {1}, uint {1}, uint {1}));
} else {
IE_THROW(NotFound) << "Unsupported device metric: " << name;
2020-05-22 22:34:00 +03:00
}
}
// ! [plugin:get_metric]
// ! [plugin:create_plugin_engine]
static const InferenceEngine::Version version = {{2, 1}, CI_BUILD_NUMBER, "templatePlugin"};
IE_DEFINE_PLUGIN_CREATE_FUNCTION(Plugin, version)
2020-05-22 22:34:00 +03:00
// ! [plugin:create_plugin_engine]