Publishing R3
[platform/upstream/dldt.git] / inference-engine / src / mkldnn_plugin / nodes / mkldnn_tile_node.cpp
1 // Copyright (C) 2018 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5
6 #include "mkldnn_tile_node.h"
7 #include <ie_layers.h>
8 #include <string>
9 #include <mkldnn_types.h>
10 #include <mkldnn_extension_utils.h>
11
12 using namespace mkldnn;
13 using namespace MKLDNNPlugin;
14 using namespace InferenceEngine;
15
16 MKLDNNTileNode::MKLDNNTileNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng) : MKLDNNNode(layer, eng) {}
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.";
26     if (!getChildEdges().size())
27         THROW_IE_EXCEPTION << "Incorrect number of output edges.";
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() == 2) {
49         fmt = memory::format::nc;
50     } else if (inDims.ndims() == 4) {
51         fmt = memory::format::nchw;
52     }
53     if (fmt == memory::format::any) {
54         THROW_IE_EXCEPTION << "Tile " << getName() << " supports only 2d and 4d dimensions!";
55     }
56
57     InferenceEngine::LayerConfig config;
58     config.dynBatchSupport = true;
59     config.inConfs.resize(1);
60     config.outConfs.resize(1);
61     config.inConfs[0].inPlace = -1;
62     config.inConfs[0].constant = false;
63     config.inConfs[0].desc = MKLDNNMemoryDesc(getParentEdgeAt(0)->getDims(), inputDataType, fmt);
64     config.outConfs[0].inPlace = -1;
65     config.outConfs[0].constant = false;
66     config.outConfs[0].desc = MKLDNNMemoryDesc(getChildEdgeAt(0)->getDims(), outputDataType, fmt);
67     supportedPrimitiveDescriptors.push_back({config, impl_desc_type::unknown});
68 }
69
70 void MKLDNNTileNode::createPrimitive() {
71     auto& dstMemPtr = getChildEdgeAt(0)->getMemoryPtr();
72     auto& srcMemPtr = getParentEdgeAt(0)->getMemoryPtr();
73     if (!dstMemPtr || !dstMemPtr->GetPrimitivePtr())
74         THROW_IE_EXCEPTION << "Destination memory didn't allocate.";
75     if (!srcMemPtr || !srcMemPtr->GetPrimitivePtr())
76         THROW_IE_EXCEPTION << "Input memory didn't allocate.";
77     if (getSelectedPrimitiveDescriptor() == nullptr)
78         THROW_IE_EXCEPTION << "Preferable primitive descriptor does not set.";
79     if (getParentEdges().size() != 1)
80         THROW_IE_EXCEPTION << "Incorrect number of input edges.";
81 }
82
83 void MKLDNNTileNode::execute(mkldnn::stream strm) {
84     auto& srcMemory = getParentEdgeAt(0)->getMemory();
85
86     const float *src_ptr = reinterpret_cast<const float*>(srcMemory.GetData()) +
87             srcMemory.GetDescriptor().data.layout_desc.blocking.offset_padding;
88     float *dst_ptr = reinterpret_cast<float*>(getChildEdgeAt(0)->getMemory().GetData()) +
89             getChildEdgeAt(0)->getMemory().GetDescriptor().data.layout_desc.blocking.offset_padding;
90
91     int m_inner_dim = 1;
92     int m_outer_dim = 1;
93     memory::dims inDims = srcMemory.GetDims();
94     for (int i=0; i < axis; i++ ) m_outer_dim *= inDims[i];
95     for (int i=axis; i < inDims.size(); i++ ) m_inner_dim *= inDims[i];
96     if (axis > 0) {
97         m_outer_dim /= inDims[0];
98         m_outer_dim *= batchToProcess();
99     } else {
100         m_inner_dim /= inDims[0];
101         m_inner_dim *= batchToProcess();
102     }
103
104     if (m_inner_dim == 1 && inDims.size() == 4 && m_outer_dim%8 == 0 && srcMemory.GetFormat() == memory::nChw8c) {
105         /*
106          * We may enable tile processing directly to appropriate output format (nChw8c)
107          */
108         m_inner_dim *= 8;
109         m_outer_dim /= 8;
110     } else if (m_inner_dim == 1 && inDims.size() == 4 && m_outer_dim%16 == 0
111                && srcMemory.GetFormat() == memory::nChw16c) {
112         /*
113          * We may enable tile processing directly to appropriate output format (nChw16c)
114          */
115         m_inner_dim *= 16;
116         m_outer_dim /= 16;
117     }
118
119     for (int i = 0; i < m_outer_dim; ++i) {
120         for (int t = 0; t < tiles; ++t) {
121             memcpy(dst_ptr, src_ptr, m_inner_dim* sizeof(float));
122             dst_ptr += m_inner_dim;
123         }
124         src_ptr += m_inner_dim;
125     }
126 }
127
128 bool MKLDNNTileNode::created() const {
129     return getType() == Tile;
130 }