Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / mkl-dnn / tests / gtests / test_deconvolution.cpp
1 /*******************************************************************************
2 * Copyright 2018 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16
17 #include "mkldnn_test_common.hpp"
18 #include "gtest/gtest.h"
19
20 #include "mkldnn.hpp"
21 #include "mkldnn_debug.h"
22 namespace mkldnn {
23 using fmt = memory::format;
24 struct deconvolution_test_params {
25     const mkldnn::engine::kind engine_kind;
26     mkldnn::algorithm aalgorithm;
27     test_convolution_formats_t formats;
28     test_convolution_attr_t attr;
29     test_convolution_sizes_t sizes;
30     bool expect_to_fail;
31     mkldnn_status_t expected_status;
32 };
33 template <typename data_t>
34 void compute_bias_fwd(const test_convolution_sizes_t &c,
35     mkldnn::memory& dst, mkldnn::memory& bias) {
36     data_t *bias_data = (data_t *)bias.get_data_handle();
37     data_t *dst_data = (data_t *)dst.get_data_handle();
38
39     const memory::desc bias_d = bias.get_primitive_desc().desc();
40     const memory::desc dst_d = dst.get_primitive_desc().desc();
41
42     mkldnn::impl::parallel_nd(c.mb, c.ng, c.oc / c.ng, c.oh, c.ow,
43         [&](int n, int g, int oc, int oh, int ow) {
44             data_t b = bias_data[map_index(bias_d, g * c.oc / c.ng + oc)];
45             int oidx = n * c.oc * c.oh * c.ow
46                 + g * c.oc / c.ng * c.oh * c.ow
47                 + oc * c.oh * c.ow + oh * c.ow + ow;
48             dst_data[map_index(dst_d, oidx)] += b;
49         }
50     );
51 }
52
53 template <typename data_t>
54 void compute_bias_bwd(const test_convolution_sizes_t &c,
55     mkldnn::memory& dst, mkldnn::memory& bias) {
56     data_t *bias_data = (data_t *)bias.get_data_handle();
57     data_t *dst_data = (data_t *)dst.get_data_handle();
58
59     const memory::desc bias_d = bias.get_primitive_desc().desc();
60     const memory::desc dst_d = dst.get_primitive_desc().desc();
61
62     mkldnn::impl::parallel_nd(c.ng, c.oc / c.ng, [&](int g, int oc) {
63         int bidx = g * c.oc / c.ng + oc;
64         bias_data[map_index(bias_d, bidx)] = 0.0;
65         for (int mb = 0; mb < c.mb; ++mb) {
66             for (int oh = 0; oh < c.oh; ++oh) {
67                 for (int ow = 0; ow < c.ow; ++ow) {
68                     int oidx = mb * c.oc * c.oh * c.ow
69                             + g * c.oc / c.ng * c.oh * c.ow
70                             + oc * c.oh * c.ow + oh * c.ow + ow;
71                     bias_data[map_index(bias_d, bidx)]
72                         += dst_data[map_index(dst_d, oidx)];
73                 }
74             }
75         }
76     });
77 }
78
79 template <typename data_t>
80 void transpose_wei(const test_convolution_sizes_t &c,
81     mkldnn::memory& weights, mkldnn::memory& weights_tr) {
82
83     data_t *weights_data = (data_t *)weights.get_data_handle();
84     const memory::desc weights_d = weights.get_primitive_desc().desc();
85     data_t *weights_tr_data = (data_t *)weights_tr.get_data_handle();
86     const memory::desc weights_tr_d = weights_tr.get_primitive_desc().desc();
87
88     mkldnn::impl::parallel_nd(c.ng, c.oc / c.ng, c.ic / c.ng, c.kh, c.kw,
89         [&](int g, int oc, int ic, int kh, int kw) {
90             int widx = g * c.oc / c.ng * c.ic / c.ng * c.kh * c.kw
91                      + oc * c.ic / c.ng * c.kh * c.kw
92                      + ic * c.kh * c.kw + kh * c.kw + kw;
93             int widx_tr = g * c.oc / c.ng * c.ic / c.ng * c.kh * c.kw
94                      + ic * c.oc / c.ng * c.kh * c.kw
95                      + oc * c.kh * c.kw + kh * c.kw + kw;
96             weights_tr_data[map_index(weights_tr_d, widx_tr)]
97                  = weights_data[map_index(weights_d, widx)];
98         }
99     );
100 }
101
102 template <typename data_t>
103 class deconvolution_test : public
104 ::testing::TestWithParam<deconvolution_test_params> {
105 private:
106    std::shared_ptr<test_memory> src;
107    std::shared_ptr<test_memory> weights;
108    std::shared_ptr<test_memory> dst;
109    std::shared_ptr<test_memory> bias;
110
111    std::shared_ptr<memory::desc> dec_src_desc;
112    std::shared_ptr<memory::desc> dec_weights_desc;
113    std::shared_ptr<memory::desc> dec_bias_desc;
114    std::shared_ptr<memory::desc> dec_dst_desc;
115
116    std::shared_ptr<memory::desc> con_src_desc;
117    std::shared_ptr<memory::desc> con_bias_desc;
118    std::shared_ptr<memory::desc> con_dst_desc;
119    std::shared_ptr<memory::desc> con_weights_desc;
120
121    std::shared_ptr<engine> eng;
122    bool with_bias;
123    std::vector<ptrdiff_t> padR;
124 protected:
125     virtual void SetUp() {
126         auto p = ::testing::TestWithParam<deconvolution_test_params>::GetParam();
127         catch_expected_failures([=](){Test();}, p.expect_to_fail,
128                     p.expected_status);
129     }
130
131     void Test() {
132         auto p = ::testing::TestWithParam<deconvolution_test_params>::GetParam();
133
134         ASSERT_TRUE(p.engine_kind == engine::kind::cpu);
135         eng.reset(new engine(p.engine_kind, 0));
136
137         ASSERT_EQ(p.aalgorithm, algorithm::deconvolution_direct);
138         memory::data_type data_type = data_traits<data_t>::data_type;
139
140         test_convolution_sizes_t dd = p.sizes;
141         p.formats.bias_format = memory::format::format_undef;
142         with_bias = p.formats.bias_format != memory::format::format_undef;
143
144         memory::dims src_dims = {dd.mb, dd.ic, dd.ih, dd.iw};
145         memory::dims dst_dims = {dd.mb, dd.oc, dd.oh, dd.ow};
146         memory::dims weights_dims, c_weights_dims;
147         if (dd.ng > 1) {
148             weights_dims = { dd.ng, dd.oc / dd.ng, dd.ic / dd.ng, dd.kh, dd.kw };
149             c_weights_dims = { dd.ng, dd.ic / dd.ng, dd.oc / dd.ng, dd.kh, dd.kw };
150         } else {
151             weights_dims = { dd.oc, dd.ic, dd.kh, dd.kw };
152             c_weights_dims = { dd.ic, dd.oc, dd.kh, dd.kw };
153         }
154         memory::dims bias_dims;
155         if (with_bias) bias_dims = {dd.oc};
156         else bias_dims = {};
157
158         dec_src_desc.reset(new memory::desc(src_dims, data_type,
159             p.formats.src_format));
160         dec_dst_desc.reset(new memory::desc(dst_dims, data_type,
161             p.formats.src_format));
162         dec_weights_desc.reset(new memory::desc(weights_dims, data_type,
163             p.formats.weights_format));
164         dec_bias_desc.reset(new memory::desc(bias_dims, data_type,
165             p.formats.bias_format));
166
167         con_src_desc.reset(new memory::desc(dst_dims, data_type,
168             p.formats.src_format));
169         con_dst_desc.reset(new memory::desc(src_dims, data_type,
170             p.formats.src_format));
171         con_weights_desc.reset(new memory::desc(c_weights_dims, data_type,
172             p.formats.weights_format));
173
174         src.reset(new test_memory(*dec_src_desc, *eng));
175         weights.reset(new test_memory(*dec_weights_desc, *eng));
176         bias.reset(new test_memory(*dec_bias_desc, *eng));
177         dst.reset(new test_memory(*dec_dst_desc, *eng));
178
179         padR = {
180             right_padding(dd.oh, dd.ih, dd.kh, dd.padh, dd.strh, dd.dilh),
181             right_padding(dd.ow, dd.iw, dd.kw, dd.padw, dd.strw, dd.dilw)
182         };
183         Forward();
184         BackwardData();
185         BackwardWeights();
186     }
187     void Forward() {
188         auto aprop_kind =  prop_kind::forward;
189         deconvolution_test_params p =
190             ::testing::TestWithParam<deconvolution_test_params>::GetParam();
191         auto conv_src = test_memory(*con_src_desc, *eng);
192         auto conv_dst = src;
193         test_convolution_sizes_t dd = p.sizes;
194
195         fill_data<data_t>(src->get_size() / sizeof(data_t),
196             (data_t *)src->get().get_data_handle());
197
198         fill_data<data_t>(weights->get_size() / sizeof(data_t),
199                 (data_t *)weights->get().get_data_handle());
200         if (with_bias) {
201             fill_data<data_t>(bias->get_size() / sizeof(data_t),
202                     (data_t *)bias->get().get_data_handle());
203         }
204
205         auto weights_tr = memory({*con_weights_desc, *eng});
206         transpose_wei<data_t>(dd, weights->get(), weights_tr);
207         auto deconv_desc = with_bias ?
208             deconvolution_forward::desc(aprop_kind,
209                     algorithm::deconvolution_direct, *dec_src_desc,
210                     *dec_weights_desc, *dec_bias_desc, *dec_dst_desc,
211                     { dd.strh, dd.strw }, { dd.padh, dd.padw }, padR,
212                     padding_kind::zero) :
213                 deconvolution_forward::desc(aprop_kind,
214                         algorithm::deconvolution_direct, *dec_src_desc,
215                         *dec_weights_desc, *dec_dst_desc, { dd.strh, dd.strw },
216                         { dd.padh, dd.padw }, padR, padding_kind::zero);
217
218         auto deconv_primitive_desc = deconvolution_forward::primitive_desc(
219                 deconv_desc, *eng);
220
221         auto deconv = with_bias ?
222             deconvolution_forward(deconv_primitive_desc, src->get(),
223                     weights->get(), bias->get(), dst->get()) :
224             deconvolution_forward(deconv_primitive_desc, src->get(),
225                     weights->get(), dst->get());
226
227         auto conv_desc = convolution_forward::desc(
228                 prop_kind::forward_training, algorithm::convolution_direct,
229                 *con_src_desc, *con_weights_desc, *con_dst_desc,
230                 { dd.strh, dd.strw }, { dd.padh, dd.padw }, padR,
231                 padding_kind::zero);
232
233         auto conv_primitive_desc = convolution_forward::primitive_desc(
234                 conv_desc, *eng);
235
236         auto conv_bwd_data_desc = convolution_backward_data::desc(
237                 algorithm::convolution_direct, *con_src_desc,
238                 *con_weights_desc, *con_dst_desc,
239                 { dd.strh, dd.strw }, { dd.padh, dd.padw }, padR,
240                 padding_kind::zero);
241
242         auto conv_bwd_data_primitive_desc
243             = convolution_backward_data::primitive_desc(
244                     conv_bwd_data_desc, *eng, conv_primitive_desc);
245
246         auto conv_bwd_data = convolution_backward_data(
247                 conv_bwd_data_primitive_desc,
248                 conv_dst->get(), weights_tr, conv_src.get());
249
250         std::vector<primitive> pipeline;
251         pipeline.push_back(deconv);
252         pipeline.push_back(conv_bwd_data);
253         stream(stream::kind::lazy).submit(pipeline).wait();
254
255         if(with_bias) compute_bias_fwd<data_t>(dd, conv_src.get(), bias->get());
256         compare_data<data_t>(conv_src.get(), dst->get());
257     }
258
259     void BackwardData() {
260         auto p = ::testing::TestWithParam<deconvolution_test_params>::GetParam();
261         auto conv_src = dst;
262         auto conv_dst = test_memory(*con_dst_desc, *eng);
263         test_convolution_sizes_t dd = p.sizes;
264
265         fill_data<data_t>(weights->get_size() / sizeof(data_t),
266             (data_t *)weights->get().get_data_handle());
267
268         fill_data<data_t>(dst->get_size() / sizeof(data_t),
269                 (data_t *)dst->get().get_data_handle());
270
271         auto weights_tr = memory({*con_weights_desc, *eng});
272         transpose_wei<data_t>(dd, weights->get(), weights_tr);
273
274         auto deconv_desc = deconvolution_forward::desc(prop_kind::forward_training,
275                 algorithm::deconvolution_direct, *dec_src_desc,
276                 *dec_weights_desc, *dec_dst_desc, { dd.strh, dd.strw },
277                 { dd.padh, dd.padw }, padR, padding_kind::zero);
278
279         auto deconv_primitive_desc = deconvolution_forward::primitive_desc(
280                 deconv_desc, *eng);
281
282         auto deconv_bwd_data_desc = deconvolution_backward_data::desc(
283                 algorithm::deconvolution_direct, *dec_src_desc,
284                 *dec_weights_desc, *dec_dst_desc,
285                 { dd.strh, dd.strw }, { dd.padh, dd.padw }, padR,
286                 padding_kind::zero);
287         auto deconv_bwd_data_primitive_desc
288             = deconvolution_backward_data::primitive_desc(
289                     deconv_bwd_data_desc, *eng, deconv_primitive_desc);
290
291         auto deconv_bwd_data = deconvolution_backward_data(
292                 deconv_bwd_data_primitive_desc, dst->get(), weights->get(),
293                 src->get());
294
295         auto conv_desc = convolution_forward::desc(
296                 prop_kind::forward_training, algorithm::convolution_direct,
297                 *con_src_desc, *con_weights_desc, *con_dst_desc,
298                 { dd.strh, dd.strw }, { dd.padh, dd.padw }, padR,
299                 padding_kind::zero);
300
301         auto conv_primitive_desc = convolution_forward::primitive_desc(
302                 conv_desc, *eng);
303
304         auto conv = convolution_forward(conv_primitive_desc, conv_src->get(),
305                 weights_tr, conv_dst.get());
306
307         std::vector<primitive> pipeline;
308         pipeline.push_back(deconv_bwd_data);
309         pipeline.push_back(conv);
310         stream(stream::kind::lazy).submit(pipeline).wait();
311
312         compare_data<data_t>(conv_dst.get(), src->get());
313     }
314
315     void BackwardWeights() {
316         auto p = ::testing::TestWithParam<deconvolution_test_params>::GetParam();
317         auto conv_src = dst;
318         auto conv_dst = src;
319         auto conv_weights = memory({*con_weights_desc, *eng});
320         test_convolution_sizes_t dd = p.sizes;
321
322         fill_data<data_t>(src->get_size() / sizeof(data_t),
323             (data_t *)src->get().get_data_handle());
324
325         fill_data<data_t>(dst->get_size() / sizeof(data_t),
326                 (data_t *)dst->get().get_data_handle());
327
328         auto deconv_desc = deconvolution_forward::desc(prop_kind::forward_training,
329                 algorithm::deconvolution_direct, *dec_src_desc,
330                 *dec_weights_desc, *dec_bias_desc, *dec_dst_desc,
331                 { dd.strh, dd.strw }, { dd.padh, dd.padw }, padR, padding_kind::zero);
332
333         auto deconv_primitive_desc = deconvolution_forward::primitive_desc(
334                 deconv_desc, *eng);
335
336         auto deconv_bwd_weights_desc = deconvolution_backward_weights::desc(
337                 algorithm::deconvolution_direct, *dec_src_desc,
338                 *dec_weights_desc, *dec_bias_desc, *dec_dst_desc,
339                 { dd.strh, dd.strw }, { dd.padh, dd.padw }, padR,
340                 padding_kind::zero);
341         auto deconv_bwd_weights_primitive_desc
342             = deconvolution_backward_weights::primitive_desc(
343                     deconv_bwd_weights_desc, *eng, deconv_primitive_desc);
344
345         auto deconv_bwd_weights = deconvolution_backward_weights(
346                 deconv_bwd_weights_primitive_desc, src->get(), dst->get(),
347                 weights->get(), bias->get());
348
349         auto conv_desc = convolution_forward::desc(
350                 prop_kind::forward_training, algorithm::convolution_direct,
351                 *con_src_desc, *con_weights_desc, *con_dst_desc,
352                 { dd.strh, dd.strw }, { dd.padh, dd.padw }, padR,
353                 padding_kind::zero);
354
355         auto conv_primitive_desc = convolution_forward::primitive_desc(
356                 conv_desc, *eng);
357
358         auto conv_bwd_weights_desc = convolution_backward_weights::desc(
359                 algorithm::convolution_direct, *con_src_desc, *con_weights_desc,
360                 *con_dst_desc, { dd.strh, dd.strw }, { dd.padh, dd.padw },
361                 padR, padding_kind::zero);
362
363         auto conv_bwd_weights_primitive_desc =
364             convolution_backward_weights::primitive_desc(
365                     conv_bwd_weights_desc, *eng, conv_primitive_desc);
366
367         auto conv_bwd_weights =
368             convolution_backward_weights(conv_bwd_weights_primitive_desc,
369                     conv_src->get(), conv_dst->get(), conv_weights);
370
371         std::vector<primitive> pipeline;
372         pipeline.push_back(conv_bwd_weights);
373         pipeline.push_back(deconv_bwd_weights);
374         stream(stream::kind::lazy).submit(pipeline).wait();
375
376         auto weights_tr = memory({*con_weights_desc, *eng});
377         transpose_wei<data_t>(dd, weights->get(), weights_tr);
378
379         compare_data<data_t>(weights_tr, conv_weights);
380
381         if (with_bias) {
382             auto ref_bias = memory({*dec_bias_desc, *eng});
383             compute_bias_bwd<data_t>(dd, dst->get(), ref_bias);
384             compare_data<data_t>(ref_bias, bias->get());
385         }
386     }
387 };
388
389 using deconvolution_test_float = deconvolution_test<float>;
390
391 TEST_P(deconvolution_test_float, TestDeconvolution)
392 {
393 }
394
395 #define EXPAND_FORMATS(src, weights, bias, dst) \
396     { mkldnn::memory::format::src, mkldnn::memory::format::weights, \
397     mkldnn::memory::format::bias, mkldnn::memory::format::dst }
398
399 #define ENGINE engine::kind::cpu
400 #define ALGORITHM mkldnn::deconvolution_direct
401
402 #define PARAMS(src, weights, bias, dst, ...) \
403         deconvolution_test_params { ENGINE, ALGORITHM, \
404             EXPAND_FORMATS(src, weights, bias, dst), {}, \
405                 {__VA_ARGS__} }
406
407 #define INST_TEST_CASE(str, ...) INSTANTIATE_TEST_CASE_P( \
408         str, deconvolution_test_float, ::testing::Values(__VA_ARGS__))
409
410 #define FMT_BIAS x
411 #define FMT_DATA_BLOCKED nChw8c
412 #define FMT_WEIGHTS_BLOCKED Ohwi8o
413
414 INST_TEST_CASE(SimpleSmall_NCHW,
415     PARAMS(nchw, oihw, x, nchw,
416         2, 1, 6, 4, 4, 4, 4, 4, 3, 3, 1, 1, 1, 1),
417     PARAMS(nchw, oihw, x, nchw,
418         2, 1, 6, 2, 2, 4, 4, 4, 3, 3, 0, 0, 1, 1),
419     PARAMS(nhwc, oihw, x, nhwc,
420         2, 1, 6, 2, 2, 4, 4, 4, 3, 3, 0, 0, 1, 1),
421     PARAMS(nhwc, hwio, x, nhwc,
422         2, 1, 6, 4, 4, 4, 4, 4, 3, 3, 1, 1, 1, 1),
423     PARAMS(nhwc, hwio, x, nhwc,
424         2, 1, 6, 2, 2, 4, 4, 4, 3, 3, 0, 0, 1, 1),
425     PARAMS(nhwc, goihw, x, nhwc,
426         2, 2, 6, 4, 4, 4, 4, 4, 3, 3, 0, 0, 1, 1),
427     PARAMS(nhwc, hwigo, x, nhwc,
428         2, 2, 6, 4, 4, 4, 4, 4, 3, 3, 1, 1, 1, 1)
429
430 );
431
432 INST_TEST_CASE(SimpleSmall_Blocked,
433     PARAMS(FMT_DATA_BLOCKED, FMT_WEIGHTS_BLOCKED, FMT_BIAS, FMT_DATA_BLOCKED,
434         2, 1, 32, 12, 12, 32, 13, 13, 3, 3, 0, 0, 1, 1),
435     PARAMS(FMT_DATA_BLOCKED, FMT_WEIGHTS_BLOCKED, FMT_BIAS, FMT_DATA_BLOCKED,
436         2, 1, 32, 4, 4, 32, 3, 3, 3, 3, 1, 1, 1, 1),
437     PARAMS(FMT_DATA_BLOCKED, FMT_WEIGHTS_BLOCKED, FMT_BIAS, FMT_DATA_BLOCKED,
438         2, 1, 32, 4, 4, 32, 4, 4, 3, 3, 0, 0, 1, 1),
439     PARAMS(FMT_DATA_BLOCKED, FMT_WEIGHTS_BLOCKED, FMT_BIAS, FMT_DATA_BLOCKED,
440         2, 1, 32, 2, 2, 32, 3, 3, 3, 3, 0, 0, 1, 1),
441     PARAMS(FMT_DATA_BLOCKED, FMT_WEIGHTS_BLOCKED, FMT_BIAS, FMT_DATA_BLOCKED,
442         2, 1, 32, 2, 2, 32, 2, 2, 3, 3, 1, 1, 1, 1),
443     PARAMS(FMT_DATA_BLOCKED, FMT_WEIGHTS_BLOCKED, FMT_BIAS, FMT_DATA_BLOCKED,
444         2, 1, 48, 13, 13, 32, 13, 13, 3, 3, 1, 1, 1, 1),
445     PARAMS(FMT_DATA_BLOCKED, FMT_WEIGHTS_BLOCKED, FMT_BIAS, FMT_DATA_BLOCKED,
446         2, 1, 48, 11, 11, 32, 13, 13, 3, 3, 0, 0, 1, 1)
447 );
448
449
450 }
451