updated readme file due to moving CMake scripts to the root folder
[platform/upstream/dldt.git] / inference-engine / src / mkldnn_plugin / nodes / mkldnn_tile_node.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include "mkldnn_tile_node.h"
6 #include <ie_layers.h>
7 #include <string>
8 #include <mkldnn_types.h>
9 #include <mkldnn_extension_utils.h>
10
11 using namespace mkldnn;
12 using namespace MKLDNNPlugin;
13 using namespace InferenceEngine;
14
15 MKLDNNTileNode::MKLDNNTileNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng, int socket) :
16         MKLDNNNode(layer, eng, socket) {}
17
18 void MKLDNNTileNode::getSupportedDescriptors() {
19     auto * tileLayer = dynamic_cast<TileLayer*>(getCnnLayer().get());
20
21     if (tileLayer == nullptr)
22         THROW_IE_EXCEPTION << "Cannot convert tile layer.";
23
24     if (getParentEdges().size() != 1)
25         THROW_IE_EXCEPTION << "Incorrect number of input edges for layer " << getName();
26     if (!getChildEdges().size())
27         THROW_IE_EXCEPTION << "Incorrect number of output edges for layer " << getName();
28
29     axis = tileLayer->axis;
30     tiles = tileLayer->tiles;
31 }
32
33 void MKLDNNTileNode::initSupportedPrimitiveDescriptors() {
34     if (!supportedPrimitiveDescriptors.empty())
35         return;
36
37     InferenceEngine::Precision precision = getCnnLayer()->insData[0].lock()->getPrecision();
38     if (precision != InferenceEngine::Precision::FP32)
39         precision = InferenceEngine::Precision::FP32;
40     auto inputDataType = MKLDNNExtensionUtils::IEPrecisionToDataType(precision);
41     precision = getCnnLayer()->outData[0]->getPrecision();
42     if (precision != InferenceEngine::Precision::FP32)
43         precision = InferenceEngine::Precision::FP32;
44     auto outputDataType = MKLDNNExtensionUtils::IEPrecisionToDataType(precision);
45
46     auto& inDims = getParentEdgeAt(0)->getDims();
47     memory::format fmt = memory::format::any;
48     if (inDims.ndims() == 1) {
49         fmt = memory::format::x;
50     } else if (inDims.ndims() == 2) {
51         fmt = memory::format::nc;
52     } else if (inDims.ndims() == 3) {
53         fmt = memory::format::tnc;
54     } else if (inDims.ndims() == 4) {
55         fmt = memory::format::nchw;
56     } else if (inDims.ndims() == 5) {
57         fmt = memory::format::ncdhw;
58     }
59     if (fmt == memory::format::any) {
60         THROW_IE_EXCEPTION << "Tile " << getName() << " supports only 2D, 4D and 5D dimensions!";
61     }
62
63     InferenceEngine::LayerConfig config;
64     config.dynBatchSupport = true;
65     config.inConfs.resize(1);
66     config.outConfs.resize(1);
67     config.inConfs[0].inPlace = -1;
68     config.inConfs[0].constant = false;
69     config.inConfs[0].desc = MKLDNNMemoryDesc(getParentEdgeAt(0)->getDims(), inputDataType, fmt);
70     config.outConfs[0].inPlace = -1;
71     config.outConfs[0].constant = false;
72     config.outConfs[0].desc = MKLDNNMemoryDesc(getChildEdgeAt(0)->getDims(), outputDataType, fmt);
73     supportedPrimitiveDescriptors.push_back({config, impl_desc_type::unknown, fmt});
74 }
75
76 void MKLDNNTileNode::createPrimitive() {
77     auto& dstMemPtr = getChildEdgeAt(0)->getMemoryPtr();
78     auto& srcMemPtr = getParentEdgeAt(0)->getMemoryPtr();
79     if (!dstMemPtr || !dstMemPtr->GetPrimitivePtr())
80         THROW_IE_EXCEPTION << "Destination memory didn't allocate.";
81     if (!srcMemPtr || !srcMemPtr->GetPrimitivePtr())
82         THROW_IE_EXCEPTION << "Input memory didn't allocate.";
83     if (getSelectedPrimitiveDescriptor() == nullptr)
84         THROW_IE_EXCEPTION << "Preferable primitive descriptor is not set.";
85     if (getParentEdges().size() != 1)
86         THROW_IE_EXCEPTION << "Incorrect number of input edges for layer " << getName();
87 }
88
89 void MKLDNNTileNode::execute(mkldnn::stream strm) {
90     auto& srcMemory = getParentEdgeAt(0)->getMemory();
91
92     const float *src_ptr = reinterpret_cast<const float*>(srcMemory.GetData()) +
93             srcMemory.GetDescriptor().data.layout_desc.blocking.offset_padding;
94     float *dst_ptr = reinterpret_cast<float*>(getChildEdgeAt(0)->getMemory().GetData()) +
95             getChildEdgeAt(0)->getMemory().GetDescriptor().data.layout_desc.blocking.offset_padding;
96
97     int m_inner_dim = 1;
98     int m_outer_dim = 1;
99     memory::dims inDims = srcMemory.GetDims();
100     for (int i=0; i < axis; i++ ) m_outer_dim *= inDims[i];
101     for (int i=axis; i < inDims.size(); i++ ) m_inner_dim *= inDims[i];
102     if (axis > 0) {
103         m_outer_dim /= inDims[0];
104         m_outer_dim *= batchToProcess();
105     } else {
106         m_inner_dim /= inDims[0];
107         m_inner_dim *= batchToProcess();
108     }
109
110     if (m_inner_dim == 1 && m_outer_dim % 8 == 0 && ((inDims.size() == 4 && srcMemory.GetFormat() == memory::nChw8c) ||
111             (inDims.size() == 5 && srcMemory.GetFormat() == memory::nCdhw8c))) {
112         /*
113          * We may enable tile processing directly to appropriate output format (nChw8c)
114          */
115         m_inner_dim *= 8;
116         m_outer_dim /= 8;
117     } else if (m_inner_dim == 1 && m_outer_dim % 16 == 0 &&
118             ((inDims.size() == 4 && srcMemory.GetFormat() == memory::nChw16c) ||
119             (inDims.size() == 5 && srcMemory.GetFormat() == memory::nCdhw16c))) {
120         /*
121          * We may enable tile processing directly to appropriate output format (nChw16c)
122          */
123         m_inner_dim *= 16;
124         m_outer_dim /= 16;
125     }
126
127     for (int i = 0; i < m_outer_dim; ++i) {
128         for (int t = 0; t < tiles; ++t) {
129             memcpy(dst_ptr, src_ptr, m_inner_dim* sizeof(float));
130             dst_ptr += m_inner_dim;
131         }
132         src_ptr += m_inner_dim;
133     }
134 }
135
136 bool MKLDNNTileNode::created() const {
137     return getType() == Tile;
138 }
139 REG_MKLDNN_PRIM_FOR(MKLDNNTileNode, Tile);