Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / mkl-dnn / tests / gtests / test_convolution_depthwise_forward_common.hpp
1 /*******************************************************************************
2 * Copyright 2018-2019 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 #include "math_utils.hpp"
20 #include "mkldnn.hpp"
21
22 using namespace mkldnn::impl::math;
23
24 namespace mkldnn {
25
26 template <typename T, typename U>
27 inline typename std::remove_reference<T>::type div_up(const T a, const U b) {
28     assert(b);
29     return (a + b - 1) / b;
30 }
31
32 template <typename T, typename U>
33 inline typename std::remove_reference<T>::type rnd_up(const T a, const U b) {
34     return div_up(a, b) * b;
35 }
36
37 template <typename data_t_src, typename data_t_wei,
38           typename data_t_acc, typename data_t_dst>
39 void compute_ref_conv_depthwise_fwd(const test_convolution_sizes_t &c,
40         const memory &src, const memory &weights, const memory &bias,
41         const memory &dst, bool w_bias, algorithm depthwise_alg,
42         const memory &depthwise_weights, const memory &depthwise_bias)
43 {
44     data_t_src *src_data = (data_t_src *)src.get_data_handle();
45     data_t_wei *weights_data = (data_t_wei *)weights.get_data_handle();
46     data_t_dst *bias_data
47             = (data_t_dst *)(w_bias ? bias.get_data_handle() : nullptr);
48     data_t_dst *dst_data = (data_t_dst *)dst.get_data_handle();
49
50     float *d_weights_data = (float *)depthwise_weights.get_data_handle();
51     float *d_bias_data = (float *)depthwise_bias.get_data_handle();
52
53     const memory::desc src_d = src.get_primitive_desc().desc();
54     const memory::desc weights_d = weights.get_primitive_desc().desc();
55     const memory::desc dst_d = dst.get_primitive_desc().desc();
56
57     size_t padded_ic = src_d.data.layout_desc.blocking.padding_dims[1];
58     size_t padded_oc = dst_d.data.layout_desc.blocking.padding_dims[1];
59
60     size_t padded_ic_w = weights_d.data.format == mkldnn_OhIw8o4i ? weights_d.data.layout_desc.blocking.padding_dims[1] :
61                                                                     src_d.data.layout_desc.blocking.padding_dims[1];
62     size_t padded_oc_w = weights_d.data.format == mkldnn_OhIw8o4i ? weights_d.data.layout_desc.blocking.padding_dims[0] :
63                                                                     dst_d.data.layout_desc.blocking.padding_dims[1];
64
65     mkldnn::impl::parallel_nd(c.mb, c.ng, c.oc / c.ng, c.oh, c.ow,
66         [&](int n, int g, int oc, int oh, int ow) {
67             size_t oidx = n * padded_oc * c.oh * c.ow
68                     + g * padded_oc / c.ng * c.oh * c.ow
69                     + oc * c.oh * c.ow + oh * c.ow + ow;
70
71             size_t didx = map_index(dst_d, oidx);
72             size_t bidx = g * c.oc / c.ng + oc;
73             dst_data[didx] = bias_data
74                     ? bias_data[bidx] : data_t_dst{0};
75
76             for (int ic = 0; ic < c.ic / c.ng; ic++)
77             for (int kh = 0; kh < c.kh; kh++)
78             for (int kw = 0; kw < c.kw; kw++)
79             {
80                 int ih = oh * c.strh - c.padh + kh * (1 + c.dilh);
81                 if (ih < 0 || ih >= c.ih) continue;
82                 int iw = ow * c.strw - c.padw + kw * (1 + c.dilw);
83                 if (iw < 0 || iw >= c.iw) continue;
84
85                 size_t iidx = n * padded_ic * c.ih * c.iw
86                     + g * padded_ic / c.ng * c.ih * c.iw
87                     + ic * c.ih * c.iw + ih * c.iw + iw;
88                 size_t widx = g * padded_oc_w / c.ng * padded_ic_w
89                     / c.ng * c.kh * c.kw
90                     + oc * padded_ic_w / c.ng * c.kh * c.kw
91                     + ic * c.kh * c.kw + kh * c.kw + kw;
92
93                 dst_data[didx] += src_data[map_index(src_d, iidx)]
94                         * weights_data[map_index(weights_d, widx)];
95             }
96
97             switch (depthwise_alg) {
98                 case depthwise_scale_shift:
99                     dst_data[didx] = scale_shift_fwd(dst_data[didx], d_weights_data[bidx], d_bias_data[bidx]);
100                     break;
101                 case depthwise_prelu:
102                     dst_data[didx] = prelu_fwd(dst_data[didx], d_weights_data[bidx]);
103                     break;
104                 default: assert(!"unknown alg_kind");
105             }
106         }
107     );
108 }
109
110 template <typename data_t_src, typename data_t_wei,
111           typename data_t_acc, typename data_t_dst>
112 class convolution_depthwise_test
113     : public ::testing::TestWithParam<test_convolution_depthwise_params_t> {
114 protected:
115     virtual void SetUp() {
116         test_convolution_depthwise_params_t p
117                 = ::testing::TestWithParam<
118                 test_convolution_depthwise_params_t>::GetParam();
119
120         ASSERT_TRUE(p.engine_kind == engine::kind::cpu);
121         ASSERT_EQ(p.aalgorithm, convolution_direct);
122         auto eng = engine(p.engine_kind, 0);
123
124         memory::data_type data_type_src = data_traits<data_t_src>::data_type;
125         memory::data_type data_type_dst = data_traits<data_t_dst>::data_type;
126         memory::data_type data_type_wei = data_traits<data_t_wei>::data_type;
127
128         test_convolution_sizes_t cd = p.sizes;
129
130         auto c_src_desc = create_md({ cd.mb, cd.ic, cd.ih, cd.iw },
131                 data_type_src, p.formats.src_format);
132         auto c_weights_desc = cd.ng > 1 ?
133                 create_md({ cd.ng, cd.oc / cd.ng, cd.ic / cd.ng, cd.kh, cd.kw },
134                         data_type_wei, p.formats.weights_format) :
135                 create_md({ cd.oc, cd.ic, cd.kh, cd.kw },
136                         data_type_wei, p.formats.weights_format);
137         auto c_dst_desc = create_md({ cd.mb, cd.oc, cd.oh, cd.ow },
138                 data_type_dst, p.formats.dst_format);
139
140         auto c_src = memory({c_src_desc, eng});
141         auto c_weights = memory({c_weights_desc, eng});
142         auto c_dst = memory({c_dst_desc, eng});
143
144         auto dst_ref = memory({c_dst_desc, eng});
145
146         fill_data<data_t_src>(c_src.get_primitive_desc().get_size()
147                 / sizeof(data_t_src), (data_t_src *)c_src.get_data_handle(),
148                 data_t_src(0), data_t_src(1));
149         check_zero_tail<data_t_src>(1, c_src);
150
151         fill_data<data_t_wei>(
152                 c_weights.get_primitive_desc().get_size()
153                 / sizeof(data_t_wei),(data_t_wei *)c_weights.get_data_handle(),
154                 data_t_wei(0), data_t_wei(1));
155         check_zero_tail<data_t_wei>(1, c_weights);
156
157         bool with_bias = p.formats.bias_format != memory::format::format_undef;
158         auto c_bias_desc = with_bias ?
159                 create_md({ cd.oc }, data_type_dst, p.formats.bias_format) :
160                 create_md({}, data_type_dst, p.formats.bias_format);
161         auto c_bias = memory({c_bias_desc, eng});
162         if (with_bias) {
163             fill_data<data_t_dst>(
164                     c_bias.get_primitive_desc().get_size() / sizeof(data_t_dst),
165                     (data_t_dst *)c_bias.get_data_handle(), 1., true);
166         }
167
168         std::vector<ptrdiff_t> padR = { cd.padh, cd.padw };
169         for (int i = 0; i < 2; ++i) {
170             if ((cd.ih - ((cd.kh - 1) * (cd.dilh + 1) + 1) + cd.padh + padR[0])
171                 / cd.strh + 1 != cd.oh)
172                 ++padR[0];
173             if ((cd.iw - ((cd.kw - 1) * (cd.dilw + 1) + 1) + cd.padw + padR[1])
174                 / cd.strw + 1 != cd.ow)
175                 ++padR[1];
176         }
177
178         auto c_depthwise_weights_desc = create_md({ rnd_up(cd.oc, 16) }, data_type_dst, memory::x);
179         auto c_depthwise_bias_desc = create_md({ rnd_up(cd.oc, 16) }, data_type_dst, memory::x);
180
181         auto c_depthwise_weights = memory({c_depthwise_weights_desc, eng});
182         auto c_depthwise_bias = memory({c_depthwise_bias_desc, eng});
183
184         fill_data<data_t_dst>(
185                 c_depthwise_weights.get_primitive_desc().get_size() / sizeof(data_t_dst),
186                 (data_t_dst *)c_depthwise_weights.get_data_handle(), 1., true);
187         fill_data<data_t_dst>(
188                 c_depthwise_bias.get_primitive_desc().get_size() / sizeof(data_t_dst),
189                 (data_t_dst *)c_depthwise_bias.get_data_handle(), 1., true);
190
191
192         auto test = [&]() {
193             mkldnn::post_ops ops;
194             ops.append_depthwise(p.alg, static_cast<const float*>(c_depthwise_weights.get_data_handle()),
195                                         static_cast<const float*>(c_depthwise_bias.get_data_handle()));
196
197             mkldnn::primitive_attr attr;
198             attr.set_post_ops(ops);
199
200             auto conv_desc = with_bias
201                 ? convolution_forward::desc(prop_kind::forward_scoring,
202                         p.aalgorithm, c_src_desc, c_weights_desc, c_bias_desc,
203                         c_dst_desc, { cd.strh, cd.strw }, { cd.dilh, cd.dilw },
204                         { cd.padh, cd.padw }, padR, padding_kind::zero)
205                 : convolution_forward::desc(prop_kind::forward_scoring,
206                         p.aalgorithm, c_src_desc, c_weights_desc, c_dst_desc,
207                         { cd.strh, cd.strw }, { cd.dilh, cd.dilw },
208                         { cd.padh, cd.padw }, padR, padding_kind::zero);
209
210             auto conv_primitive_desc =
211                 convolution_forward::primitive_desc(conv_desc, attr, eng);
212
213             auto conv = with_bias
214                 ? convolution_forward(conv_primitive_desc,
215                         c_src, c_weights, c_bias, c_dst)
216                 : convolution_forward(conv_primitive_desc,
217                         c_src, c_weights, c_dst);
218             std::vector<primitive> pipeline;
219             pipeline.push_back(conv);
220
221             stream(stream::kind::lazy).submit(pipeline).wait();
222         };
223
224         if (catch_expected_failures(test, p.expect_to_fail, p.expected_status))
225             return;
226
227         compute_ref_conv_depthwise_fwd<data_t_src, data_t_wei, data_t_wei,
228             data_t_dst>(cd, c_src, c_weights, c_bias, dst_ref, with_bias,
229                         p.alg, c_depthwise_weights, c_depthwise_bias);
230         check_zero_tail<data_t_dst>(1, dst_ref);
231
232         compare_data<data_t_dst>(dst_ref, c_dst, 1e-2);
233         check_zero_tail<data_t_dst>(0, c_dst);
234     }
235 };
236
237 }