Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / tests / unit / engines / mkldnn / graph / structure / graph_deconv_concat_tets.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include <gtest/gtest.h>
6 #include <gmock/gmock-spec-builders.h>
7 #include "mkldnn_plugin/mkldnn_graph.h"
8
9 #include "test_graph.hpp"
10
11 #include "single_layer_common.hpp"
12 #include <mkldnn_plugin/mkldnn_extension_utils.h>
13 #include "tests_common.hpp"
14 #include "ir_gen_helper.hpp"
15
16 using namespace ::testing;
17 using namespace std;
18 using namespace mkldnn;
19 using namespace single_layer_tests;
20
21 struct concat_params {
22     size_t axis;
23 };
24
25 struct deconv_concat_params {
26     // Formats: NCHW, NCDHW
27     std::vector<size_t> in;
28
29     conv_common_params deconv;
30     concat_params concat;
31
32     std::vector<MKLDNNPlugin::impl_desc_type> preferTypes;
33 };
34
35 void ref_deconv_common(const InferenceEngine::Blob &src,
36                        InferenceEngine::Blob &dst,
37                        const float *weights_data,
38                        size_t weights_size,
39                        const float *bias_data,
40                        size_t bias_size,
41                        const conv_common_params &prm) {
42     auto dims_size = src.dims().size();
43
44     size_t G  = prm.group;
45     size_t KW = prm.kernel[InferenceEngine::X_AXIS];
46     size_t KH = prm.kernel[InferenceEngine::Y_AXIS];
47     size_t KD = prm.kernel.size() > InferenceEngine::Z_AXIS ? prm.kernel[InferenceEngine::Z_AXIS] : 1u;
48
49     size_t PW = prm.pads_begin[InferenceEngine::X_AXIS];
50     size_t PH = prm.pads_begin[InferenceEngine::Y_AXIS];
51     size_t PD = prm.pads_begin.size() > InferenceEngine::Z_AXIS ? prm.pads_begin[InferenceEngine::Z_AXIS] : 0u;
52
53     size_t SW = prm.stride[InferenceEngine::X_AXIS];
54     size_t SH = prm.stride[InferenceEngine::Y_AXIS];
55     size_t SD = prm.stride.size() > InferenceEngine::Z_AXIS ? prm.stride[InferenceEngine::Z_AXIS] : 1u;
56
57     size_t IW = src.dims()[dims_size - 1];
58     size_t IH = src.dims()[dims_size - 2];
59     size_t ID = dims_size == 5 ? src.dims()[dims_size - 3] : 1u;
60     size_t IC = src.dims()[1];
61     size_t MB = src.dims()[0];
62
63     size_t OC = prm.out_c;
64
65     size_t OW = SW * (IW - 1lu) + KW - 2lu * PW;
66     size_t OH = SH * (IH - 1lu) + KH - 2lu * PH;
67     size_t OD = dims_size == 5 ? (SD * (ID - 1) + KD - 2 * PD) : 1u;
68
69     const float *src_data = src.cbuffer().as<float *>();
70     float *dst_data = dst.buffer().as<float *>();
71
72     size_t CS1 = OH * OW;
73     size_t CS2 = CS1 * OD;
74     size_t CS3 = CS2 * OC;
75
76     size_t CI1 = IH * IW;
77     size_t CI2 = CI1 * ID;
78     size_t CI3 = CI2 * IC;
79     
80     size_t OC_G = OC / G;
81     size_t IC_G = IC / G;
82
83     size_t CK1 = KH * KW;
84     size_t CK2 = CK1 * KD;
85     size_t CK3 = CK2 * OC_G;
86     size_t CK4 = CK3 * IC_G;
87
88     for (size_t g = 0lu; g < G; ++g) {
89         size_t g_OC_G = g * OC_G;
90         size_t g_IC_G = g * IC_G;
91         size_t g_CK4 = g * CK4;
92         for (size_t mb = 0lu; mb < MB; ++mb) {
93             size_t mb_CS3 = mb * CS3;
94             size_t mb_CI3 = mb * CI3;
95             for (size_t oc = 0lu; oc < OC_G; ++oc) {
96                 size_t g_OC_G_oc = g_OC_G + oc;
97                 size_t mb_CS3_g_OC_G_oc_CS2 = mb_CS3 + g_OC_G_oc * CS2;
98                 size_t g_CK4_oc_CK2 = g_CK4 + oc * CK2;
99                 for (size_t od = 0lu; od < OD; ++od) {
100                     size_t mb_CS3_g_OC_G_oc_CS2_od_CS1 = mb_CS3_g_OC_G_oc_CS2 + od * CS1;
101                     size_t od_PD = od + PD;
102                     for (size_t oh = 0lu; oh < OH; ++oh) {
103                         size_t mb_CS3_g_OC_G_oc_CS2_od_CS1_oh_OW = mb_CS3_g_OC_G_oc_CS2_od_CS1 + oh * OW;
104                         size_t oh_PH = oh + PH;
105                         for (size_t ow = 0lu; ow < OW; ++ow) {
106                             size_t didx = mb_CS3_g_OC_G_oc_CS2_od_CS1_oh_OW + ow;
107                             size_t ow_PW = ow + PW;
108
109                             dst_data[didx] = float(0);
110                             if (prm.with_bias) dst_data[didx] += bias_data[g_OC_G_oc];
111
112                             for (size_t ic = 0lu; ic < IC_G; ic++) {
113                                 size_t mb_CI3_g_IC_G_ic_CI2 = mb_CI3 + (g_IC_G + ic) * CI2;
114                                 size_t g_CK4_oc_CK2_ic_CK3 = g_CK4_oc_CK2 + ic * CK3;
115                                 for (int kd = 0lu; kd < KD; kd++) {
116                                     if (od_PD < kd) continue;
117                                     size_t id = od_PD - kd;
118                                     if (id % SD != 0) continue;
119                                     id /= SD;
120                                     if (id >= ID) continue;
121                                     size_t mb_CI3_g_IC_G_ic_CI2_id_CI1 = mb_CI3_g_IC_G_ic_CI2 + id * CI1;
122                                     size_t g_CK4_oc_CK2_ic_CK3_kd_CK1 = g_CK4_oc_CK2_ic_CK3 + kd * CK1;
123                                     for (size_t kh = 0lu; kh < KH; kh++) {
124                                         if (oh_PH < kh) continue;
125                                         size_t ih = oh_PH - kh;
126                                         if (ih % SH != 0) continue;
127                                         ih /= SH;
128                                         if (ih >= IH) continue;
129                                         size_t mb_CI3_g_IC_G_ic_CI2_id_CI1_ih_IW = mb_CI3_g_IC_G_ic_CI2_id_CI1 + ih * IW;
130                                         size_t g_CK4_oc_CK2_ic_CK3_kd_CK1_kh_KW = g_CK4_oc_CK2_ic_CK3_kd_CK1 + kh * KW;
131                                         for (size_t kw = 0lu; kw < KW; kw++) {
132                                             if (ow_PW < kw) continue;
133                                             size_t iw = ow_PW - kw;
134                                             if (iw % SW != 0) continue;
135                                             iw /= SW;
136                                             if (iw >= IW) continue;
137
138                                             size_t sidx = mb_CI3_g_IC_G_ic_CI2_id_CI1_ih_IW + iw;
139
140                                             size_t widx = g_CK4_oc_CK2_ic_CK3_kd_CK1_kh_KW + kw;
141
142                                             dst_data[didx] += src_data[sidx] * weights_data[widx];
143                                         }
144                                     }
145                                 }
146                             }
147                         }
148                     }
149                 }
150             }
151         }
152     }
153 }
154
155 class MKLDNNDeconvConcatTests: public TestsCommon,
156                                     public WithParamInterface<deconv_concat_params> {
157     std::string layers_t = R"V0G0N(
158         <layer id="2" name="Deconvolution_1" precision="FP32" type="Deconvolution">
159             <data kernel="_K_" strides="_KS_"
160              pads_begin="_PB_" pads_end="_PE_"
161              dilations="1,1,1" output="_OC_" group="_GC_" PrimitivesPriority="_IMPLS_"/>
162             <input>
163                 <port id="0">
164                     __INP_DIMS__
165                 </port>
166             </input>
167             <output>
168                 <port id="1">
169                     <dim>_IN_</dim>
170                     <dim>_OC_</dim>
171                     __DECONV_OUT_DIMS__
172                 </port>
173             </output>
174             <blobs>
175                 <weights offset="0" size="262144"/>
176             </blobs>
177         </layer>
178         <layer id="3" name="concat0" precision="FP32" type="Concat">
179             <data axis="__AXIS__"/>
180             <input>
181                 <port id="0">
182                     <dim>_IN_</dim>
183                     <dim>_OC_</dim>
184                     __DECONV_OUT_DIMS__
185                 </port>
186                 <port id="1">
187                     __INP_DIMS__
188                 </port>
189             </input>
190             <output>
191                 <port id="2">
192                     __CONCAT_OUT_DIMS__
193                 </port>
194             </output>
195         </layer>
196 )V0G0N";
197
198     std::string edges_t = R"V0G0N(
199         <edge from-layer="0" from-port="0" to-layer="2" to-port="0"/>
200         <edge from-layer="0" from-port="0" to-layer="3" to-port="1"/>
201         <edge from-layer="2" from-port="1" to-layer="3" to-port="0"/>
202 )V0G0N";
203
204     std::string getModel(deconv_concat_params p) {
205         std::string model = layers_t;
206         
207         std::string s_dims;
208         for (auto& dim : p.in) {
209             s_dims += "\n                    <dim>";
210             s_dims += std::to_string(dim) + "</dim>";
211         }
212         REPLACE_WITH_STR(model, "__INP_DIMS__", s_dims);
213
214         s_dims = "";
215         size_t deconv_axis_val = p.in[p.concat.axis];
216         int k_len = p.deconv.kernel.size();
217         for (size_t i = 2lu; i < p.in.size(); i++) {
218             size_t inx = k_len - i + 1;
219             size_t dim = p.deconv.stride[inx] * (p.in[i] - 1) + p.deconv.kernel[inx] - 2 * p.deconv.pads_begin[inx];
220             s_dims += "\n                    <dim>";
221             s_dims += std::to_string(dim) + "</dim>";
222             if (i == p.concat.axis) {
223                 deconv_axis_val = dim;
224             }
225         }
226         REPLACE_WITH_STR(model, "__DECONV_OUT_DIMS__", s_dims);
227
228         s_dims = "";
229         for (size_t i = 0lu; i < p.in.size(); i++) {
230             size_t val = p.in[i];
231             if (i == p.concat.axis) {
232                 val += deconv_axis_val;
233             }
234             s_dims += "\n                    <dim>";
235             s_dims += std::to_string(val) + "</dim>";
236         }
237         REPLACE_WITH_STR(model, "__CONCAT_OUT_DIMS__", s_dims);
238
239         REPLACE_WITH_NUM_VECTOR_REVERSE(model, "_K_", p.deconv.kernel);
240         REPLACE_WITH_NUM_VECTOR_REVERSE(model, "_KS_", p.deconv.stride);
241         REPLACE_WITH_NUM_VECTOR_REVERSE(model, "_PB_", p.deconv.pads_begin);
242         REPLACE_WITH_NUM_VECTOR_REVERSE(model, "_PE_", p.deconv.pads_end);
243         REPLACE_WITH_NUM(model, "_GC_", p.deconv.group);
244         REPLACE_WITH_NUM(model, "_OC_", p.deconv.out_c);
245         REPLACE_WITH_NUM(model, "_IN_", p.in[0]);
246         REPLACE_WITH_NUM(model, "__AXIS__", p.concat.axis);
247
248         std::string impls;
249         for (const auto& preferType : p.preferTypes) {
250             if (!impls.empty())
251                 impls += ",";
252             impls += "cpu:" + MKLDNNGraphTestClass::getStrPrimitiveDescriptorType(preferType);
253         }
254         REPLACE_WITH_STR(model, "_IMPLS_", impls);
255
256         model = IRTemplateGenerator::getIRTemplate("Deconvolution_Concat", p.in, "FP32", model, edges_t);
257
258         return model;
259     }
260
261 protected:
262     virtual void TearDown() {
263     }
264
265     virtual void SetUp() {
266         try {
267             TestsCommon::SetUp();
268             deconv_concat_params p = ::testing::WithParamInterface<deconv_concat_params>::GetParam();
269             std::string model = getModel(p);
270
271             InferenceEngine::CNNNetReader net_reader;
272             ASSERT_NO_THROW(net_reader.ReadNetwork(model.data(), model.length()));
273
274             size_t blob_size = p.deconv.out_c * (p.in[1] / p.deconv.group);
275             for (int i = 0 ; i < p.deconv.kernel.size(); i++) {
276                 blob_size *= p.deconv.kernel[i];
277             }
278             InferenceEngine::SizeVector dims_weights = { blob_size };
279
280             std::vector<InferenceEngine::Blob::Ptr> blob_to_model;
281             InferenceEngine::Blob::Ptr weights = InferenceEngine::make_shared_blob<float>(InferenceEngine::Precision::FP32, InferenceEngine::C, dims_weights);
282             weights->allocate();
283             fill_data(weights->buffer().as<float*>(), weights->size());
284             blob_to_model.push_back(weights);
285
286             InferenceEngine::Blob::Ptr bias = InferenceEngine::make_shared_blob<float>(InferenceEngine::Precision::FP32, InferenceEngine::C, {p.deconv.out_c});
287             bias->allocate();
288             fill_data(bias->buffer().as<float*>(), bias->size());
289             blob_to_model.push_back(bias);
290
291             size_t total_size_in_bytes = 0;
292             for (InferenceEngine::Blob::Ptr blb : blob_to_model) total_size_in_bytes += blb->byteSize();
293
294             InferenceEngine::TBlob<uint8_t>::Ptr model_blob =
295                     InferenceEngine::make_shared_blob<uint8_t>(InferenceEngine::Precision::U8, InferenceEngine::C, {total_size_in_bytes});
296             model_blob->allocate();
297             uint8_t* model_blob_ptr = model_blob->buffer().as<uint8_t*>();
298             for (InferenceEngine::Blob::Ptr blb : blob_to_model) {
299                 memcpy(model_blob_ptr, blb->buffer().as<uint8_t*>(), blb->byteSize());
300                 model_blob_ptr += blb->byteSize();
301             }
302             net_reader.SetWeights(model_blob);
303
304             auto network = net_reader.getNetwork();
305             MKLDNNGraphTestClass graph;
306             graph.CreateGraph(network);
307
308             InferenceEngine::SizeVector dims_src = p.in;
309
310             InferenceEngine::Blob::Ptr src = InferenceEngine::make_shared_blob<float, const InferenceEngine::SizeVector>(
311                     InferenceEngine::Precision::FP32, InferenceEngine::TensorDesc::getLayoutByDims(p.in), dims_src);
312             src->allocate();
313             fill_data(src->buffer(), src->size());
314
315             InferenceEngine::TBlob<float>* srcPtr = dynamic_cast<InferenceEngine::TBlob<float>*>(src.get());
316
317             if (srcPtr == nullptr)
318                 FAIL() << "Cannot cast blob to TBlob<float>.";
319
320             InferenceEngine::BlobMap srcs;
321             srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("in1", src));
322
323             InferenceEngine::OutputsDataMap out;
324             out = network.getOutputsInfo();
325             InferenceEngine::BlobMap outputBlobs;
326
327             std::pair<std::string, InferenceEngine::DataPtr> item = *out.begin();
328
329             InferenceEngine::TBlob<float>::Ptr output;
330             output = InferenceEngine::make_shared_blob<float>(item.second->getTensorDesc());
331             output->allocate();
332             outputBlobs[item.first] = output;
333
334             graph.Infer(srcs, outputBlobs);
335
336             // Compare with reference
337
338             auto deconv = network.getLayerByName("Deconvolution_1");
339             InferenceEngine::TBlob<float> deconv_ref(deconv->outData[0]->getTensorDesc());
340             deconv_ref.allocate();
341
342             ref_deconv_common(*srcPtr, deconv_ref, weights->buffer().as<float*>(), weights->size(),
343                     bias->buffer().as<float*>(), bias->size(), p.deconv);
344
345             float *src1_ptr = deconv_ref.buffer();
346             size_t src1_size = deconv_ref.size();
347             float *src2_ptr = src->buffer();
348             size_t src2_size = src->size();
349             float *dst_ptr = output->buffer();
350             size_t dst_size = output->size();
351
352             int len1 = 1, len2 = 1;
353             for (int dim = p.concat.axis; dim < output->dims().size(); dim++) {
354                 len1 *= deconv->outData[0]->getTensorDesc().getDims()[dim];
355                 len2 *= src->dims()[dim];
356             }
357
358             size_t index1 = 0, index2 = 0, index = 0;
359             float max_diff = 0.0001f;
360             for (size_t cycle = 0lu; cycle < p.concat.axis; cycle ++) {
361                 for (int i1 = 0; i1 < len1; i1++) {
362                     if (fabs(src1_ptr[index1] - dst_ptr[index]) > max_diff)
363                     {
364                         FAIL() << "index: " << index << " src: " << src1_ptr[index1] << ", dst: " << dst_ptr[index];
365                     }
366                     index1++; index++;
367                 }
368                 for (int i2 = 0; i2 < len2; i2++) {
369                     if (fabs(src2_ptr[index2] - dst_ptr[index]) > max_diff)
370                     {
371                         FAIL() << "index: " << index << " src: " << src2_ptr[index2] << ", dst: " << dst_ptr[index];
372                     }
373                     index2++; index++;
374                 }
375             }
376
377         } catch (const InferenceEngine::details::InferenceEngineException &e) {
378             FAIL() << e.what();
379         }
380     }
381 };
382
383 TEST_P(MKLDNNDeconvConcatTests, TestsDwConvFusing) {}
384
385 INSTANTIATE_TEST_CASE_P(
386         TestsDwConvFusing, MKLDNNDeconvConcatTests,
387         ::testing::Values(
388                 deconv_concat_params{{1, 256, 4, 4}, 
389                                      { {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, "", 1, 256, false },
390                                      {1}, {MKLDNNPlugin::impl_desc_type::gemm_blas}},
391                 deconv_concat_params{{2, 256, 4, 4},
392                                      { {1, 1}, {1, 1}, {0, 0}, {0, 0}, {1, 1}, "", 1, 256, false },
393                                      {1}, {MKLDNNPlugin::impl_desc_type::gemm_blas}},
394                 deconv_concat_params{{1, 256, 4, 4, 4},
395                                      { {1, 1, 1}, {1, 1, 1}, {0, 0, 0}, {0, 0, 0}, {1, 1, 1}, "", 1, 256, false },
396                                      {1}, {MKLDNNPlugin::impl_desc_type::gemm_blas}},
397                 deconv_concat_params{{2, 256, 4, 4, 4},
398                                      { {1, 1, 1}, {1, 1, 1}, {0, 0, 0}, {0, 0, 0}, {1, 1, 1}, "", 1, 256, false },
399                                      {1}, {MKLDNNPlugin::impl_desc_type::gemm_blas}}
400         ));