Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / cldnn_engine / cldnn_engine.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include <limits>
6 #include <algorithm>
7
8 #include <string>
9 #include <map>
10 #include <vector>
11 #include <iostream>
12 #include <cmath>
13 #include <debug.h>
14 #include <ie_data.h>
15 #include <cpp/ie_cnn_network.h>
16 #include <description_buffer.hpp>
17 #include <memory>
18 #include <cpp_interfaces/base/ie_plugin_base.hpp>
19 #include "ie_plugin.hpp"
20 #include "ie_plugin_config.hpp"
21 #include "details/caseless.hpp"
22 #include <details/ie_cnn_network_tools.h>
23
24 #undef min
25 #undef max
26
27 #include "cldnn_engine.h"
28 #include "cldnn_graph.h"
29 #include "cldnn_custom_layer.h"
30
31 #ifdef __linux__
32 #include <dlfcn.h>
33 #endif
34
35 using InferenceEngine::DescriptionBuffer;
36 using InferenceEngine::TBlob;
37 using InferenceEngine::Blob;
38 using namespace InferenceEngine;
39 using namespace details;
40
41 namespace CLDNNPlugin {
42
43 struct clDNNEngine::impl {
44     CLDNNGraph::Config m_config;
45 };
46
47 clDNNEngine::clDNNEngine() {
48     _impl = new impl;
49
50     // locate global custom kernel config
51     // and auto-load kernels from it
52 #ifdef _WIN32
53     CHAR mpath[MAX_PATH + 1];
54     HMODULE nModule;
55     GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
56         (LPCSTR)CLDNNCustomLayer::LoadFromFile,
57         &nModule);
58     GetModuleFileName(nModule, mpath, sizeof(mpath));
59 #elif __linux__
60     Dl_info dl_info;
61     dladdr(reinterpret_cast<void *>(CLDNNCustomLayer::LoadFromFile), &dl_info);
62     const char* mpath = dl_info.dli_fname;
63 #endif
64     std::string configFile(mpath);
65     std::size_t dir_split_pos = configFile.find_last_of("/\\");
66     std::string config_path;
67
68     if (dir_split_pos != std::string::npos) {
69         // path contains directory
70         config_path = configFile.substr(0, dir_split_pos);
71     }
72     config_path += "/cldnn_global_custom_kernels/cldnn_global_custom_kernels.xml";
73     CLDNNCustomLayer::LoadFromFile(config_path, _impl->m_config.customLayers, true);
74 }
75
76 clDNNEngine::~clDNNEngine() {
77     if (_impl) {
78         delete _impl;
79         _impl = nullptr;
80     }
81 }
82
83 ExecutableNetworkInternal::Ptr clDNNEngine::LoadExeNetworkImpl(InferenceEngine::ICNNNetwork &network,
84                                                                const std::map<std::string, std::string> &config) {
85     auto specifiedDevice = network.getTargetDevice();
86     auto supportedDevice = InferenceEngine::TargetDevice::eGPU;
87     if (specifiedDevice != InferenceEngine::TargetDevice::eDefault && specifiedDevice != supportedDevice) {
88         THROW_IE_EXCEPTION << "The plugin doesn't support target device: " << getDeviceName(specifiedDevice) << ".\n" <<
89                            "Supported target device: " << getDeviceName(supportedDevice);
90     }
91
92     CLDNNGraph::Config conf = this->_impl->m_config;
93     conf.LoadFromMap(config);
94
95     // verification of supported input
96     InferenceEngine::InputsDataMap _networkInputs;
97     network.getInputsInfo(_networkInputs);
98     for (auto ii : _networkInputs) {
99         auto input_precision = ii.second->getInputPrecision();
100         if (input_precision != InferenceEngine::Precision::FP16 && input_precision != InferenceEngine::Precision::I16
101             && input_precision != InferenceEngine::Precision::FP32 && input_precision != InferenceEngine::Precision::U8) {
102             THROW_IE_EXCEPTION << NOT_IMPLEMENTED_str
103                                << "Input image format " << input_precision << " is not supported yet...";
104         }
105     }
106     // todo: handle input precision differently - per input and not one per network...
107
108     int max_batch = -1;
109     if (conf.enableDynamicBatch) {
110         max_batch = network.getBatchSize();
111     }
112
113     return std::make_shared<CLDNNGraph>(network, conf, max_batch);
114 }
115
116 INFERENCE_PLUGIN_API(StatusCode) CreatePluginEngine(IInferencePlugin *&plugin, ResponseDesc *resp) noexcept {
117     try {
118         plugin = make_ie_compatible_plugin(
119                 {1, 6,
120                  CI_BUILD_NUMBER,
121                  "clDNNPlugin"}, std::make_shared<clDNNEngine>());
122         return OK;
123     }
124     catch (std::exception &ex) {
125         return DescriptionBuffer(GENERAL_ERROR, resp) << ex.what();
126     }
127 }
128
129 void clDNNEngine::SetConfig(const std::map<std::string, std::string> &config) {
130     _impl->m_config.LoadFromMap(config);
131 }
132
133 void clDNNEngine::QueryNetwork(const ICNNNetwork& network, QueryNetworkResult& res) const {
134     QueryNetwork(network, {}, res);
135 }
136
137 void clDNNEngine::QueryNetwork(const ICNNNetwork& network, const std::map<std::string, std::string>& config, QueryNetworkResult& res) const {
138     std::vector <CNNLayer::Ptr> concats;
139     std::vector <CNNLayer::Ptr> nextLayerDependent;
140
141     std::vector<CNNLayerPtr> sortedLayers = CNNNetSortTopologically(network);
142     for (auto layer : sortedLayers) {
143         if (CaselessEq<std::string>()(layer->type, "DetectionOutput")) {
144         } else if (CaselessEq<std::string>()(layer->type, "PriorBox")) {
145         } else if (CaselessEq<std::string>()(layer->type, "Proposal")) {
146         } else if (CaselessEq<std::string>()(layer->type, "SimplerNMS")) {
147         } else if (CaselessEq<std::string>()(layer->type, "Concat")) {
148             concats.push_back(layer);
149         } else if (CaselessEq<std::string>()(layer->type, "reshape")) {
150             nextLayerDependent.push_back(layer);
151         } else if (CaselessEq<std::string>()(layer->type, "permute")) {
152             nextLayerDependent.push_back(layer);
153         } else if (CaselessEq<std::string>()(layer->type, "Const")) {
154             nextLayerDependent.push_back(layer);
155         } else if (CLDNNGraph::IsLayerSupported(layer->type)) {
156             res.supportedLayers.insert(layer->name);
157         }
158     }
159
160     // evaluation of concats - if all parent layers are supported, only in this case we
161     // will mark concat as a supported for GPU
162     for (const auto &concat : concats) {
163         // take all parrents.
164         bool supported = true;
165         for (DataWeakPtr insData : concat->insData) {
166             CNNLayerPtr prev = insData.lock()->getCreatorLayer().lock();
167             // verify if previous layer is not supported or if it in the list of not defined layers yet
168             // not defined layers are treated as layers which will be assigned to GPU if next layer is assigned to GPU
169             if (res.supportedLayers.find(prev->name) == res.supportedLayers.end()
170                 && std::find(nextLayerDependent.begin(), nextLayerDependent.end(), prev) == nextLayerDependent.end()) {
171                 supported = false;
172             }
173         }
174         if (supported)
175             res.supportedLayers.insert(concat->name);
176     }
177
178     // evaluation of constant blobs - if all consumers are on GPU,
179     // then leave it on GPU, else - move to other device
180     for (auto cnl = nextLayerDependent.rbegin();
181         cnl != nextLayerDependent.rend();
182         cnl++) {
183         bool supported = true;
184         for (DataPtr out : (*cnl)->outData) {
185             for (auto ol : out->inputTo) {
186                 if (res.supportedLayers.find(ol.second->name) == res.supportedLayers.end()) {
187                     supported = false;
188                 }
189             }
190         }
191         std::cout << (*cnl)->name << " is " << (supported ? "GPU" : "CPU") << std::endl;
192
193         if (supported)
194             res.supportedLayers.insert((*cnl)->name);
195     }
196 }
197
198
199 };  // namespace CLDNNPlugin