Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / inference_engine / builders / ie_convolution_layer.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include <builders/ie_convolution_layer.hpp>
6 #include <ie_cnn_layer_builder.h>
7
8 #include <vector>
9 #include <string>
10 #include <limits>
11
12 using namespace InferenceEngine;
13
14 Builder::ConvolutionLayer::ConvolutionLayer(const std::string& name): LayerDecorator("Convolution", name) {
15     getLayer()->getInputPorts().resize(3);
16     getLayer()->getInputPorts()[1].setParameter("type", "weights");
17     getLayer()->getInputPorts()[2].setParameter("type", "biases");
18     getLayer()->getOutputPorts().resize(1);
19     setGroup(1);
20     setKernel({});
21     setOutDepth(0);
22     setStrides({});
23     setDilation({});
24     setPaddingsEnd({});
25     setPaddingsBegin({});
26 }
27
28 Builder::ConvolutionLayer::ConvolutionLayer(const Layer::Ptr& layer): LayerDecorator(layer) {
29     checkType("Convolution");
30 }
31
32 Builder::ConvolutionLayer::ConvolutionLayer(const Layer::CPtr& layer): LayerDecorator(layer) {
33     checkType("Convolution");
34 }
35
36 Builder::ConvolutionLayer &Builder::ConvolutionLayer::setName(const std::string &name) {
37     getLayer()->setName(name);
38     return *this;
39 }
40
41 const Port& Builder::ConvolutionLayer::getInputPort() const {
42     return getLayer()->getInputPorts()[0];
43 }
44
45 Builder::ConvolutionLayer& Builder::ConvolutionLayer::setInputPort(const Port& port) {
46     getLayer()->getInputPorts()[0] = port;
47     return *this;
48 }
49
50 const Port& Builder::ConvolutionLayer::getOutputPort() const {
51     return getLayer()->getOutputPorts()[0];
52 }
53
54 Builder::ConvolutionLayer& Builder::ConvolutionLayer::setOutputPort(const Port& port) {
55     getLayer()->getOutputPorts()[0] = port;
56     return *this;
57 }
58
59 const std::vector<size_t> Builder::ConvolutionLayer::getKernel() const {
60     return getLayer()->getParameters().at("kernel");
61 }
62 Builder::ConvolutionLayer& Builder::ConvolutionLayer::setKernel(const std::vector<size_t>& kernel) {
63     getLayer()->getParameters()["kernel"] = kernel;
64     return *this;
65 }
66
67 const std::vector<size_t> Builder::ConvolutionLayer::getStrides() const {
68     return getLayer()->getParameters().at("strides");
69 }
70 Builder::ConvolutionLayer& Builder::ConvolutionLayer::setStrides(const std::vector<size_t>& strides) {
71     getLayer()->getParameters()["strides"] = strides;
72     return *this;
73 }
74
75 const std::vector<size_t> Builder::ConvolutionLayer::getDilation() const {
76     return getLayer()->getParameters().at("dilations");
77 }
78 Builder::ConvolutionLayer& Builder::ConvolutionLayer::setDilation(const std::vector<size_t>& dilation) {
79     getLayer()->getParameters()["dilations"] = dilation;
80     return *this;
81 }
82
83 const std::vector<size_t> Builder::ConvolutionLayer::getPaddingsBegin() const {
84     return getLayer()->getParameters().at("pads_begin");
85 }
86 Builder::ConvolutionLayer& Builder::ConvolutionLayer::setPaddingsBegin(const std::vector<size_t>& paddings) {
87     getLayer()->getParameters()["pads_begin"] = paddings;
88     return *this;
89 }
90
91 const std::vector<size_t> Builder::ConvolutionLayer::getPaddingsEnd() const {
92     return getLayer()->getParameters().at("pads_end");
93 }
94 Builder::ConvolutionLayer& Builder::ConvolutionLayer::setPaddingsEnd(const std::vector<size_t>& paddings) {
95     getLayer()->getParameters()["pads_end"] = paddings;
96     return *this;
97 }
98
99 size_t Builder::ConvolutionLayer::getGroup() const {
100     return getLayer()->getParameters().at("group");
101 }
102 Builder::ConvolutionLayer& Builder::ConvolutionLayer::setGroup(size_t group) {
103     getLayer()->getParameters()["group"] = group;
104     return *this;
105 }
106
107 size_t Builder::ConvolutionLayer::getOutDepth() const {
108     return getLayer()->getParameters().at("output");
109 }
110 Builder::ConvolutionLayer& Builder::ConvolutionLayer::setOutDepth(size_t outDepth) {
111     getLayer()->getParameters()["output"] = outDepth;
112     return *this;
113 }
114
115 REG_VALIDATOR_FOR(Convolution, [] (const InferenceEngine::Builder::Layer::CPtr& layer, bool partial) {
116     // WA for old IRs
117     if (layer->getParameters().find("kernel") == layer->getParameters().end() &&
118         layer->getParameters().find("kernel-x") != layer->getParameters().end() &&
119         layer->getParameters().find("kernel-y") != layer->getParameters().end())
120         return;
121
122     Builder::ConvolutionLayer convBuilder(layer);
123     std::vector<size_t> l_kernel = convBuilder.getKernel();
124     std::vector<size_t> l_dilation = convBuilder.getDilation();
125     std::vector<size_t> l_paddingBegin = convBuilder.getPaddingsBegin();
126     std::vector<size_t> l_paddingEnd = convBuilder.getPaddingsEnd();
127     std::vector<size_t> l_strides = convBuilder.getStrides();
128
129     if (l_paddingBegin.empty() && !l_kernel.empty())
130         l_paddingBegin.resize(l_kernel.size(), 0);
131     if (l_paddingEnd.empty() && !l_kernel.empty())
132         l_paddingEnd.resize(l_kernel.size(), 0);
133     if (l_dilation.empty() && !l_kernel.empty())
134         l_dilation.resize(l_kernel.size(), 1);
135     if (l_strides.empty() && !l_kernel.empty())
136         l_strides.resize(l_kernel.size(), 1);
137
138     if (l_kernel.empty()) {
139         THROW_IE_EXCEPTION << "Kernel is empty!";
140     }
141
142     if (l_paddingBegin.size() != l_paddingEnd.size()) {
143         THROW_IE_EXCEPTION << "Padding_begin dimension is not equal to padding_end dimension";
144     }
145
146     if (!l_paddingBegin.empty() && l_kernel.size() != l_paddingBegin.size()) {
147         THROW_IE_EXCEPTION << "Padding dimension is not equal to kernel dimension";
148     }
149
150     if (l_kernel.size() != l_strides.size()) {
151         THROW_IE_EXCEPTION << "Stride dimension is not equal to kernel dimension";
152     }
153
154     if (!l_dilation.empty() && l_kernel.size() != l_dilation.size()) {
155         THROW_IE_EXCEPTION << "Dilation dimension is not equal to kernel dimension";
156     }
157
158     if (convBuilder.getOutDepth() == 0) {
159         THROW_IE_EXCEPTION << "OutDepth parameter should be more than 0";
160     }
161
162     for (size_t kernel_dim : l_kernel) {
163         if (kernel_dim == 0) {
164             THROW_IE_EXCEPTION << "Kernel dimensions should be more than 0";
165         }
166     }
167
168     for (size_t i_stride : l_strides) {
169         if (i_stride == 0) {
170             THROW_IE_EXCEPTION << "Strides should be more than 0";
171         }
172     }
173
174     for (size_t dil : l_dilation) {
175         if (dil == 0)
176             THROW_IE_EXCEPTION << "Dilation should be more than 0";
177     }
178
179     if (!convBuilder.getGroup())
180         THROW_IE_EXCEPTION << "Group should be more than 0";
181
182     if (convBuilder.getInputPort().shape().empty())
183         return;
184
185     const size_t IC = convBuilder.getInputPort().shape()[1];
186     if (IC % convBuilder.getGroup())
187         THROW_IE_EXCEPTION << "Number of input channels (" << IC <<
188                            ") is not divided by group number (" << convBuilder.getGroup() << ")";
189
190     size_t weight_size = convBuilder.getOutDepth() * IC / convBuilder.getGroup();
191     for (size_t kernel_dim : l_kernel) {
192         if (static_cast<double>(weight_size) * kernel_dim > std::numeric_limits<size_t>::max()) {
193             THROW_IE_EXCEPTION << "Weight size exceeds the size_t max";
194         }
195         weight_size *= kernel_dim;
196     }
197
198     if (partial)
199         return;
200
201     const auto weights = layer->getInputPorts()[1].getData()->getData();
202     if (weights->size() != weight_size) {
203         THROW_IE_EXCEPTION << "Weight size is not correct!";
204     }
205
206     const auto biases = layer->getInputPorts()[2].getData()->getData();
207     if (biases && biases->cbuffer() && biases->size() != convBuilder.getOutDepth())
208         THROW_IE_EXCEPTION << "Biases size is incorrect!";
209 });
210
211 REG_CONVERTER_FOR(Convolution, [](const CNNLayerPtr& cnnLayer, Builder::Layer& layer) {
212     // WA for old IRs
213     if (cnnLayer->params.find("kernel") == cnnLayer->params.end() &&
214         cnnLayer->params.find("kernel-x") != cnnLayer->params.end() &&
215         cnnLayer->params.find("kernel-y") != cnnLayer->params.end())
216         return;
217
218     std::vector<unsigned int> tmp = cnnLayer->GetParamAsUInts("kernel");
219     std::vector<size_t> cur(tmp.size());
220     for (size_t i = 0; i < tmp.size(); ++i) {
221         cur[i] = static_cast<size_t>(tmp[i]);
222     }
223     layer.getParameters()["kernel"] = cur;
224
225     tmp = cnnLayer->GetParamAsUInts("strides");
226     cur.resize(tmp.size());
227     for (size_t i = 0; i < tmp.size(); ++i) {
228         cur[i] = static_cast<size_t>(tmp[i]);
229     }
230     layer.getParameters()["strides"] = cur;
231
232     tmp = cnnLayer->GetParamAsUInts("dilations");
233     cur.resize(tmp.size());
234     for (size_t i = 0; i < tmp.size(); ++i) {
235         cur[i] = static_cast<size_t>(tmp[i]);
236     }
237     layer.getParameters()["dilations"] = cur;
238
239     tmp = cnnLayer->GetParamAsUInts("pads_begin");
240     cur.resize(tmp.size());
241     for (size_t i = 0; i < tmp.size(); ++i) {
242         cur[i] = static_cast<size_t>(tmp[i]);
243     }
244     layer.getParameters()["pads_begin"] = cur;
245
246     tmp = cnnLayer->GetParamAsUInts("pads_end");
247     cur.resize(tmp.size());
248     for (size_t i = 0; i < tmp.size(); ++i) {
249         cur[i] = static_cast<size_t>(tmp[i]);
250     }
251     layer.getParameters()["pads_end"] = cur;
252
253     layer.getParameters()["group"] = static_cast<size_t>(cnnLayer->GetParamAsUInt("group"));
254     layer.getParameters()["output"] = static_cast<size_t>(cnnLayer->GetParamAsUInt("output"));
255 });