assert 'Device with "BLA" name is not registered in the InferenceEngine' in str(e.value)
+@pytest.mark.skip(reason="IENetwork.layers return not all layers in case of ngraph representation due to inner conversion into legacy representation")
def test_query_network(device):
ie = IECore()
net = ie.read_network(model=test_net_xml, weights=test_net_bin)
SOURCES ${SOURCES} ${HEADERS}
VERSION_DEFINES_FOR hetero_plugin.cpp)
-target_link_libraries(${TARGET_NAME} PRIVATE inference_engine ade pugixml)
+target_link_libraries(${TARGET_NAME} PRIVATE inference_engine ade pugixml ${NGRAPH_LIBRARIES} inference_engine_transformations)
#include "hetero_plugin.hpp"
#include "network_serializer.h"
+#include <ngraph/function.hpp>
+#include <ngraph/variant.hpp>
+#include <ngraph/graph_util.hpp>
+#include <ngraph/op/result.hpp>
+#include <ngraph/op/parameter.hpp>
+#include <ngraph/rt_info.hpp>
+
using namespace InferenceEngine;
using namespace details;
using namespace HeteroPlugin;
saveGraphToDot(network, stream, split_color);
}
+
+void dumpGraph(InferenceEngine::ICNNNetwork& network,
+ const std::vector<std::shared_ptr<const ngraph::Function>>& subFunctions,
+ std::ostream& stream) {
+ static const std::array<const char *, 9> colors{{"#FFC405",
+ "#20F608",
+ "#F1F290",
+ "#C405FF",
+ "#BCFF05",
+ "#05FFC4",
+ "#FFC405",
+ "#5A5DF0",
+ "#FF2E05"}};
+ auto split_color = [&](const CNNLayerPtr layer,
+ ordered_properties &printed_properties,
+ ordered_properties &node_properties) {
+ for (size_t i = 0; i < subFunctions.size(); i++) {
+ for (auto&& node : subFunctions[i]->get_ordered_ops()) {
+ if (node->get_friendly_name() == layer->name) {
+ node_properties.emplace_back(
+ "fillcolor",
+ colors[i % colors.size()]);
+ printed_properties.insert(printed_properties.begin(),
+ std::pair<std::string, std::string>("subgraph#", std::to_string(i)));
+ printed_properties.insert(printed_properties.begin(),
+ std::pair<std::string, std::string>("device", layer->affinity));
+ return;
+ }
+ }
+ }
+ };
+
+ saveGraphToDot(const_cast<InferenceEngine::ICNNNetwork&>(network), stream, split_color);
+}
+
} // namespace
-HeteroExecutableNetwork::HeteroExecutableNetwork(const InferenceEngine::ICNNNetwork& network_,
- const Engine::Configs& config,
- Engine* heteroPlugin):
- InferenceEngine::ExecutableNetworkThreadSafeDefault(
- nullptr, std::make_shared<InferenceEngine::ImmediateExecutor>()),
- _heteroPlugin(heteroPlugin),
- _name{network_.getName()},
- _config{config} {
+void HeteroExecutableNetwork::InitCNNImpl(const InferenceEngine::ICNNNetwork& network_) {
auto networkPtr = cloneNet(network_);
auto& network = *networkPtr;
THROW_IE_EXCEPTION << "Network passed to LoadNetwork has affinity assigned, but some layers eg: \n(Name:" <<
layerEmptyAffinity->name << ", Type: " << layerEmptyAffinity->type <<
") were not assigned to any device.\n" <<
- "It might happen if you assigned layers amnually and missed some layers or\n" <<
+ "It might happen if you assigned layers manually and missed some layers or\n" <<
"if you used some automatic assigning mode which decided that these layers are not\n" <<
"supported by any plugin";
}
auto deviceName = d._device;
auto metaDevices = _heteroPlugin->GetDevicePlugins(deviceName, cfg);
assert(metaDevices.size() == 1);
-
auto loadConfig = metaDevices[deviceName];
d._network = _heteroPlugin->GetCore()->LoadNetwork(d._clonedNetwork, deviceName, loadConfig);
}
networks = std::move(descs);
}
+template<typename T>
+using NodeMap = std::unordered_map<ngraph::Node*, T>;
+
+void HeteroExecutableNetwork::InitNgraph(const InferenceEngine::ICNNNetwork& network_) {
+ auto function = network_.getFunction();
+ auto networkPtr = cloneNetwork(network_);
+ auto& network = *networkPtr;
+ auto itDumpDotFile = _config.find(HETERO_CONFIG_KEY(DUMP_GRAPH_DOT));
+ bool dumpDotFile = itDumpDotFile != _config.end() ? (itDumpDotFile->second == YES) : false;
+#ifndef NDEBUG
+ dumpDotFile = true;
+#endif
+
+ QueryNetworkResult queryNetworkResult;
+ auto orderedOps = function->get_ordered_ops();
+ orderedOps.erase(
+ std::remove_if(std::begin(orderedOps), std::end(orderedOps), [] (const std::shared_ptr<ngraph::Node>& node) {
+ return node->is_constant();
+ }),
+ std::end(orderedOps));
+ bool allEmpty = true;
+ // Get user defined affinity
+ for (auto&& node : orderedOps) {
+ auto& nodeInfo = node->get_rt_info();
+ auto itInfo = nodeInfo.find("affinity");
+ if (itInfo != nodeInfo.end()) {
+ IE_ASSERT((ngraph::is_type<ngraph::VariantWrapper<std::string>>(itInfo->second)));
+ queryNetworkResult.supportedLayersMap.emplace(
+ node->get_friendly_name(),
+ ngraph::as_type_ptr<ngraph::VariantWrapper<std::string>>(itInfo->second)->get());
+ allEmpty = false;
+ }
+ }
+
+ if (queryNetworkResult.supportedLayersMap.empty()) {
+ auto it = _config.find("TARGET_FALLBACK");
+ if (it != _config.end()) {
+ _heteroPlugin->QueryNetwork(network_, _config, queryNetworkResult);
+ } else {
+ THROW_IE_EXCEPTION << "The 'TARGET_FALLBACK' option was not defined for heterogeneous plugin";
+ }
+ }
+
+ using Input = ngraph::Input<ngraph::Node>;
+ using NodeSet = std::unordered_set<ngraph::Node*>;
+ using InputSet = std::set<Input>;
+
+ auto InputNode = [] (const ngraph::Input<ngraph::Node>& input) {
+ return input.get_source_output().get_node();
+ };
+
+ auto NoConstants = [] (std::vector<ngraph::Input<ngraph::Node>>&& inputs) {
+ std::vector<ngraph::Input<ngraph::Node>> result;
+ for (auto&& input : inputs) {
+ if (!(input.get_source_output().get_node()->is_constant())) {
+ result.emplace_back(std::move(input));
+ }
+ }
+ return result;
+ };
+
+ // Set parameters affinity
+ for (auto&& node : function->get_parameters()) {
+ if (!contains(queryNetworkResult.supportedLayersMap, node->get_friendly_name())) {
+ auto& outputNodeName = node->output(0).get_target_inputs().begin()->get_node()->get_friendly_name();
+ auto itOutputAffinity = queryNetworkResult.supportedLayersMap.find(outputNodeName);
+ if (itOutputAffinity == queryNetworkResult.supportedLayersMap.end()) {
+ THROW_IE_EXCEPTION << "Layer " << outputNodeName <<
+ " was not assigned on any pointed device.";
+ }
+ queryNetworkResult.supportedLayersMap[node->get_friendly_name()] = itOutputAffinity->second;
+ }
+ }
+
+ // Set results affinity
+ for (auto&& node : function->get_results()) {
+ if (!contains(queryNetworkResult.supportedLayersMap, node->get_friendly_name())) {
+ auto& inputNodeName = node->input_value(0).get_node()->get_friendly_name();
+ auto itInputAffinity = queryNetworkResult.supportedLayersMap.find(inputNodeName);
+ if (itInputAffinity == queryNetworkResult.supportedLayersMap.end()) {
+ THROW_IE_EXCEPTION << "Layer " << inputNodeName <<
+ " was not assigned on any pointed device.";
+ }
+ queryNetworkResult.supportedLayersMap[node->get_friendly_name()] = itInputAffinity->second;
+ }
+ }
+
+ std::unordered_set<std::string> devices;
+ NodeMap<std::string> affinities;
+ // Check that all nodes has user or plugin defined affinities
+ for (auto&& node : orderedOps) {
+ auto itAffinity = queryNetworkResult.supportedLayersMap.find(node->get_friendly_name());
+ if (itAffinity != queryNetworkResult.supportedLayersMap.end()) {
+ affinities[node.get()] = itAffinity->second;
+ if (dumpDotFile) {
+ devices.insert(itAffinity->second);
+ for (details::CNNNetworkIterator el(&network); el != details::CNNNetworkIterator(); el++) {
+ CNNLayer::Ptr layer = *el;
+ if (CaselessEq<std::string>()(layer->name, node->get_friendly_name())) {
+ layer->affinity = itAffinity->second;
+ }
+ }
+ }
+ } else if (allEmpty) {
+ THROW_IE_EXCEPTION << "Hetero plugin used default fallback policy, but some layers eg: \n(Name:" <<
+ node->get_friendly_name() << ", Type: " << node->get_type_name() <<
+ ") were not able to be assigned on any pointed device.\n" <<
+ "It happened because these layers are not supported in plugins by default.\n" <<
+ "You need to implement custom layers to support them.";
+ } else {
+ THROW_IE_EXCEPTION << "Network passed to LoadNetwork has affinity assigned, but some layers eg: \n(Name:" <<
+ node->get_friendly_name() << ", Type: " << node->get_type_name() <<
+ ") were not assigned to any device.\n" <<
+ "It might happen if you assigned layers manually and missed some layers or\n" <<
+ "if you used some automatic assigning mode which decided that these layers are not\n" <<
+ "supported by any plugin";
+ }
+ }
+
+ if (dumpDotFile) {
+ std::ofstream ofstream{"hetero_affinity_" + _name + ".dot"};
+ saveGraphToDot(network, ofstream, HeteroLayerColorer{{devices.begin(), devices.end()}});
+ }
+
+ NodeMap<InputSet> nodeInputDependencies;
+ NodeSet graphInputNodes;
+ InputSet subgraphInputs;
+ // Get all subgraph inputs using just node affinities. Also collect transitive closure
+ for (auto&& node : orderedOps) {
+ if (node->is_parameter()) {
+ graphInputNodes.insert(node.get());
+ subgraphInputs.insert(Input{node.get(), 0});
+ nodeInputDependencies[node.get()].insert(Input{node.get(), 0});
+ } else {
+ auto inputs = NoConstants(node->inputs());
+ auto& nodeInputDependency = nodeInputDependencies[node.get()];
+ for (auto&& input : inputs) {
+ nodeInputDependency.insert(input);
+ auto& inputDependency = nodeInputDependencies[InputNode(input)];
+ nodeInputDependency.insert(inputDependency.begin(), inputDependency.end());
+ if (affinities[node.get()] != affinities[InputNode(input)]) {
+ subgraphInputs.insert(input);
+ }
+ }
+ }
+ }
+
+ // Assign each node subgraph ID
+ auto CollectSubgraphs = [&] {
+ std::deque<int> subgraphIds;
+ NodeMap<int*> subgraphIdPtrs;
+ for (auto&& node : orderedOps) {
+ auto allNodeInputs = NoConstants(node->inputs());
+ std::vector<Input> inputs;
+ for (auto&& input : allNodeInputs) {
+ if (!contains(subgraphInputs, input)) {
+ inputs.emplace_back(std::move(input));
+ }
+ }
+ if (inputs.empty()) {
+ subgraphIds.push_back(subgraphIds.size());
+ subgraphIdPtrs.emplace(node.get(), &(subgraphIds.back()));
+ } else {
+ auto firstInputSubgraphIdPtr = subgraphIdPtrs[InputNode(inputs.front())];
+ for (auto&& input : inputs) {
+ auto inputId = *subgraphIdPtrs[InputNode(input)];
+ for (auto& subgraphId : subgraphIds) {
+ if (subgraphId == inputId) {
+ subgraphId = *firstInputSubgraphIdPtr;
+ }
+ }
+ }
+ subgraphIdPtrs.emplace(node.get(), firstInputSubgraphIdPtr);
+ }
+ }
+ NodeMap<int> result;
+ for (auto&& subgraphIdPtr : subgraphIdPtrs) {
+ result.emplace(subgraphIdPtr.first, *(subgraphIdPtr.second));
+ }
+ return result;
+ };
+
+ // Split cyclic dependencies.
+ for (std::size_t prevSubgraphs = 0, cyclicSplitStep = 0; prevSubgraphs != subgraphInputs.size(); ++cyclicSplitStep) {
+ IE_ASSERT(cyclicSplitStep < orderedOps.size());
+ prevSubgraphs = subgraphInputs.size();
+ auto subgraphIds = CollectSubgraphs();
+ // All inputs that belong to the same subgraph as node
+ std::unordered_map<ngraph::Node*, InputSet> nodeSubgraphInputDependencies;
+ // All inputs that depends on the same subgraph as node
+ std::unordered_map<ngraph::Node*, InputSet> nodeSubgraphCyclicInputDependencies;
+ for (auto&& node : orderedOps) {
+ auto& nodeSubgraphInputDependency = nodeSubgraphInputDependencies[node.get()];
+ auto allNodeSubgraphInputs = Intersection(nodeInputDependencies[node.get()], subgraphInputs);
+ for (auto&& subgraphInput : allNodeSubgraphInputs) {
+ if (subgraphIds[node.get()] == subgraphIds[subgraphInput.get_node()]) {
+ nodeSubgraphInputDependency.emplace(subgraphInput);
+ }
+ }
+ auto& nodeSubgraphCyclicInputDependency = nodeSubgraphCyclicInputDependencies[node.get()];
+ for (auto&& subgraphInput : allNodeSubgraphInputs) {
+ if (!subgraphInput.get_node()->is_parameter() && subgraphIds[node.get()] == subgraphIds[InputNode(subgraphInput)]) {
+ nodeSubgraphCyclicInputDependency.emplace(subgraphInput);
+ }
+ }
+ }
+
+ for (auto&& node : orderedOps) {
+ auto& nodeSubgraphCyclicInputDependency = nodeSubgraphCyclicInputDependencies[node.get()];
+ if (!nodeSubgraphCyclicInputDependency.empty()) {
+ auto& nodeSubgraphInputDependency = nodeSubgraphInputDependencies[node.get()];
+ // Collect all subgraph inputs that cyclic subgraph output depends on
+ InputSet cyclicInputsDependencies;
+ for (auto&& cyclicInput : nodeSubgraphCyclicInputDependency) {
+ for (auto&& input : nodeSubgraphInputDependencies[InputNode(cyclicInput)]) {
+ cyclicInputsDependencies.emplace(input);
+ }
+ }
+ for (auto&& input : NoConstants(node->inputs())) {
+ auto& inputNodeSubgraphCyclicInputDependency = nodeSubgraphCyclicInputDependencies[InputNode(input)];
+ auto& inputNodeSubgraphInputDependency = nodeSubgraphInputDependencies[InputNode(input)];
+ if (!Intersects(nodeSubgraphCyclicInputDependency,
+ inputNodeSubgraphCyclicInputDependency) &&
+ Intersects(cyclicInputsDependencies, inputNodeSubgraphInputDependency)) {
+ subgraphInputs.insert(input);
+ }
+ }
+ }
+ }
+ }
+
+ auto subgraphIds = CollectSubgraphs();
+ // Break graph using insertion of result parameter split
+ NodeMap<ngraph::Node*> subgraphParameterToPrevResult;
+ std::vector<std::shared_ptr<ngraph::op::Result>> results;
+ for (auto&& input : subgraphInputs) {
+ if (!(input.get_node()->is_parameter())) {
+ auto output = input.get_source_output();
+ output.remove_target_input(input);
+ auto result = std::make_shared<ngraph::op::Result>(output);
+ ngraph::copy_runtime_info(output.get_node_shared_ptr(), result);
+ auto parameter = std::make_shared<ngraph::op::Parameter>(output.get_element_type(), output.get_shape());
+ ngraph::copy_runtime_info(input.get_node()->shared_from_this(), parameter);
+ input.replace_source_output(parameter->output(0));
+ results.push_back(result);
+ subgraphIds.emplace(result.get(), subgraphIds[output.get_node()]);
+ subgraphIds.emplace(parameter.get(), subgraphIds[input.get_node()]);
+ subgraphParameterToPrevResult.emplace(parameter.get(), result.get());
+ _blobNameMap.emplace(parameter->get_friendly_name(),
+ output.get_node()->get_friendly_name() +
+ ((output.get_node()->get_output_size() != 1)
+ ? ("." + std::to_string(output.get_index())) : std::string{}));
+ }
+ }
+
+ struct Subgraph {
+ ngraph::ResultVector _results;
+ ngraph::ParameterVector _parameters;
+ std::string _affinity;
+ };
+ std::unordered_map<int, Subgraph> subgraphs;
+ // Extracts subgraph parameters, results and affinities
+ for (auto&& subgraphIdPtrValue : subgraphIds) {
+ auto node = subgraphIdPtrValue.first;
+ auto& subgraph = subgraphs[subgraphIdPtrValue.second];
+ if (node->is_output()) {
+ subgraph._results.emplace_back(
+ std::dynamic_pointer_cast<ngraph::op::v0::Result>(node->shared_from_this()));
+ } else if (node->is_parameter()) {
+ subgraph._parameters.emplace_back(
+ std::dynamic_pointer_cast<ngraph::op::v0::Parameter>(node->shared_from_this()));
+ }
+ auto itAffinity = affinities.find(node);
+ if (itAffinity != affinities.end()) {
+ subgraph._affinity = itAffinity->second;
+ }
+ }
+
+ // Subgraph topological sort
+ std::vector<Subgraph> allSubgraphs;
+ for (auto&& subgraph : subgraphs) {
+ allSubgraphs.emplace_back(std::move(subgraph.second));
+ }
+
+ std::vector<Subgraph> orderedSubgraphs;
+ NodeSet prevResults;
+ int subgraphTopoSortsStep = 0;
+ do {
+ IE_ASSERT(subgraphTopoSortsStep++ < subgraphs.size());
+ std::vector<Subgraph> nextSubgraphs;
+ auto IsNextSubGraph = [&] (const Subgraph& subgraph) {
+ auto& parameters = subgraph._parameters;
+ return std::all_of(parameters.begin(), parameters.end(),
+ [&] (const ngraph::ParameterVector::value_type& parameter) {
+ return contains(graphInputNodes, parameter.get()) ||
+ contains(prevResults, subgraphParameterToPrevResult[parameter.get()]);});
+ };
+ std::remove_copy_if(std::begin(allSubgraphs), std::end(allSubgraphs),
+ std::back_inserter(nextSubgraphs),
+ [&] (const Subgraph& subgraph) { return !IsNextSubGraph(subgraph);});
+ allSubgraphs.erase(
+ std::remove_if(std::begin(allSubgraphs), std::end(allSubgraphs), IsNextSubGraph),
+ std::end(allSubgraphs));
+ for (auto&& subgraph : nextSubgraphs) {
+ for (auto&& result : subgraph._results) {
+ prevResults.insert(result.get());
+ }
+ }
+ std::move(std::begin(nextSubgraphs), std::end(nextSubgraphs), std::back_inserter(orderedSubgraphs));
+ } while (!allSubgraphs.empty());
+
+ InputsDataMap externalInputsData;
+ network.getInputsInfo(externalInputsData);
+ networks.resize(orderedSubgraphs.size());
+ std::vector<std::shared_ptr<const ngraph::Function>> subFunctions(orderedSubgraphs.size());
+ std::vector<bool> isInputSubnetwork(orderedSubgraphs.size());
+ int id = 0;
+ for (auto&& subgraph : orderedSubgraphs) {
+ networks[id]._device = subgraph._affinity;
+ subFunctions[id] =
+ std::make_shared<const ngraph::Function>(subgraph._results, subgraph._parameters,
+ _name + '_' + std::to_string(id));
+ networks[id]._clonedNetwork = CNNNetwork{subFunctions[id]};
+ // update of pre-processing info
+ auto clonedInputs = networks[id]._clonedNetwork.getInputsInfo();
+ for (auto&& externalInput : externalInputsData) {
+ auto itClonedInput = clonedInputs.find(externalInput.first);
+ if (itClonedInput != clonedInputs.end() && nullptr != itClonedInput->second) {
+ itClonedInput->second->getPreProcess() = externalInput.second->getPreProcess();
+ itClonedInput->second->setPrecision(externalInput.second->getPrecision());
+ }
+ }
+
+ isInputSubnetwork[id] = std::any_of(std::begin(subgraph._parameters),
+ std::end(subgraph._parameters),
+ [&] (const std::shared_ptr<ngraph::op::v0::Parameter>& p) {
+ return contains(graphInputNodes, p.get());
+ });
+ ++id;
+ }
+ if (dumpDotFile) {
+ std::ofstream ofstream{"hetero_subgraphs_" + _name + ".dot"};
+ dumpGraph(network, subFunctions, ofstream);
+ }
+ for (auto&& network : networks) {
+ auto cfg = _config;
+ cfg[CONFIG_KEY_INTERNAL(SUBNETWORK_WITH_NETWORK_INPUTS)]
+ = isInputSubnetwork[std::distance(networks.data(), &network)] ? CONFIG_VALUE(YES) : CONFIG_VALUE(NO);
+ auto metaDevices = _heteroPlugin->GetDevicePlugins(network._device, cfg);
+ network._network = _heteroPlugin->GetCore()->LoadNetwork(network._clonedNetwork,
+ network._device, metaDevices[network._device]);
+ }
+}
+
+HeteroExecutableNetwork::HeteroExecutableNetwork(const InferenceEngine::ICNNNetwork& network,
+ const Engine::Configs& config,
+ Engine* plugin):
+ InferenceEngine::ExecutableNetworkThreadSafeDefault(
+ nullptr, std::make_shared<InferenceEngine::ImmediateExecutor>()),
+ _heteroPlugin{plugin},
+ _name{network.getName()},
+ _config{config} {
+ if (network.getFunction() == nullptr) {
+ InitCNNImpl(network);
+ } else {
+ InitNgraph(network);
+ }
+}
+
HeteroExecutableNetwork::HeteroExecutableNetwork(std::istream& heteroModel,
const std::map<std::string, std::string>& configs,
Engine* heteroPlugin) :
}
return std::make_shared<HeteroInferRequest>(networkInputs,
networkOutputs,
- inferRequests);
+ inferRequests,
+ _blobNameMap);
}
void HeteroExecutableNetwork::CreateInferRequest(IInferRequest::Ptr &asyncRequest) {
HeteroExecutableNetwork(const InferenceEngine::ICNNNetwork& network,
const std::map<std::string, std::string>& config,
Engine* plugin);
-
/**
* @brief Import from opened file constructor
*/
void ExportImpl(std::ostream& modelFile) override;
private:
+ void InitCNNImpl(const InferenceEngine::ICNNNetwork& network);
+
+ void InitNgraph(const InferenceEngine::ICNNNetwork& network);
+
struct NetworkDesc {
std::string _device;
InferenceEngine::CNNNetwork _clonedNetwork;
Engine* _heteroPlugin;
std::string _name;
std::map<std::string, std::string> _config;
+ std::unordered_map<std::string, std::string> _blobNameMap;
};
} // namespace HeteroPlugin
#include <ie_util_internal.hpp>
#include <description_buffer.hpp>
#include <ie_layouts.h>
+#include <ie_algorithm.hpp>
#include <cassert>
#include <map>
#include <string>
using namespace HeteroPlugin;
using namespace InferenceEngine;
+using namespace InferenceEngine::details;
HeteroInferRequest::HeteroInferRequest(InferenceEngine::InputsDataMap networkInputs,
InferenceEngine::OutputsDataMap networkOutputs,
- const SubRequestsList &inferRequests) :
- InferRequestInternal(networkInputs, networkOutputs),
- _inferRequests(inferRequests) {
+ const SubRequestsList& inferRequests,
+ const std::unordered_map<std::string, std::string>& subgraphInputToOutputBlobNames) :
+ InferRequestInternal(networkInputs, networkOutputs),
+ _inferRequests(inferRequests) {
if (_networkOutputs.empty() || _networkInputs.empty()) {
THROW_IE_EXCEPTION << "Internal error: no information about network's output/input";
}
- auto requestBlob([&](const std::string &e, InferenceEngine::InferRequest::Ptr r) {
- if (networkInputs.find(e) != networkInputs.end()) {
- if (_blobs.find(e) != _blobs.end()) {
- r->SetBlob(e.c_str(), _blobs[e]);
- } else {
- _blobs[e] = r->GetBlob(e.c_str());
- _inputs[e] = _blobs[e];
- }
- } else if (networkOutputs.find(e) != networkOutputs.end()) {
- if (_blobs.find(e) != _blobs.end()) {
- r->SetBlob(e.c_str(), _blobs[e]);
- } else {
- _blobs[e] = r->GetBlob(e.c_str());
- _outputs[e] = _blobs[e];
+ auto requestBlob([&](const std::string& blobName, InferenceEngine::InferRequest::Ptr r) {
+ std::string intermediateBlobName = blobName;
+ auto itName = subgraphInputToOutputBlobNames.find(blobName);
+ if (itName != subgraphInputToOutputBlobNames.end()) {
+ intermediateBlobName = itName->second;
+ }
+ BlobMap::iterator itBlob;
+ bool emplaced = false;
+ std::tie(itBlob, emplaced) = _blobs.emplace(intermediateBlobName, Blob::Ptr{});
+ if (emplaced) {
+ itBlob->second = r->GetBlob(blobName);
+ if (contains(networkInputs, blobName)) {
+ _inputs[blobName] = itBlob->second;
+ } else if (contains(networkOutputs, blobName)) {
+ _outputs[blobName] = itBlob->second;
}
} else {
- if (_blobs.find(e) != _blobs.end()) {
- r->SetBlob(e.c_str(), _blobs[e]);
- } else {
- _blobs[e] = r->GetBlob(e.c_str());
- }
+ r->SetBlob(blobName, itBlob->second);
}
});
#include <string>
#include <vector>
#include <memory>
-#include <unordered_set>
+#include <unordered_map>
#include <ie_common.h>
#include <cpp_interfaces/impl/ie_infer_request_internal.hpp>
#include <cpp_interfaces/impl/ie_executable_network_internal.hpp>
explicit HeteroInferRequest(InferenceEngine::InputsDataMap networkInputs,
InferenceEngine::OutputsDataMap networkOutputs,
- const SubRequestsList &inferRequests);
+ const SubRequestsList &inferRequests,
+ const std::unordered_map<std::string, std::string>& blobNameMap);
void InferImpl() override;
void updateInOutIfNeeded();
SubRequestsList _inferRequests;
- std::map<std::string, InferenceEngine::Blob::Ptr> _blobs;
+ std::map<std::string, InferenceEngine::Blob::Ptr> _blobs;
};
} // namespace HeteroPlugin
#include "hetero/hetero_plugin_config.hpp"
#include <cpp_interfaces/base/ie_plugin_base.hpp>
#include "hetero_executable_network.hpp"
+#include "convert_function_to_cnn_network.hpp"
+#include <generic_ie.hpp>
+#include <transformations/common_optimizations/common_optimizations.hpp>
+#include <transformations/convert_opset1_to_legacy/convert_opset1_to_legacy.hpp>
+#include <transformations/convert_opset2_to_opset1/convert_opset2_to_opset1.hpp>
+#include <transformations/convert_opset3_to_opset2/convert_opset3_to_opset2.hpp>
using namespace InferenceEngine;
using namespace InferenceEngine::PluginConfigParams;
if (GetCore() == nullptr) {
THROW_IE_EXCEPTION << "Please, work with HETERO device via InferencEngine::Core object";
}
-
- return std::make_shared<HeteroExecutableNetwork>(*cloneNet(network), mergeConfigs(_config, config), this);
+ auto tconfig = mergeConfigs(_config, config);
+ auto it = tconfig.find("TARGET_FALLBACK");
+ if (it == tconfig.end()) {
+ THROW_IE_EXCEPTION << "The 'TARGET_FALLBACK' option was not defined for heterogeneous plugin";
+ }
+ DeviceMetaInformationMap metaDevices = GetDevicePlugins(it->second, tconfig);
+
+ auto function = network.getFunction();
+ if (function != nullptr) {
+ auto anyDeviceDoNotSupportNgraph =
+ std::any_of(std::begin(metaDevices), std::end(metaDevices),
+ [&] (const DeviceMetaInformationMap::value_type& metaDevice) {
+ auto& deviceName = metaDevice.first;
+ auto clonedNetwork = cloneNetwork(network);
+ GetCore()->QueryNetwork(*clonedNetwork, deviceName, metaDevice.second);
+ return (clonedNetwork->getFunction() == nullptr);
+ });
+ if (anyDeviceDoNotSupportNgraph) {
+ auto clonedNetwork = cloneNetwork(network);
+ auto function = clonedNetwork->getFunction();
+ ::ngraph::op::GenericIE::DisableReshape noReshape(function);
+ ::ngraph::pass::CommonOptimizations().run_on_function(function);
+ ::ngraph::pass::ConvertOpSet3ToOpSet2().run_on_function(function);
+ ::ngraph::pass::ConvertOpSet2ToOpSet1().run_on_function(function);
+ ::ngraph::pass::ConvertOpSet1ToLegacy().run_on_function(function);
+ return std::make_shared<HeteroExecutableNetwork>(
+ *InferenceEngine::details::convertFunctionToICNNNetwork(function, *clonedNetwork),
+ mergeConfigs(_config, config), this);
+ } else {
+ return std::make_shared<HeteroExecutableNetwork>(*cloneNetwork(network), mergeConfigs(_config, config), this);
+ }
+ } else {
+ return std::make_shared<HeteroExecutableNetwork>(network, mergeConfigs(_config, config), this);
+ }
}
ExecutableNetwork Engine::ImportNetworkImpl(std::istream& heteroModel, const Configs& config) {
// go over devices and call query network
for (auto&& metaDevice : metaDevices) {
auto& deviceName = metaDevice.first;
- queryResults[deviceName] = GetCore()->QueryNetwork(network, deviceName, metaDevice.second);
+ auto clonedNetwork = cloneNetwork(network);
+ queryResults[deviceName] = GetCore()->QueryNetwork(*clonedNetwork, deviceName, metaDevice.second);
}
// WARNING: Here is devices with user set priority
auto fallbackDevices = InferenceEngine::DeviceIDParser::getHeteroDevices(fallbackDevicesStr);
- details::CNNNetworkIterator i(&network);
- while (i != details::CNNNetworkIterator()) {
- CNNLayer::Ptr layer = *i;
- for (auto&& deviceName : fallbackDevices) {
- auto& deviceQueryResult = queryResults[deviceName];
- if (deviceQueryResult.supportedLayersMap.find(layer->name) != deviceQueryResult.supportedLayersMap.end()) {
- qr.supportedLayersMap[layer->name] = deviceName;
- break;
- }
+ for (auto&& deviceName : fallbackDevices) {
+ for (auto&& layerQueryResult : queryResults[deviceName].supportedLayersMap) {
+ qr.supportedLayersMap.emplace(layerQueryResult);
}
- i++;
}
// set OK status
#include <transformations/convert_opset1_to_legacy/convert_opset1_to_legacy.hpp>
#include <transformations/convert_opset2_to_opset1/convert_opset2_to_opset1.hpp>
#include <transformations/convert_opset3_to_opset2/convert_opset3_to_opset2.hpp>
+#include <transformations/rt_info/fused_names_attribute.hpp>
#include <ngraph/opsets/opset1.hpp>
#include <ngraph/opsets/opset2.hpp>
#include <ngraph/opsets/opset3.hpp>
ExecutorManager::getInstance()->clear("CPUCallbackExecutor");
}
+static void Transformation(ICNNNetwork::Ptr& clonedNetwork) {
+ const auto transformations_callback = [](const std::shared_ptr<const ::ngraph::Node> &node) -> bool {
+ // DepthToSpace node implementation supports only equal input/output tensors with rank <= 5
+ if (auto dtsOp = std::dynamic_pointer_cast<const ::ngraph::opset3::DepthToSpace>(node)) {
+ return dtsOp->input_value(0).get_shape().size() <= 5lu && dtsOp->input_value(0).get_shape().size() == dtsOp->get_output_shape(0).size();
+ }
+
+ // SpaceToDepth node implementation supports only equal input/output tensors with rank <= 5
+ if (auto stdOp = std::dynamic_pointer_cast<const ::ngraph::opset3::SpaceToDepth>(node)) {
+ return stdOp->input_value(0).get_shape().size() <= 5lu && stdOp->input_value(0).get_shape().size() == stdOp->get_output_shape(0).size();
+ }
+
+ if (auto fc_op = std::dynamic_pointer_cast<const ngraph::op::FullyConnected>(node)) {
+ return fc_op->input_value(0).get_shape().size() == 3ul;
+ }
+
+ return std::dynamic_pointer_cast<const ::ngraph::opset2::Gelu>(node) ||
+ std::dynamic_pointer_cast<const ::ngraph::opset2::BatchToSpace>(node) ||
+ std::dynamic_pointer_cast<const ::ngraph::opset2::SpaceToBatch>(node);
+ };
+ auto nGraphFunc = clonedNetwork->getFunction();
+ // Disable shape inference (WA for generic operations)
+ ::ngraph::op::GenericIE::DisableReshape noReshape(nGraphFunc);
+
+ // Note: instead of running all Conversion Transformations you can make up your own transformation pipeline
+ ngraph::pass::CommonOptimizations(transformations_callback).run_on_function(nGraphFunc);
+ ngraph::pass::ConvertOpSet3ToOpSet2(transformations_callback).run_on_function(nGraphFunc);
+ ngraph::pass::ConvertOpSet2ToOpSet1(transformations_callback).run_on_function(nGraphFunc);
+ ngraph::pass::ConvertOpSet1ToLegacy(transformations_callback).run_on_function(nGraphFunc);
+ clonedNetwork = InferenceEngine::details::convertFunctionToICNNNetwork(nGraphFunc, *clonedNetwork);
+}
+
InferenceEngine::ExecutableNetworkInternal::Ptr
Engine::LoadExeNetworkImpl(const InferenceEngine::ICNNNetwork &network, const std::map<std::string, std::string> &config) {
// verification of supported input
}
std::shared_ptr<ICNNNetwork> clonedNetwork = cloneNetwork(network);
-
if (clonedNetwork->getFunction()) {
- const auto transformations_callback = [](const std::shared_ptr<const ::ngraph::Node> &node) -> bool {
- // DepthToSpace node implementation supports only equal input/output tensors with rank <= 5
- if (auto dtsOp = std::dynamic_pointer_cast<const ::ngraph::opset3::DepthToSpace>(node)) {
- return dtsOp->input_value(0).get_shape().size() <= 5lu && dtsOp->input_value(0).get_shape().size() == dtsOp->get_output_shape(0).size();
- }
-
- // SpaceToDepth node implementation supports only equal input/output tensors with rank <= 5
- if (auto stdOp = std::dynamic_pointer_cast<const ::ngraph::opset3::SpaceToDepth>(node)) {
- return stdOp->input_value(0).get_shape().size() <= 5lu && stdOp->input_value(0).get_shape().size() == stdOp->get_output_shape(0).size();
- }
-
- if (auto fc_op = std::dynamic_pointer_cast<const ngraph::op::FullyConnected>(node)) {
- return fc_op->input_value(0).get_shape().size() == 3ul;
- }
-
- return std::dynamic_pointer_cast<const ::ngraph::opset2::Gelu>(node) ||
- std::dynamic_pointer_cast<const ::ngraph::opset2::BatchToSpace>(node) ||
- std::dynamic_pointer_cast<const ::ngraph::opset2::SpaceToBatch>(node);
- };
- auto nGraphFunc = clonedNetwork->getFunction();
- // Disable shape inference (WA for generic operations)
- ::ngraph::op::GenericIE::DisableReshape noReshape(nGraphFunc);
-
- // Note: instead of running all Conversion Transformations you can make up your own transformation pipeline
- ngraph::pass::CommonOptimizations(transformations_callback).run_on_function(nGraphFunc);
- ngraph::pass::ConvertOpSet3ToOpSet2(transformations_callback).run_on_function(nGraphFunc);
- ngraph::pass::ConvertOpSet2ToOpSet1(transformations_callback).run_on_function(nGraphFunc);
- ngraph::pass::ConvertOpSet1ToLegacy(transformations_callback).run_on_function(nGraphFunc);
- clonedNetwork = InferenceEngine::details::convertFunctionToICNNNetwork(nGraphFunc, *clonedNetwork);
+ Transformation(clonedNetwork);
}
-
auto implNetwork = std::dynamic_pointer_cast<details::CNNNetworkImpl>(clonedNetwork);
if (implNetwork) {
// valid for CNNNetworkImpl only, while there's no API in ICNNNetwork to change network
}
void Engine::QueryNetwork(const ICNNNetwork& network, const std::map<std::string, std::string>& config, QueryNetworkResult& res) const {
- details::CNNNetworkIterator i(&network);
- while (i != details::CNNNetworkIterator()) {
- try {
- mkldnn::engine eng(mkldnn::engine(mkldnn::engine::kind::cpu, 0));
- MKLDNNWeightsSharing::Ptr fake_w_cache;
-
- // if we can create and have not thrown exception, then layer is supported
- std::unique_ptr <MKLDNNNode>(MKLDNNNode::CreateNode(*i, eng, extensionManager, fake_w_cache));
- res.supportedLayersMap.insert({ (*i)->name, GetName() });
- } catch (InferenceEngine::details::InferenceEngineException&) {
+ MKLDNNWeightsSharing::Ptr fake_w_cache;
+ auto function = network.getFunction();
+ if (function != nullptr) {
+ std::unordered_set<std::string> originalOps;
+ for (auto&& node : function->get_ops()) {
+ if (!node->is_constant() && !node->is_parameter() && !node->is_output()) {
+ originalOps.emplace(node->get_friendly_name());
+ }
+ }
+ auto clonedNetwork = cloneNetwork(network);
+ Transformation(clonedNetwork);
+ std::unordered_set<std::string> supported;
+ std::unordered_set<std::string> unsupported;
+ for (details::CNNNetworkIterator itLayer{clonedNetwork.get()}; itLayer != details::CNNNetworkIterator(); itLayer++) {
+ auto layerIsSupported = [&] {
+ std::unique_ptr<MKLDNNNode> ptr;
+ try {
+ ptr.reset(MKLDNNNode::CreateNode(*itLayer, {mkldnn::engine::kind::cpu, 0}, extensionManager, fake_w_cache));
+ } catch (InferenceEngine::details::InferenceEngineException&) {
+ return false;
+ }
+ return true;
+ } ();
+ for (auto&& fusedLayerName : ngraph::getFusedNamesVector((*itLayer)->getNode())) {
+ if (contains(originalOps, fusedLayerName)) {
+ if (layerIsSupported) {
+ supported.emplace(fusedLayerName);
+ } else {
+ unsupported.emplace(fusedLayerName);
+ }
+ }
+ }
+ }
+ for (auto&& layerName : supported) {
+ if (!contains(unsupported, layerName)) {
+ res.supportedLayersMap.emplace(layerName, GetName());
+ }
+ }
+ } else {
+ details::CNNNetworkIterator i(&network);
+ while (i != details::CNNNetworkIterator()) {
+ try {
+ mkldnn::engine eng(mkldnn::engine(mkldnn::engine::kind::cpu, 0));
+ // if we can create and have not thrown exception, then layer is supported
+ std::unique_ptr <MKLDNNNode>(MKLDNNNode::CreateNode(*i, eng, extensionManager, fake_w_cache));
+ res.supportedLayersMap.insert({ (*i)->name, GetName() });
+ } catch (InferenceEngine::details::InferenceEngineException&) {
+ }
+ i++;
}
- i++;
}
}
#include <utility>
#include <map>
#include <unordered_map>
+#include <unordered_set>
#include "ie_metric_helpers.hpp"
#include <ie_api.h>
THROW_IE_EXCEPTION << "Please, work with MULTI device via InferencEngine::Core object";
}
- // TODO: do we really need a clone?
- ICNNNetwork::Ptr clonedNetwork = cloneNet(network);
-
auto fullConfig = mergeConfigs(_config, config);
auto priorities = fullConfig.find(MultiDeviceConfigParams::KEY_MULTI_DEVICE_PRIORITIES);
if (priorities == fullConfig.end()) {
auto & deviceName = p.first;
auto & metaDevice = p.second;
auto & deviceConfig = metaDevice.config;
+ auto clonedNetwork = cloneNetwork(network);
executableNetworkPerDevice.insert({ deviceName, GetCore()->LoadNetwork(CNNNetwork{clonedNetwork}, deviceName, deviceConfig) });
multiNetworkConfig.insert(deviceConfig.begin(), deviceConfig.end());
}
}
DeviceMap<DeviceInformation> metaDevices = ParseMetaDevices(priorities->second, fullConfig);
- std::map<std::string, QueryNetworkResult> queryResults;
-
+ std::unordered_set<std::string> supportedLayers;
for (auto&& value : metaDevices) {
auto& deviceName = value.first;
auto& metaDevice = value.second;
- queryResults[deviceName] = GetCore()->QueryNetwork(network, deviceName, metaDevice.config);
- }
-
- details::CNNNetworkIterator i(&network);
- while (i != details::CNNNetworkIterator()) {
- CNNLayer::Ptr layer = *i;
- bool layerIsInQueryResultsForAllDevices = std::all_of(std::begin(queryResults), std::end(queryResults),
- [&](const std::map<std::string, QueryNetworkResult>::value_type& qr) {
- return qr.second.supportedLayersMap.end() != qr.second.supportedLayersMap.find(layer->name);});
- if (layerIsInQueryResultsForAllDevices) {
- queryResult.supportedLayersMap[layer->name] = GetName();
+ auto clonedNetwork = cloneNetwork(network);
+ auto deviceQr = GetCore()->QueryNetwork(*clonedNetwork, deviceName, metaDevice.config);
+ std::unordered_set<std::string> deviceSupportedLayers;
+ for (auto&& layerQr : deviceQr.supportedLayersMap) {
+ deviceSupportedLayers.emplace(layerQr.first);
}
- i++;
+ supportedLayers = supportedLayers.empty()
+ ? deviceSupportedLayers : (deviceSupportedLayers.empty()
+ ? supportedLayers : Intersection(supportedLayers, deviceSupportedLayers));
+ }
+ for (auto&& supportedLayer : supportedLayers) {
+ queryResult.supportedLayersMap[supportedLayer] = GetName();
}
}
} // namespace MultiDevicePlugin
(*idx) = ((*idx) < max) ? (*idx) : (max - 1);
}
+/**
+ * @brief Set containers intersection
+ * @tparam Set
+ * @param lhs First set container
+ * @param rhs Second set container
+ * @return Set intersection
+ */
+template<typename Set>
+static Set Intersection(const Set& lhs, const Set& rhs) {
+ Set result;
+ const auto& minSizeSet = (lhs.size() < rhs.size()) ? lhs : rhs;
+ const auto& maxSizeSet = (lhs.size() >= rhs.size()) ? lhs : rhs;
+ for (auto&& val : minSizeSet) {
+ if (contains(maxSizeSet, val)) {
+ result.insert(val);
+ }
+ }
+ return result;
+}
+
+/**
+ * @brief Check whether two sets intersect
+ * @tparam Set
+ * @param lhs First set container
+ * @param rhs Second set container
+ * @return true if two sets interesect false otherwise
+ */
+template<typename Set>
+static bool Intersects(const Set& lhs, const Set& rhs) {
+ const auto& minSizeSet = (lhs.size() < rhs.size()) ? lhs : rhs;
+ const auto& maxSizeSet = (lhs.size() >= rhs.size()) ? lhs : rhs;
+ for (auto&& val : minSizeSet) {
+ if (contains(maxSizeSet, val)) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace details
} // namespace InferenceEngine
--- /dev/null
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <vector>
+
+#include "hetero/query_network.hpp"
+#include "ngraph_functions/builders.hpp"
+#include "ngraph_functions/subgraph_builders.hpp"
+
+namespace {
+using namespace HeteroTests;
+
+auto ConvBias = ngraph::builder::subgraph::makeConvBias();
+
+INSTANTIATE_TEST_CASE_P(smoke_FullySupportedTopologies, QueryNetworkTest,
+ ::testing::Combine(
+ ::testing::Values("CPU", "HETERO:CPU", "MULTI:CPU"),
+ ::testing::Values(ConvBias)),
+ QueryNetworkTest::getTestCaseName);
+} // namespace
--- /dev/null
+// Copyright (C) 2020 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include <vector>
+
+#include "hetero/synthetic.hpp"
+#include "ngraph_functions/builders.hpp"
+#include "ngraph_functions/subgraph_builders.hpp"
+
+namespace {
+using namespace HeteroTests;
+
+INSTANTIATE_TEST_CASE_P(smoke_SingleMajorNode, HeteroSyntheticTest,
+ ::testing::Combine(
+ ::testing::Values(std::vector<PluginParameter>{{"CPU0", "MKLDNNPlugin"}, {"CPU1", "MKLDNNPlugin"}}),
+ ::testing::ValuesIn(HeteroTests::HeteroSyntheticTest::_singleMajorNodeFunctions)),
+ HeteroSyntheticTest::getTestCaseName);
+
+INSTANTIATE_TEST_CASE_P(nightly_RandomMajorNodes, HeteroSyntheticTest,
+ ::testing::Combine(
+ ::testing::Values(std::vector<PluginParameter>{{"CPU0", "MKLDNNPlugin"}, {"CPU1", "MKLDNNPlugin"}}),
+ ::testing::ValuesIn(HeteroTests::HeteroSyntheticTest::_randomMajorNodeFunctions)),
+ HeteroSyntheticTest::getTestCaseName);
+} // namespace
// Load CNNNetwork to target plugins
InferenceEngine::IExecutableNetwork::Ptr execNet;
std::map<std::string, std::string> config {};
- if (targetDevice.find(CommonTestUtils::DEVICE_MULTI) == std::string::npos ||
- targetDevice.find(CommonTestUtils::DEVICE_HETERO) == std::string::npos) {
+ if (targetDevice.find(CommonTestUtils::DEVICE_MULTI) == std::string::npos &&
+ targetDevice.find(CommonTestUtils::DEVICE_HETERO) == std::string::npos) {
ASSERT_NO_THROW(ie->SetConfig(configuration, targetDevice));
ASSERT_NO_THROW(execNet = ie->LoadNetwork(cnnNet, targetDevice, config));
} else {
- ASSERT_THROW(ie->SetConfig(configuration, targetDevice),
- InferenceEngine::details::InferenceEngineException);
+ ASSERT_NO_THROW(ie->SetConfig(configuration, targetDevice));
ASSERT_NO_THROW(execNet = ie->LoadNetwork(cnnNet, targetDevice, configuration));
}
}
InferenceEngine::IExecutableNetwork::Ptr execNet;
for (auto i = 0; i < 2; i++) {
ASSERT_NO_THROW(execNet = ie->LoadNetwork(cnnNet, targetDevice, configuration));
+ ASSERT_NE(nullptr, cnnNet.getFunction());
}
}
--- /dev/null
+// Copyright (C) 2019 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <tuple>
+#include <string>
+#include <vector>
+#include "functional_test_utils/layer_test_utils.hpp"
+#include "ngraph_functions/utils/ngraph_helpers.hpp"
+
+namespace HeteroTests {
+
+using QueryNetworkTestParameters = std::tuple<
+ std::string,
+ std::shared_ptr<ngraph::Function>
+>;
+
+struct QueryNetworkTest : public testing::WithParamInterface<QueryNetworkTestParameters>,
+ public LayerTestsUtils::LayerTestsCommon {
+ enum {Plugin, Function};
+ ~QueryNetworkTest() override = default;
+ void SetUp() override;
+ static std::string getTestCaseName(const ::testing::TestParamInfo<QueryNetworkTestParameters>& obj);
+ std::string targetDevice;
+ std::shared_ptr<ngraph::Function> function;
+ InferenceEngine::CNNNetwork cnnNetwork;
+};
+} // namespace HeteroTests
--- /dev/null
+// Copyright (C) 2019 Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#pragma once
+
+#include <tuple>
+#include <string>
+#include <vector>
+#include <unordered_set>
+#include "functional_test_utils/layer_test_utils.hpp"
+#include "ngraph_functions/utils/ngraph_helpers.hpp"
+
+namespace HeteroTests {
+
+struct PluginParameter {
+ std::string _name;
+ std::string _location;
+};
+
+struct FunctionParameter {
+ std::unordered_set<std::string> _majorPluginNodeIds;
+ std::shared_ptr<ngraph::Function> _function;
+};
+
+using HeteroSyntheticTestParameters = std::tuple<
+ std::vector<PluginParameter>,
+ FunctionParameter
+>;
+
+struct HeteroSyntheticTest : public testing::WithParamInterface<HeteroSyntheticTestParameters>,
+ public LayerTestsUtils::LayerTestsCommon {
+ enum {Plugin, Function};
+ ~HeteroSyntheticTest() override = default;
+ void SetUp() override;
+ void TearDown() override;
+ std::string SetUpAffinity();
+ static std::string getTestCaseName(const ::testing::TestParamInfo<HeteroSyntheticTestParameters>& obj);
+ static std::vector<FunctionParameter> _singleMajorNodeFunctions;
+ static std::vector<FunctionParameter> _randomMajorNodeFunctions;
+ std::vector<std::string> _registredPlugins;
+};
+
+} // namespace HeteroTests
--- /dev/null
+// Copyright (C) 2020 Intel Corporation
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "hetero/query_network.hpp"
+#include <ngraph/variant.hpp>
+#include "ngraph_functions/builders.hpp"
+#include "ngraph_functions/subgraph_builders.hpp"
+#include <random>
+namespace HeteroTests {
+
+void QueryNetworkTest::SetUp() {
+ auto& param = GetParam();
+ targetDevice = std::get<Plugin>(param);
+ function = std::get<Function>(param);
+ cnnNetwork = InferenceEngine::CNNNetwork{function};
+}
+
+std::string QueryNetworkTest::getTestCaseName(const ::testing::TestParamInfo<QueryNetworkTestParameters>& obj) {
+ return "function=" + std::get<Function>(obj.param)->get_friendly_name() + "_targetDevice=" + std::get<Plugin>(obj.param);
+}
+
+TEST_P(QueryNetworkTest, queryNetworkResultContainAllAndOnlyInputLayers) {
+ auto& param = GetParam();
+ auto queryNetworkResult = PluginCache::get().ie()->QueryNetwork(cnnNetwork, std::get<Plugin>(param));
+ ASSERT_NE(nullptr, cnnNetwork.getFunction());
+ std::set<std::string> expectedLayers;
+ for (auto&& node : function->get_ops()) {
+ if (!node->is_parameter() && !node->is_constant() && !node->is_output()) {
+ expectedLayers.insert(node->get_friendly_name());
+ }
+ }
+ std::set<std::string> actualLayers;
+ for (auto&& res : queryNetworkResult.supportedLayersMap) {
+ actualLayers.insert(res.first);
+ }
+ ASSERT_EQ(expectedLayers, actualLayers);
+}
+} // namespace HeteroTests
\ No newline at end of file
--- /dev/null
+// Copyright (C) 2020 Intel Corporation
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+
+#include "hetero/synthetic.hpp"
+#include <ngraph/variant.hpp>
+#include "ngraph_functions/builders.hpp"
+#include "ngraph_functions/subgraph_builders.hpp"
+#include <random>
+namespace HeteroTests {
+
+static std::vector<std::function<std::shared_ptr<ngraph::Function>()>> builders = {
+ [] {return ngraph::builder::subgraph::makeSplitMultiConvConcat();},
+ [] {return ngraph::builder::subgraph::makeNestedSplitConvConcat();},
+ [] {return ngraph::builder::subgraph::makeSplitConvConcatNestedInBranch();},
+ [] {return ngraph::builder::subgraph::makeSplitConvConcatNestedInBranchNestedOut();},
+};
+
+std::vector<FunctionParameter> HeteroSyntheticTest::_singleMajorNodeFunctions{[] {
+ std::vector<FunctionParameter> result;
+ for (auto&& builder : builders) {
+ auto function = builder();
+ for (auto&& node : function->get_ordered_ops()) {
+ if (!(node->is_constant()) && !(node->is_parameter()) && !(node->is_output())) {
+ result.push_back(FunctionParameter{{node->get_friendly_name()}, function});
+ }
+ }
+ }
+ return result;
+} ()};
+
+std::vector<FunctionParameter> HeteroSyntheticTest::_randomMajorNodeFunctions{[] {
+ std::vector<FunctionParameter> results;
+ for (auto p = 0.2; p < 1.; p+=0.2) {
+ std::mt19937 e{std::random_device {} ()};
+ std::bernoulli_distribution d{p};
+ for (auto&& builder : builders) {
+ auto function = builder();
+ auto ordered_ops = function->get_ordered_ops();
+ for (std::size_t i = 0; i < ordered_ops.size(); ++i) {
+ std::unordered_set<std::string> majorPluginNodeIds;
+ for (auto&& node : ordered_ops) {
+ if (!(node->is_constant()) && !(node->is_parameter()) && !(node->is_output()) && d(e)) {
+ majorPluginNodeIds.emplace(node->get_friendly_name());
+ }
+ }
+ if (std::any_of(std::begin(results), std::end(results), [&] (const FunctionParameter& param) {
+ return majorPluginNodeIds == param._majorPluginNodeIds;
+ })) {
+ continue;
+ }
+ results.push_back(FunctionParameter{majorPluginNodeIds, function});
+ }
+ }
+ }
+ return results;
+} ()};
+
+std::string HeteroSyntheticTest::getTestCaseName(const ::testing::TestParamInfo<HeteroSyntheticTestParameters>& obj) {
+ std::vector<PluginParameter> pluginParameters;
+ FunctionParameter functionParamter;
+ std::tie(pluginParameters, functionParamter) = obj.param;
+ std::string name = "function=" + functionParamter._function->get_friendly_name();
+ name += "_layers=";
+ std::size_t num = functionParamter._majorPluginNodeIds.size() - 1;
+ for (auto&& id : functionParamter._majorPluginNodeIds) {
+ name += id + ((num !=0) ? "," : "");
+ num--;
+ }
+ name += "_targetDevice=HETERO:";
+ num = pluginParameters.size() - 1;
+ for (auto&& pluginParameter : pluginParameters) {
+ name += pluginParameter._name + ((num !=0) ? "," : "");
+ num--;
+ }
+ return name;
+}
+
+void HeteroSyntheticTest::SetUp() {
+ auto& param = GetParam();
+ targetDevice = "HETERO:";
+ int num = std::get<Plugin>(param).size() - 1;
+ for (auto&& pluginParameter : std::get<Plugin>(param)) {
+ bool registred = true;
+ try {
+ PluginCache::get().ie()->RegisterPlugin(pluginParameter._location, pluginParameter._name);
+ } catch (InferenceEngine::details::InferenceEngineException& ex) {
+ if (std::string{ex.what()}.find("Device with \"" + pluginParameter._name
+ + "\" is already registered in the InferenceEngine")
+ == std::string::npos) {
+ throw ex;
+ } else {
+ registred = false;
+ }
+ }
+ if (registred) {
+ _registredPlugins.push_back(pluginParameter._name);
+ }
+ targetDevice += pluginParameter._name;
+ targetDevice += ((num !=0) ? "," : "");
+ --num;
+ }
+ function = std::get<Function>(param)._function;
+}
+
+void HeteroSyntheticTest::TearDown() {
+ for (auto&& pluginName : _registredPlugins) {
+ PluginCache::get().ie()->UnregisterPlugin(pluginName);
+ }
+}
+
+std::string HeteroSyntheticTest::SetUpAffinity() {
+ int id = 0;
+ auto& param = GetParam();
+ std::string affinities;
+ auto& pluginParameters = std::get<Plugin>(param);
+ affinities += "\n{\n";
+ for (auto&& node : std::get<Function>(param)._function->get_ordered_ops()) {
+ if (!(node->is_constant()) && !(node->is_parameter()) && !(node->is_output())) {
+ std::string affinity;
+ if (std::get<Function>(param)._majorPluginNodeIds.end() !=
+ std::get<Function>(param)._majorPluginNodeIds.find(node->get_friendly_name())) {
+ affinity = pluginParameters.at(0)._name;
+ } else {
+ affinity = pluginParameters.at(1)._name;
+ }
+ node->get_rt_info()["affinity"] = std::make_shared<ngraph::VariantWrapper<std::string>>(affinity);
+ affinities += "\t{" + node->get_friendly_name() + ",\t\t" + affinity + "}\n";
+ }
+ }
+ affinities += "}";
+ return affinities;
+}
+
+TEST_P(HeteroSyntheticTest, someLayersToMajorPluginOthersToFallback) {
+ auto affinities = SetUpAffinity();
+ SCOPED_TRACE(affinities);
+ Run();
+ ASSERT_NE(nullptr, cnnNetwork.getFunction());
+}
+
+} // namespace HeteroTests
\ No newline at end of file
InferenceEngine::ExecutableNetwork executableNetwork;
std::vector<InferenceEngine::Blob::Ptr> inputs;
float threshold;
+ InferenceEngine::CNNNetwork cnnNetwork;
virtual void Validate();
std::vector<InferenceEngine::Blob::Ptr> GetOutputs();
std::shared_ptr<InferenceEngine::Core> core;
- InferenceEngine::CNNNetwork cnnNetwork;
InferenceEngine::InferRequest inferRequest;
RefMode refMode = RefMode::INTERPRETER;
};
auto concat = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu1->output(0), relu2->output(0)}, 1);
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(concat)};
std::shared_ptr<ngraph::Function> fnPtr = std::make_shared<ngraph::Function>(results, params);
+ fnPtr->set_friendly_name("SplitConvConcat");
return fnPtr;
}
auto concat = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu1_4->output(0), relu2_4->output(0)}, 1);
ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(concat)};
std::shared_ptr<ngraph::Function> fnPtr = std::make_shared<ngraph::Function>(results, params);
+ fnPtr->set_friendly_name("SplitMultiConvConcat");
return fnPtr;
}
auto results = ngraph::ResultVector{std::make_shared<ngraph::opset1::Result>(out0),
std::make_shared<ngraph::opset1::Result>(out1)};
auto fn_ptr = std::make_shared<ngraph::Function>(results, ngraph::ParameterVector{SENT, H_init, C_init});
+ fn_ptr->set_friendly_name("TIwithLSTMcell");
return fn_ptr;
}
ngraph::op::PadType::EXPLICIT, 5);
auto result = std::make_shared<ngraph::opset1::Result>(conv1);
auto fn_ptr = std::make_shared<ngraph::Function>(ngraph::ResultVector{result}, ngraph::ParameterVector{param0});
- return
- fn_ptr;
+ fn_ptr->set_friendly_name("SingleConv");
+ return fn_ptr;
}
static std::shared_ptr<ngraph::Function> makeMultiSingleConv(std::vector<size_t> inputShape = {1, 3, 24, 24}) {
ngraph::op::PadType::EXPLICIT, 5);
auto result = std::make_shared<ngraph::opset1::Result>(conv10);
auto fn_ptr = std::make_shared<ngraph::Function>(ngraph::ResultVector{result}, ngraph::ParameterVector{param0});
- return
- fn_ptr;
+ fn_ptr->set_friendly_name("MultiSingleConv");
+ return fn_ptr;
}
static std::shared_ptr<ngraph::Function> make2InputSubtract(std::vector<size_t> inputShape = {1, 3, 24, 24},
auto param1 = std::make_shared<ngraph::opset1::Parameter>(type, ngraph::Shape(inputShape));
auto subtract = std::make_shared<ngraph::opset1::Subtract>(param0, param1);
auto result = std::make_shared<ngraph::opset1::Result>(subtract);
- return std::make_shared<ngraph::Function>(ngraph::ResultVector{result}, ngraph::ParameterVector{param0, param1});
+ auto fn_ptr = std::make_shared<ngraph::Function>(ngraph::ResultVector{result}, ngraph::ParameterVector{param0, param1});
+ fn_ptr->set_friendly_name("TwoInputSubtract");
+ return fn_ptr;
+}
+
+static std::shared_ptr<ngraph::Function> makeNestedSplitConvConcat(std::vector<size_t> inputShape = {1, 4, 20, 20},
+ InferenceEngine::Precision netPrecision = InferenceEngine::Precision::FP32) {
+ auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
+ auto params = ngraph::builder::makeParams(ngPrc, {inputShape});
+ auto split = ngraph::builder::makeSplit(params[0], ngPrc, 2, 1);
+
+ auto conv1 = ngraph::builder::makeConvolution(split->output(0), ngPrc, {3, 3}, {1, 1}, {0, 0}, {0, 0}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5);
+ auto relu1 = std::make_shared<ngraph::opset1::Relu>(conv1);
+
+ auto conv2 = ngraph::builder::makeConvolution(split->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 10);
+ auto relu2 = std::make_shared<ngraph::opset1::Relu>(conv2);
+
+ auto split2 = ngraph::builder::makeSplit(relu2, ngPrc, 2, 1);
+
+ auto conv3 = ngraph::builder::makeConvolution(split2->output(0), ngPrc, {3, 3}, {1, 1}, {0, 0}, {0, 0}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5);
+ auto relu3 = std::make_shared<ngraph::opset1::Relu>(conv3);
+
+ auto conv4 = ngraph::builder::makeConvolution(split2->output(1), ngPrc, {3, 3}, {1, 1}, {0, 0}, {0, 0}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5);
+ auto relu4 = std::make_shared<ngraph::opset1::Relu>(conv4);
+
+ auto concat = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu3->output(0), relu4->output(0)}, 1);
+
+ auto concat1 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu1->output(0), concat}, 1);
+ ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(concat1)};
+ std::shared_ptr<ngraph::Function> fnPtr = std::make_shared<ngraph::Function>(results, params);
+ fnPtr->set_friendly_name("NestedSplitConvConcat");
+ return fnPtr;
+}
+
+static std::shared_ptr<ngraph::Function> makeSplitConvConcatInputInBranch(std::vector<size_t> inputShape = {1, 4, 20, 20},
+ InferenceEngine::Precision netPrecision = InferenceEngine::Precision::FP32) {
+ auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
+ auto params = ngraph::builder::makeParams(ngPrc, {inputShape, inputShape});
+ auto split = ngraph::builder::makeSplit(params[0], ngPrc, 2, 1);
+
+ auto conv1 = ngraph::builder::makeConvolution(split->output(0), ngPrc, {3, 3}, {1, 1}, {0, 0}, {0, 0}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5);
+ auto relu1 = std::make_shared<ngraph::opset1::Relu>(conv1);
+
+ auto conv2 = ngraph::builder::makeConvolution(split->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5);
+ auto relu2 = std::make_shared<ngraph::opset1::Relu>(conv2);
+
+ auto conv4 = ngraph::builder::makeConvolution(params[1]->output(0), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5);
+ auto relu4 = std::make_shared<ngraph::opset1::Relu>(conv4);
+
+ auto concat = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu4->output(0), relu2->output(0)}, 1);
+
+ auto conv3 = ngraph::builder::makeConvolution(concat, ngPrc, {3, 3}, {1, 1}, {0, 0}, {0, 0}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5);
+ auto relu3 = std::make_shared<ngraph::opset1::Relu>(conv3);
+
+ auto concat1 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu1->output(0), relu3->output(0)}, 1);
+ ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(concat1)};
+ std::shared_ptr<ngraph::Function> fnPtr = std::make_shared<ngraph::Function>(results, params);
+ fnPtr->set_friendly_name("SplitConvConcatInputInBranch");
+ return fnPtr;
+}
+
+static std::shared_ptr<ngraph::Function> makeSplitConvConcatNestedInBranch(std::vector<size_t> inputShape = {1, 4, 20, 20},
+ InferenceEngine::Precision netPrecision = InferenceEngine::Precision::FP32) {
+ auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
+ auto params = ngraph::builder::makeParams(ngPrc, {inputShape, inputShape});
+ int localId = 0;
+ #define SET_NAME(node) node->set_friendly_name(#node + std::to_string(localId++));
+ auto split = ngraph::builder::makeSplit(params[0], ngPrc, 2, 1); SET_NAME(split);
+
+ auto conv1 = ngraph::builder::makeConvolution(split->output(0), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv1);
+ auto relu1 = std::make_shared<ngraph::opset1::Relu>(conv1); SET_NAME(relu1);
+
+ auto conv2 = ngraph::builder::makeConvolution(split->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv2);
+ auto relu2 = std::make_shared<ngraph::opset1::Relu>(conv2); SET_NAME(relu2);
+
+ auto nestedSubgraph = [&] {
+ auto split = ngraph::builder::makeSplit(params[1], ngPrc, 2, 1); SET_NAME(split);
+
+ auto conv1 = ngraph::builder::makeConvolution(split->output(0), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv1);
+ auto relu1 = std::make_shared<ngraph::opset1::Relu>(conv1); SET_NAME(relu1);
+
+ auto conv2 = ngraph::builder::makeConvolution(split->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 10); SET_NAME(conv2);
+ auto relu2 = std::make_shared<ngraph::opset1::Relu>(conv2); SET_NAME(relu2);
+
+ auto split2 = ngraph::builder::makeSplit(relu2, ngPrc, 2, 1); SET_NAME(split2);
+
+ auto conv3 = ngraph::builder::makeConvolution(split2->output(0), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv3);
+ auto relu3 = std::make_shared<ngraph::opset1::Relu>(conv3); SET_NAME(relu3);
+
+ auto conv4 = ngraph::builder::makeConvolution(split2->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv4);
+ auto relu4 = std::make_shared<ngraph::opset1::Relu>(conv4); SET_NAME(relu4);
+
+ auto concat = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu3->output(0), relu4->output(0)}, 1);
+ SET_NAME(concat);
+
+ auto concat1 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu1->output(0), concat}, 1); SET_NAME(concat1);
+
+ auto conv5 = ngraph::builder::makeConvolution(concat1, ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv5);
+ auto relu5 = std::make_shared<ngraph::opset1::Relu>(conv5); SET_NAME(relu5);
+
+ return relu5;
+ }();
+ auto concat = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{nestedSubgraph->output(0), relu2->output(0)}, 1);
+ SET_NAME(concat);
+
+ auto conv3 = ngraph::builder::makeConvolution(concat, ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv3);
+ auto relu3 = std::make_shared<ngraph::opset1::Relu>(conv3); SET_NAME(relu3);
+
+ auto concat1 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu1->output(0), relu3->output(0)}, 1); SET_NAME(concat1);
+ ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(concat1)};
+ std::shared_ptr<ngraph::Function> fnPtr = std::make_shared<ngraph::Function>(results, params);
+ fnPtr->set_friendly_name("SplitConvConcatNestedInBranch");
+ return fnPtr;
+}
+
+static std::shared_ptr<ngraph::Function> makeSplitConvConcatNestedInBranchNestedOut(
+ std::vector<size_t> inputShape = {1, 4, 20, 20},
+ InferenceEngine::Precision netPrecision = InferenceEngine::Precision::FP32) {
+ auto ngPrc = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(netPrecision);
+ auto params = ngraph::builder::makeParams(ngPrc, {inputShape, inputShape});
+ int localId = 0;
+ #define SET_NAME(node) node->set_friendly_name(#node + std::to_string(localId++));
+ auto split = ngraph::builder::makeSplit(params[0], ngPrc, 2, 1); SET_NAME(split);
+
+ auto conv1 = ngraph::builder::makeConvolution(split->output(0), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv1);
+ auto relu1 = std::make_shared<ngraph::opset1::Relu>(conv1); SET_NAME(relu1);
+
+ auto conv2 = ngraph::builder::makeConvolution(split->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 10); SET_NAME(conv2);
+ auto relu2 = std::make_shared<ngraph::opset1::Relu>(conv2); SET_NAME(relu2);
+
+ auto split3 = ngraph::builder::makeSplit(relu2, ngPrc, 2, 1); SET_NAME(split3);
+
+ auto conv32 = ngraph::builder::makeConvolution(split3->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 10); SET_NAME(conv32);
+ auto relu32 = std::make_shared<ngraph::opset1::Relu>(conv32); SET_NAME(relu32);
+
+ auto nestedSubgraph = [&] {
+ auto split = ngraph::builder::makeSplit(params[1], ngPrc, 2, 1); SET_NAME(split);
+
+ auto conv1 = ngraph::builder::makeConvolution(split->output(0), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv1);
+ auto relu1 = std::make_shared<ngraph::opset1::Relu>(conv1); SET_NAME(relu1);
+
+ auto conv2 = ngraph::builder::makeConvolution(split->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 10); SET_NAME(conv2);
+ auto relu2 = std::make_shared<ngraph::opset1::Relu>(conv2); SET_NAME(relu2);
+
+ auto split2 = ngraph::builder::makeSplit(relu2, ngPrc, 2, 1); SET_NAME(split2);
+
+ auto conv3 = ngraph::builder::makeConvolution(split2->output(0), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv3);
+ auto relu3 = std::make_shared<ngraph::opset1::Relu>(conv3); SET_NAME(relu3);
+
+ auto conv4 = ngraph::builder::makeConvolution(split2->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv4);
+ auto relu4 = std::make_shared<ngraph::opset1::Relu>(conv4); SET_NAME(relu4);
+
+ auto concat = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu3->output(0), relu4->output(0)}, 1);
+ SET_NAME(concat);
+
+ auto concat1 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu1->output(0), concat}, 1); SET_NAME(concat1);
+
+ auto conv5 = ngraph::builder::makeConvolution(concat1, ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv5);
+ auto relu5 = std::make_shared<ngraph::opset1::Relu>(conv5); SET_NAME(relu5);
+
+ return relu5;
+ }();
+
+ auto nestedSubgraph1 = [&] {
+ auto split = ngraph::builder::makeSplit(relu32, ngPrc, 2, 1); SET_NAME(split);
+
+ auto conv1 = ngraph::builder::makeConvolution(split->output(0), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv1);
+ auto relu1 = std::make_shared<ngraph::opset1::Relu>(conv1); SET_NAME(relu1);
+
+ auto conv2 = ngraph::builder::makeConvolution(split->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 10); SET_NAME(conv2);
+ auto relu2 = std::make_shared<ngraph::opset1::Relu>(conv2); SET_NAME(relu2);
+
+ auto split2 = ngraph::builder::makeSplit(relu2, ngPrc, 2, 1); SET_NAME(split2);
+
+ auto conv3 = ngraph::builder::makeConvolution(split2->output(0), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv3);
+ auto relu3 = std::make_shared<ngraph::opset1::Relu>(conv3); SET_NAME(relu3);
+
+ auto conv4 = ngraph::builder::makeConvolution(split2->output(1), ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv4);
+ auto relu4 = std::make_shared<ngraph::opset1::Relu>(conv4); SET_NAME(relu4);
+
+ auto concat = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu3->output(0), relu4->output(0)}, 1);
+ SET_NAME(concat);
+
+ auto concat1 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu1->output(0), concat}, 1); SET_NAME(concat1);
+
+ auto conv5 = ngraph::builder::makeConvolution(concat1, ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv5);
+ auto relu5 = std::make_shared<ngraph::opset1::Relu>(conv5); SET_NAME(relu5);
+
+ return relu5;
+ }();
+
+ auto concat = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{nestedSubgraph->output(0), split3->output(0)}, 1);
+ SET_NAME(concat);
+
+ auto conv3 = ngraph::builder::makeConvolution(concat, ngPrc, {3, 3}, {1, 1}, {1, 1}, {1, 1}, {1, 1},
+ ngraph::op::PadType::EXPLICIT, 5); SET_NAME(conv3);
+ auto relu3 = std::make_shared<ngraph::opset1::Relu>(conv3); SET_NAME(relu3);
+
+ auto concat1 = std::make_shared<ngraph::opset1::Concat>(ngraph::OutputVector{relu1->output(0), relu3->output(0)}, 1); SET_NAME(concat1);
+ ngraph::ResultVector results{std::make_shared<ngraph::opset1::Result>(concat1), std::make_shared<ngraph::opset1::Result>(nestedSubgraph1)};
+ std::shared_ptr<ngraph::Function> fnPtr = std::make_shared<ngraph::Function>(results, params);
+ fnPtr->set_friendly_name("SplitConvConcatNestedInBranchNestedOut");
+ return fnPtr;
+}
+
+static std::shared_ptr<ngraph::Function> makeConvBias(std::vector<size_t> inputShape = {1, 3, 24, 24},
+ InferenceEngine::Precision prc = InferenceEngine::Precision::FP32) {
+ ngraph::element::Type type = FuncTestUtils::PrecisionUtils::convertIE2nGraphPrc(prc);
+ auto parameter = ngraph::builder::makeParams(type, {inputShape});
+ parameter[0]->set_friendly_name("parameter");
+ auto weights = ngraph::opset1::Constant::create(type, ngraph::Shape{6, 3, 1, 1}, {1});
+ auto biases = ngraph::opset1::Constant::create(type, ngraph::Shape{6, 1, 1}, {1});
+ auto conv = std::make_shared<ngraph::opset1::Convolution>(parameter[0], weights, ngraph::Strides{1, 1},
+ ngraph::CoordinateDiff{0, 0}, ngraph::CoordinateDiff{0, 0}, ngraph::Strides{1, 1});
+ conv->set_friendly_name("conv");
+ auto add = std::make_shared<ngraph::opset1::Add>(conv, biases);
+ add->set_friendly_name("add");
+ auto result = std::make_shared<ngraph::opset1::Result>(add);
+ result->set_friendly_name("result");
+ std::shared_ptr<ngraph::Function> fn_ptr = std::make_shared<ngraph::Function>(ngraph::ResultVector{result}, ngraph::ParameterVector{parameter});
+ fn_ptr->set_friendly_name("ConvBias");
+ return fn_ptr;
}
} // namespace subgraph
} // namespace builder
// Quite simple network
{
std::shared_ptr<ngraph::Function> fnPtr = ngraph::builder::subgraph::makeSingleConv();
- fnPtr->set_friendly_name("simpleNetwork");
ASSERT_NO_THROW(simpleNetwork = CNNNetwork(fnPtr));
}
std::string networkname = p;
std::cout << "Exe network name: " << std::endl << networkname << std::endl;
- ASSERT_EQ("simpleNetwork", networkname);
+ ASSERT_EQ(simpleNetwork.getName(), networkname);
ASSERT_EXEC_METRIC_SUPPORTED(EXEC_NETWORK_METRIC_KEY(NETWORK_NAME));
}
}
}
-TEST_P(IEClassLoadNetworkTest, QueryNetworkHETEROwithMULTINoThrowv10) {
+TEST_P(IEClassLoadNetworkTest, DISABLED_QueryNetworkHETEROWithMULTINoThrowV10) {
CHECK_MULTI();
Core ie;
devices += ',';
}
}
-
+ auto function = irv10Network.getFunction();
+ ASSERT_NE(nullptr, function);
+ std::unordered_set<std::string> expectedLayers;
+ for (auto&& node : function->get_ops()) {
+ if (!node->is_constant() && !node->is_parameter() && !node->is_output()) {
+ expectedLayers.emplace(node->get_friendly_name());
+ }
+ }
QueryNetworkResult result;
ASSERT_NO_THROW(result = ie.QueryNetwork(irv10Network, "HETERO", {
{MULTI_CONFIG_KEY(DEVICE_PRIORITIES), devices},
{ "TARGET_FALLBACK", "MULTI,CPU" }}));
+ std::unordered_set<std::string> actualLayers;
for (auto && layer : result.supportedLayersMap) {
- IE_SUPPRESS_DEPRECATED_START
- EXPECT_NO_THROW(irv10Network.getLayerByName(layer.first.c_str()));
- IE_SUPPRESS_DEPRECATED_END
+ actualLayers.emplace(layer.first);
}
+ ASSERT_EQ(expectedLayers, actualLayers);
} else {
GTEST_SKIP();
}
}
-TEST_P(IEClassLoadNetworkTest, DISABLED_QueryNetworkMULTIwithHETERONoThrowv10) {
+TEST_P(IEClassLoadNetworkTest, DISABLED_QueryNetworkMULTIWithHETERONoThrowV10) {
CHECK_MULTI();
Core ie;
devices += ',';
}
}
-
- // TODO: remove once HETERO and MULTI support v10
- irv10Network.getLayerByName("param0");
-
- std::vector<std::string> names;
- if (auto ngraphFunction = irv10Network.getFunction()) {
- for (auto && op : irv10Network.getFunction()->get_ops()) {
- names.push_back(op->get_friendly_name());
+ auto function = irv10Network.getFunction();
+ ASSERT_NE(nullptr, function);
+ std::unordered_set<std::string> expectedLayers;
+ for (auto&& node : function->get_ops()) {
+ if (!node->is_constant() && !node->is_parameter() && !node->is_output()) {
+ expectedLayers.emplace(node->get_friendly_name());
}
- } else {
- IE_SUPPRESS_DEPRECATED_START
- auto i = irv10Network.begin();
- while (i != irv10Network.end()) {
- CNNLayerPtr layer = *i;
- names.push_back(layer->name);
- ++i;
- }
- IE_SUPPRESS_DEPRECATED_END
}
-
QueryNetworkResult result;
ASSERT_NO_THROW(result = ie.QueryNetwork(irv10Network, "MULTI", {
{MULTI_CONFIG_KEY(DEVICE_PRIORITIES), devices},
{ "TARGET_FALLBACK", deviceName + ",CPU" }}));
- // check that all supported layers are in network
+ std::unordered_set<std::string> actualLayers;
for (auto && layer : result.supportedLayersMap) {
- EXPECT_NE(std::end(names), std::find(names.begin(), names.end(), layer.first));
- }
-
- // check that network layers are supported
- for (auto && name : names) {
- bool layerIsFound = result.supportedLayersMap.end() !=
- std::find_if(result.supportedLayersMap.begin(), result.supportedLayersMap.end(),
- [&](const std::pair<std::string, std::string> & p) {
- return name == p.first;
- });
- EXPECT_TRUE(layerIsFound);
+ actualLayers.emplace(layer.first);
}
+ ASSERT_EQ(expectedLayers, actualLayers);
} else {
GTEST_SKIP();
}