1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include "mkldnn_tile_node.h"
8 #include <mkldnn_types.h>
9 #include <mkldnn_extension_utils.h>
11 using namespace mkldnn;
12 using namespace MKLDNNPlugin;
13 using namespace InferenceEngine;
15 MKLDNNTileNode::MKLDNNTileNode(const InferenceEngine::CNNLayerPtr& layer, const mkldnn::engine& eng, int socket) :
16 MKLDNNNode(layer, eng, socket) {}
18 void MKLDNNTileNode::getSupportedDescriptors() {
19 auto * tileLayer = dynamic_cast<TileLayer*>(getCnnLayer().get());
21 if (tileLayer == nullptr)
22 THROW_IE_EXCEPTION << "Cannot convert tile layer.";
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();
29 axis = tileLayer->axis;
30 tiles = tileLayer->tiles;
33 void MKLDNNTileNode::initSupportedPrimitiveDescriptors() {
34 if (!supportedPrimitiveDescriptors.empty())
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);
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;
59 if (fmt == memory::format::any) {
60 THROW_IE_EXCEPTION << "Tile " << getName() << " supports only 2D, 4D and 5D dimensions!";
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});
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();
89 void MKLDNNTileNode::execute(mkldnn::stream strm) {
90 auto& srcMemory = getParentEdgeAt(0)->getMemory();
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;
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];
103 m_outer_dim /= inDims[0];
104 m_outer_dim *= batchToProcess();
106 m_inner_dim /= inDims[0];
107 m_inner_dim *= batchToProcess();
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))) {
113 * We may enable tile processing directly to appropriate output format (nChw8c)
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))) {
121 * We may enable tile processing directly to appropriate output format (nChw16c)
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;
132 src_ptr += m_inner_dim;
136 bool MKLDNNTileNode::created() const {
137 return getType() == Tile;
139 REG_MKLDNN_PRIM_FOR(MKLDNNTileNode, Tile);