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