1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
13 #include <ie_common.h>
14 #include <ie_profiling.hpp>
15 #include "details/caseless.hpp"
16 #include "mkldnn_dims.h"
17 #include "mkldnn_memory.h"
18 #include "mkldnn_edge.h"
19 #include "mkldnn_descriptor.h"
20 #include "mkldnn/iml_type_mapper.h"
21 #include "mkldnn_extension_mngr.h"
22 #include "mkldnn_primitive.h"
24 namespace MKLDNNPlugin {
26 using MKLDNNNodePtr = std::shared_ptr<MKLDNNNode>;
27 using MKLDNNNodeWeakPtr = std::weak_ptr<MKLDNNNode>;
38 Convolution_Activation,
39 Convolution_Depthwise,
40 Convolution_Sum_Activation,
46 FullyConnected_Activation,
70 static Type TypeFromName(const std::string type) {
71 static InferenceEngine::details::caseless_unordered_map<std::string, Type> type_to_name_tbl = {
72 { "Unknown", Unknown },
76 { "Reorder", Reorder },
77 { "Convolution", Convolution },
78 { "ReLU", Activation },
79 { "ELU", Activation },
80 { "Sigmoid", Activation },
81 { "Logistic", Activation },
82 { "TanH", Activation },
83 { "ReLU6", Activation },
84 { "Exp", Activation },
85 { "Not", Activation },
86 { "Activation", Activation },
87 { "ScaleShift", Depthwise },
88 { "PReLU", Depthwise },
89 { "Clamp", Activation },
92 { "Pooling", Pooling },
93 { "FullyConnected", FullyConnected },
94 { "InnerProduct", FullyConnected },
96 { "Softmax", SoftMax },
97 { "SoftMax", SoftMax },
100 { "Concat", Concatenation },
102 { "Deconvolution", Deconvolution },
103 { "Eltwise", Eltwise },
105 { "Reshape", Reshape },
107 { "SimplerNMS", SimplerNMS },
108 { "ROIPooling", ROIPooling },
109 { "BatchNormalization", BatchNormalization },
110 { "Flatten", Flatten },
111 { "Permute", Permute },
113 { "LSTMCell", RNNCell },
114 { "GRUCell", RNNCell },
115 { "RNNCell", RNNCell },
116 { "LSTMSequence", RNNSeq },
117 { "GRUSequence", RNNSeq },
118 { "RNNSequence", RNNSeq },
119 { "Quantize", Quantize },
120 { "BinaryConvolution", BinaryConvolution },
121 { "MemoryInput", MemoryInput}, // for construction from name ctor, arbitrary name is used
122 { "Memory", MemoryOutput }, // for construction from layer ctor
125 if (type_to_name_tbl.find(type) != type_to_name_tbl.end()) {
126 return type_to_name_tbl[type];
132 class PrimitiveDescInfo {
134 PrimitiveDescInfo(const InferenceEngine::LayerConfig conf, impl_desc_type type): config(conf) {
135 implementationType = type;
138 PrimitiveDescInfo(const PrimitiveDescInfo &descInfo) = default;
139 PrimitiveDescInfo(PrimitiveDescInfo &&descInfo) = default;
141 PrimitiveDescInfo &operator=(const PrimitiveDescInfo &descInfo) = default;
143 const InferenceEngine::LayerConfig getConfig() const {
146 InferenceEngine::LayerConfig& getConfig() {
150 impl_desc_type getImplementationType() const {
151 return implementationType;
155 InferenceEngine::LayerConfig config;
156 impl_desc_type implementationType;
159 class MKLDNNNode : public InferenceEngine::details::no_copy {
161 static MKLDNNNode* CreateNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng,
162 const MKLDNNExtensionManager::Ptr& extMgr);
164 ~MKLDNNNode() override = default;
166 void addEdge(const MKLDNNEdgeWeakPtr& edge);
167 void removeEdge(const MKLDNNEdgeWeakPtr& edge);
169 virtual void cleanup();
172 const std::vector<MKLDNNEdgeWeakPtr> &getParentEdges() const noexcept {
176 const std::vector<MKLDNNEdgeWeakPtr> &getChildEdges() const noexcept {
180 const MKLDNNEdgePtr getParentEdgeAt(size_t idx) const;
181 virtual const MKLDNNEdgePtr getChildEdgeAt(size_t idx) const;
183 const std::vector<MKLDNNEdgePtr> getParentEdgesAtPort(size_t idx) const;
184 const std::vector<MKLDNNEdgePtr> getChildEdgesAtPort(size_t idx) const;
187 return (isEdgesEmpty(childEdges) && isEdgesEmpty(parentEdges));
190 const mkldnn::engine& getEngine() const {
196 bool isInplace() const;
198 void fuseWith(const MKLDNNNodePtr &fuse) {
199 fusedWith.push_back(fuse);
202 void mergeWith(const MKLDNNNodePtr &merge) {
203 mergedWith.push_back(merge);
206 void addOriginalLayer(const InferenceEngine::CNNLayerPtr &layer);
208 const std::vector <MKLDNNNodePtr> &getMergeWith() {
212 const std::vector <MKLDNNNodePtr> &getFusedWith() {
216 const std::string getName() const {
220 const std::string getOriginalLayers() const {
221 return originalLayers;
224 Type getType() const {
228 const InferenceEngine::CNNLayerPtr &getCnnLayer() const {
232 const std::vector<PrimitiveDescInfo>& getSupportedPrimitiveDescriptors() const {
233 return supportedPrimitiveDescriptors;
236 inline const PrimitiveDescInfo* getSelectedPrimitiveDescriptor() const {
237 if (selectedPrimitiveDescriptorIndex < 0 ||
238 selectedPrimitiveDescriptorIndex >= supportedPrimitiveDescriptors.size())
240 return &supportedPrimitiveDescriptors[selectedPrimitiveDescriptorIndex];
243 inline PrimitiveDescInfo* getSelectedPrimitiveDescriptor() {
244 if (selectedPrimitiveDescriptorIndex < 0 ||
245 selectedPrimitiveDescriptorIndex >= supportedPrimitiveDescriptors.size())
247 return &supportedPrimitiveDescriptors[selectedPrimitiveDescriptorIndex];
250 void selectPrimitiveDescriptorByIndex(int index) {
251 if (index < 0 || index >= supportedPrimitiveDescriptors.size())
252 selectedPrimitiveDescriptorIndex = -1;
254 selectedPrimitiveDescriptorIndex = index;
257 std::string getPrimitiveDescriptorType();
259 PerfCount &PerfCounter() { return perfCounter; }
261 virtual void setDynamicBatchLim(int lim);
263 void resolveNotAllocatedEdges();
264 virtual void execute(mkldnn::stream strm);
265 virtual void initSupportedPrimitiveDescriptors();
266 virtual void createPrimitive() = 0;
268 virtual void selectOptimalPrimitiveDescriptor();
269 virtual void initOptimalPrimitiveDescriptor();
271 virtual void getSupportedDescriptors() = 0;
272 virtual void createDescriptor(const std::vector<InferenceEngine::TensorDesc>& inputDesc,
273 const std::vector<InferenceEngine::TensorDesc>& outputDesc) {}
274 virtual void initDescriptor(const InferenceEngine::LayerConfig& config);
275 virtual bool created() const = 0;
276 virtual bool created(const MKLDNNExtensionManager::Ptr& extMgr) {
280 template <class PD, class D, typename FPD = bool>
281 PD createPrimitiveDescriptor(const mkldnn::primitive_attr &attr = mkldnn::primitive_attr()) {
282 auto descsEqual = [](const std::vector<InferenceEngine::TensorDesc>& srcDescs,
283 const std::vector<InferenceEngine::DataConfig>& selectedDescs) {
284 if (srcDescs.empty() && selectedDescs.empty())
286 if (srcDescs.empty() || selectedDescs.empty())
288 for (size_t i = 0; i < srcDescs.size() && i < selectedDescs.size(); i++) {
289 if (srcDescs[i] != selectedDescs[i].desc && srcDescs[i].getLayout() != InferenceEngine::Layout::ANY)
295 const PrimitiveDescInfo *selected_pd = getSelectedPrimitiveDescriptor();
296 if (selected_pd == nullptr)
297 THROW_IE_EXCEPTION << "Preferable primitive descriptor does not set for node " << getName() << ".";
299 for (const auto& desc : descs) {
301 mkldnn::primitive_desc_iterator itpd = desc.createPrimitiveDescriptorIterator(engine, attr);
303 std::vector<InferenceEngine::TensorDesc> srcDescs;
304 for (size_t i = 0; i < desc.inputNumbers(); i++)
305 srcDescs.push_back(getSrcMemDesc(itpd, i));
307 std::vector<InferenceEngine::TensorDesc> dstDescs;
308 for (size_t i = 0; i < desc.outputNumbers(); i++)
309 dstDescs.push_back(getDstMemDesc(itpd, i));
311 impl_desc_type impl_type = parse_impl_name(itpd.get_impl_info_str());
313 if (impl_type == selected_pd->getImplementationType() &&
314 descsEqual(srcDescs, selected_pd->getConfig().inConfs) &&
315 descsEqual(dstDescs, selected_pd->getConfig().outConfs)) {
316 prepareMemory(selected_pd, itpd);
317 PD prim_desc = createPd<PD, D, FPD>(desc);
318 itpd.getPrimitiveDescriptor(prim_desc);
321 } while (itpd.next());
322 } catch (std::exception& e) {
323 // it throw exception in case of no implementation found
328 THROW_IE_EXCEPTION << "Primitive descriptor was not found for node " << getName() << ".";
331 static void invertVectorCopyUtoI(const InferenceEngine::PropertyVector<unsigned int>& src, std::vector<ptrdiff_t>& dst) {
333 for (int i = 1; i <= src.size(); i++) {
334 dst.push_back(static_cast<ptrdiff_t>(src[src.size() - i]));
338 std::vector<MKLDNNDims> inDims;
342 // TODO: It is necessary only in order to avoid modifications of cnnLayers and original topology
343 std::vector<MKLDNNDims> outDims;
344 void setType(Type type) {
348 virtual int getMaxBatch();
350 virtual InferenceEngine::TensorDesc getConfiguredInputDesc(const InferenceEngine::LayerConfig& config, size_t idx) const;
351 virtual InferenceEngine::TensorDesc getConfiguredOutputDesc(const InferenceEngine::LayerConfig& config, size_t idx) const;
352 virtual MKLDNNMemoryDesc getSrcMemDesc(mkldnn::primitive_desc_iterator &primitive_desc_it, size_t idx);
353 virtual MKLDNNMemoryDesc getDstMemDesc(mkldnn::primitive_desc_iterator &primitive_desc_it, size_t idx);
355 virtual std::shared_ptr<mkldnn::primitive_attr> initPrimitiveAttr() const { return nullptr; }
357 typedef std::function<MKLDNNMemoryDesc (mkldnn::primitive_desc_iterator &primitive_desc_it, size_t idx)>
358 GetPrimitiveMemoryFormatFunc;
359 std::vector<GetPrimitiveMemoryFormatFunc> internalBlobDesc;
361 std::vector <MKLDNNNodePtr> fusedWith;
362 std::vector <MKLDNNNodePtr> mergedWith;
363 std::vector <impl_desc_type> implPriorities;
365 std::string originalLayers; // contains names of the original layers separated by comma
367 MKLDNNNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng);
369 int selectedPrimitiveDescriptorIndex = -1;
370 bool permanent = false;
371 bool temporary = false;
373 enum class ConstantType {
378 ConstantType constant = ConstantType::Unknown;
379 std::vector<InferenceEngine::Blob::Ptr> internalBlobs;
380 std::vector<MKLDNNMemoryPtr> internalBlobMemory;
381 std::vector<PrimitiveDescInfo> supportedPrimitiveDescriptors;
382 MKLDNNPrimitive prim;
383 std::vector<MKLDNNDescriptor> descs;
385 InferenceEngine::Blob::Ptr ext_scales;
387 friend class MKLDNNEdge;
388 friend class MKLDNNGraph;
389 friend class MKLDNNGraphOptimizer;
391 bool isUninitTensorDesc(const InferenceEngine::TensorDesc& desc) const;
392 bool isInitConfig(const InferenceEngine::LayerConfig& config) const;
393 virtual void selectPreferPrimitiveDescriptor(const std::vector<impl_desc_type>& priority);
394 virtual bool canBeInPlace() const;
396 virtual const std::vector<impl_desc_type>& getPrimitivesPriority();
398 std::vector<mkldnn::memory::format> getAvailableFormatsForDims(const MKLDNNDims& dims) const;
399 int batchToProcess();
401 InferenceEngine::Blob::Ptr createInternalBlob(InferenceEngine::SizeVector dims, bool weights);
403 template<typename To>
407 Registry::RegisterNode(
408 Registry::CreatorByLayerFunction(
409 [](const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng)
410 -> MKLDNNNode* { return new To(layer, eng); } ) );
415 std::vector<MKLDNNEdgeWeakPtr> parentEdges;
416 std::vector<MKLDNNEdgeWeakPtr> childEdges;
418 InferenceEngine::CNNLayerPtr cnnLayer;
419 mkldnn::engine engine;
422 const std::string typeStr;
426 std::string typeToStr(Type type);
428 PerfCount perfCounter;
429 InferenceEngine::ProfilingTask profilingTask;
431 bool isEdgesEmpty(const std::vector<MKLDNNEdgeWeakPtr>& edges) const;
435 typedef std::function<MKLDNNNode *(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng)> CreatorByLayerFunction;
437 static MKLDNNNode *CreateNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng, const MKLDNNExtensionManager::Ptr& extMgr);
439 static void RegisterNode(CreatorByLayerFunction f);
441 static std::vector<CreatorByLayerFunction> _dataByLayer;
444 template <class PD, class D, typename FPD>
445 typename std::enable_if<!std::is_same<FPD, bool>::value, PD>::type
446 createPd(MKLDNNDescriptor desc) {
447 std::shared_ptr<D> selected_desc_ptr = desc;
448 std::shared_ptr<FPD> backward_prim_desc_ptr = desc;
449 return PD(*selected_desc_ptr, engine, *backward_prim_desc_ptr);
452 template <class PD, class D, typename FPD>
453 typename std::enable_if<std::is_same<FPD, bool>::value, PD>::type
454 createPd(MKLDNNDescriptor desc) {
455 std::shared_ptr<D> selected_desc_ptr = desc;
456 return PD(*selected_desc_ptr, engine);
459 void prepareMemory(const PrimitiveDescInfo *selected_pd, mkldnn::primitive_desc_iterator& itpd);
460 enum LOOK { LOOK_UP = 1, LOOK_DOWN = 2 };
461 ConstantType checkConstant(LOOK look, std::vector<MKLDNNNodePtr>& checkNodes);
464 template <typename T, typename U>
465 inline T div_up(const T a, const U b) {
467 return (a + b - 1) / b;
470 template <typename T, typename U>
471 inline T rnd_up(const T a, const U b) {
472 return div_up(a, b) * b;
475 } // namespace MKLDNNPlugin