Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / mkl-dnn / tests / gtests / test_convolution_dw_conv_common.hpp
1 /*******************************************************************************
2 * Copyright 2016-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
22 namespace mkldnn {
23
24 template <typename data_t_src, typename data_t_wei,
25           typename data_t_acc, typename data_t_dst>
26 void compute_ref_conv_fwd(const mkldnn_convolution_desc_t &conv_desc,
27         const memory &src, const memory &weights, const memory &bias, const memory &dst,
28         bool with_relu, float eltwise_alpha, const float* depthwise_weights)
29 {
30     int MB = conv_desc.src_desc.dims[0];
31     int G = conv_desc.weights_desc.ndims == 5 ? conv_desc.weights_desc.dims[0] : 1;
32     int IC = conv_desc.src_desc.dims[1];
33     int IH = conv_desc.src_desc.dims[2];
34     int IW = conv_desc.src_desc.dims[3];
35     int OC = conv_desc.dst_desc.dims[1];
36     int OH = conv_desc.dst_desc.dims[2];
37     int OW = conv_desc.dst_desc.dims[3];
38
39     int KH = G > 1 ? conv_desc.weights_desc.dims[3] : conv_desc.weights_desc.dims[2];
40     int KW = G > 1 ? conv_desc.weights_desc.dims[4] : conv_desc.weights_desc.dims[3];
41     int SH = conv_desc.strides[0];
42     int SW = conv_desc.strides[1];
43     int PH = conv_desc.padding[0][0];
44     int PW = conv_desc.padding[1][0];
45     int DH = conv_desc.dilates[0];
46     int DW = conv_desc.dilates[1];
47
48     data_t_src *src_data = (data_t_src *)src.get_data_handle();
49     data_t_wei *weights_data = (data_t_wei *)weights.get_data_handle();
50     float *bias_data = (float *)bias.get_data_handle();
51     data_t_dst *dst_data = (data_t_dst *)dst.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     mkldnn::impl::parallel_nd(MB, G, OC / G, OH, OW,
58         [&](int n, int g, int oc, int oh, int ow) {
59             int oidx = n * OC * OH * OW
60                        + g * OC / G * OH * OW
61                        + oc * OH * OW + oh * OW + ow;
62
63             data_t_acc a = (data_t_acc) 0;
64
65             for (int ic = 0; ic < IC / G; ic++) {
66                 for (int kh = 0; kh < KH; kh++) {
67                     for (int kw = 0; kw < KW; kw++) {
68                         int iw = ow * SW
69                                  - PW + kw * (1 + DW);
70                         int ih = oh * SH
71                                  - PH + kh * (1 + DH);
72                         if (iw < 0 || iw >= IW) continue;
73                         if (ih < 0 || ih >= IH) continue;
74                         int iidx = n * IC * IH * IW
75                                    + g * IC / G * IH * IW
76                                    + ic * IH * IW + ih * IW + iw;
77                         int widx = g * OC / G * IC
78                                    / G * KH * KW
79                                    + oc * IC / G * KH * KW
80                                    + ic * KH * KW + kh * KW + kw;
81
82                         a += src_data[map_index(src_d, iidx)]
83                              * weights_data[map_index(
84                                 weights_d, widx)];
85                     }
86                 }
87             }
88
89             float a_fp = (float) a;
90
91             a_fp += bias_data[G > 1 ? g : oc];
92
93             if (depthwise_weights)
94                 a_fp *= depthwise_weights[G > 1 ? g : oc];
95
96             if (with_relu) {
97                 a_fp = (a_fp > 0) ? a_fp : eltwise_alpha * a_fp;
98             }
99
100             using D = memory::data_type;
101             if (data_traits<data_t_dst>::data_type != D::f32){
102                a_fp = nearbyintf(a_fp);
103             }
104
105             dst_data[map_index(dst_d, oidx)] = (data_t_dst)a_fp;
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_dw_conv_test
113     : public ::testing::TestWithParam<test_convolution_dw_conv_params_t> {
114 protected:
115     void SetUp() {
116         auto p = ::testing::TestWithParam<test_convolution_dw_conv_params_t>::GetParam();
117         ASSERT_TRUE(p.engine_kind == engine::kind::cpu);
118         ASSERT_EQ(p.aalgorithm, convolution_direct);
119         auto eng = engine(p.engine_kind, 0);
120
121         memory::data_type data_type_src = data_traits<data_t_src>::data_type;
122         memory::data_type data_type_dst = data_traits<data_t_dst>::data_type;
123         memory::data_type data_type_wei = data_traits<data_t_wei>::data_type;
124         memory::data_type data_type_bia = data_traits<float>::data_type;
125
126         bool is_int8 = data_type_src == mkldnn_u8 || data_type_src == mkldnn_s8;
127
128         test_convolution_dw_conv_sizes_t cd = p.sizes;
129
130         int conv1_oh = (cd.ih - ((cd.conv1_kh - 1) + 1) + 2 * cd.conv1_padh) / cd.conv1_strh + 1;
131         int conv1_ow = (cd.iw - ((cd.conv1_kw - 1) + 1) + 2 * cd.conv1_padw) / cd.conv1_strw + 1;
132
133         int conv2_oh = (conv1_oh - ((cd.conv2_kh - 1) + 1) + 2 * cd.conv2_padh) / cd.conv2_strh + 1;
134         int conv2_ow = (conv1_ow - ((cd.conv2_kw - 1) + 1) + 2 * cd.conv2_padw) / cd.conv2_strw + 1;
135
136         std::vector<ptrdiff_t> conv1_padR = { cd.conv1_padh, cd.conv1_padw };
137         conv1_padR[0] += conv2_oh - conv1_oh;
138         conv1_padR[1] += conv2_ow - conv1_ow;
139
140         test_convolution_dw_conv_formats_t f = p.formats;
141
142         auto conv1_src_desc = create_md({ cd.mb, cd.ic, cd.ih, cd.iw }, data_type_src, f.src_format);
143         auto conv1_weights_desc = create_md({ cd.conv1_oc, cd.ic, cd.conv1_kh, cd.conv1_kw }, data_type_wei, f.conv1_weights_format);
144         auto conv1_bias_desc = create_md({ cd.conv1_oc }, data_type_bia, f.conv1_bias_format);
145         auto conv1_dst_desc = create_md({ cd.mb, cd.conv1_oc, conv2_oh, conv2_ow }, data_type_dst, f.dst_format);
146
147         auto conv1_desc = convolution_forward::desc(prop_kind::forward_scoring, p.aalgorithm,
148                 conv1_src_desc, conv1_weights_desc, conv1_bias_desc, conv1_dst_desc,
149                 { cd.conv1_strh, cd.conv1_strw }, { 0, 0 },
150                 { cd.conv1_padh, cd.conv1_padw }, conv1_padR, padding_kind::zero);
151
152         auto conv2_src_desc = create_md({ cd.mb, cd.conv1_oc, conv1_oh, conv1_ow }, data_type_src, f.src_format);
153         auto conv2_weights_desc = create_md({ cd.conv2_oc, 1, 1, cd.conv2_kh, cd.conv2_kw }, data_type_wei, f.conv2_weights_format);
154         auto conv2_bias_desc = create_md({ cd.conv2_oc }, data_type_bia, f.conv2_bias_format);
155         auto conv2_dst_desc = create_md({ cd.mb, cd.conv2_oc, conv2_oh, conv2_ow }, data_type_dst, f.dst_format);
156
157         auto conv2_desc = convolution_forward::desc(prop_kind::forward_scoring,
158                 p.aalgorithm, conv2_src_desc, conv2_weights_desc, conv2_bias_desc, conv2_dst_desc,
159                 { cd.conv2_strh, cd.conv2_strw }, { 0, 0 },
160                 { cd.conv2_padh, cd.conv2_padw }, { cd.conv2_padh, cd.conv2_padw }, padding_kind::zero);
161
162         auto conv1_src = memory({conv1_src_desc, eng});
163         auto conv1_weights = memory({conv1_weights_desc, eng});
164         auto conv1_bias = memory({conv1_bias_desc, eng});
165         auto conv2_weights = memory({conv2_weights_desc, eng});
166         auto conv2_bias = memory({conv2_bias_desc, eng});
167         auto conv2_dst = memory({conv2_dst_desc, eng});
168
169         fill_data<data_t_src>(conv1_src.get_primitive_desc().get_size()
170                 / sizeof(data_t_src), (data_t_src *)conv1_src.get_data_handle(), (data_t_src)1, (data_t_src)1);
171         fill_data<data_t_wei>(
172                 conv1_weights.get_primitive_desc().get_size()
173                 / sizeof(data_t_wei),(data_t_wei *)conv1_weights.get_data_handle(), (data_t_wei)1, (data_t_wei)1);
174         fill_data<float>(
175                 conv1_bias.get_primitive_desc().get_size()
176                 / sizeof(float),(float *)conv1_bias.get_data_handle(), 1., true);
177         fill_data<data_t_wei>(
178                 conv2_weights.get_primitive_desc().get_size()
179                 / sizeof(data_t_wei),(data_t_wei *)conv2_weights.get_data_handle(), (data_t_wei)1, (data_t_wei)1);
180         fill_data<float>(
181                 conv2_bias.get_primitive_desc().get_size()
182                 / sizeof(float),(float *)conv2_bias.get_data_handle(), 1., true);
183
184 //        auto conv1_depthwise_weights_desc = create_md({ cd.conv2_oc }, mkldnn::memory::data_type::f32, memory::x);
185 //        auto conv1_depthwise_weights = memory({conv1_depthwise_weights_desc, eng});
186         std::vector<float> conv1_depthwise_weights;
187         conv1_depthwise_weights.resize(cd.conv1_oc);
188         fill_data<float>(conv1_depthwise_weights.size(), &conv1_depthwise_weights[0], 1.f / ((float)cd.ic), 1.f / ((float)cd.ic * cd.conv1_kh * cd.conv1_kw));
189
190         std::vector<float> conv2_depthwise_weights;
191         conv2_depthwise_weights.resize(cd.conv1_oc);
192         fill_data<float>(conv2_depthwise_weights.size(), &conv2_depthwise_weights[0], 1.f / ((float)cd.conv2_oc), 1.f / ((float)cd.conv2_oc * cd.conv2_kh * cd.conv2_kw));
193
194         std::vector<float> conv2_depthwise_bias;
195         conv2_depthwise_bias.resize(cd.conv1_oc);
196 //        fill_data<float>(conv2_depthwise_bias.size(), &conv2_depthwise_bias[0], 1., true);
197         memset(&conv2_depthwise_bias[0], 0, conv2_depthwise_bias.size() * sizeof(float));
198
199 //        auto conv2_depthwise_weights_desc = create_md({ cd.conv2_oc }, mkldnn::memory::data_type::f32, memory::x);
200 //        auto conv2_depthwise_bias_desc = create_md({ cd.conv2_oc }, mkldnn::memory::data_type::f32, memory::x);
201 //
202 //        auto conv2_depthwise_weights = memory({conv2_depthwise_weights_desc, eng});
203 //        auto conv2_depthwise_bias = memory({conv2_depthwise_bias_desc, eng});
204
205 //        fill_data<float>(conv2_depthwise_weights.get_primitive_desc().get_size() / sizeof(float),
206 //                         (float *)conv2_depthwise_weights.get_data_handle(), 1., true);
207 //        memset((float*)conv2_depthwise_bias.get_data_handle(), 0, conv2_depthwise_bias.get_primitive_desc().get_size());
208
209         mkldnn::post_ops conv1_post_ops;
210         conv1_post_ops.append_eltwise(1.0, mkldnn::algorithm::eltwise_relu, 0.0f, 0.0f);
211         conv1_post_ops.append_dw_conv(conv1_oh, conv1_ow, cd.conv2_kh, cd.conv2_kw, cd.conv2_strh, cd.conv2_strw,
212                                       static_cast<const float*>(conv2_weights.get_data_handle()),
213                                       static_cast<const float*>(conv2_bias.get_data_handle()));
214
215         if (is_int8)
216             conv1_post_ops.append_depthwise(depthwise_scale_shift, &conv2_depthwise_weights[0], &conv2_depthwise_bias[0]);
217
218         conv1_post_ops.append_eltwise(1.0, mkldnn::algorithm::eltwise_relu, 0.0f, 0.0f);
219         mkldnn::primitive_attr conv1_attr;
220
221         if (is_int8) {
222             conv1_attr.set_int_output_round_mode(mkldnn::round_nearest);
223             conv1_attr.set_output_scales(1 << 1 /*through C dim*/, conv1_depthwise_weights);
224         }
225
226         conv1_attr.set_post_ops(conv1_post_ops);
227
228         auto conv1_primitive_desc = convolution_forward::primitive_desc(conv1_desc, conv1_attr, eng);
229         auto conv1 = convolution_forward(conv1_primitive_desc, conv1_src, conv1_weights, conv1_bias, conv2_dst);
230
231         std::vector<primitive> pipeline;
232         pipeline.push_back(conv1);
233         stream(stream::kind::lazy).submit(pipeline).wait();
234
235         auto conv1_dst_desc_ref = create_md({ cd.mb, cd.conv1_oc, conv1_oh, conv1_ow }, data_type_dst, f.dst_format);
236         auto conv1_desc_ref = convolution_forward::desc(prop_kind::forward_scoring, p.aalgorithm,
237                 conv1_src_desc, conv1_weights_desc, conv1_bias_desc, conv1_dst_desc_ref,
238                 { cd.conv1_strh, cd.conv1_strw }, { 0, 0 },
239                 { cd.conv1_padh, cd.conv1_padw }, { cd.conv1_padh, cd.conv1_padw }, padding_kind::zero);
240
241         auto conv1_dst_ref = memory({conv1_dst_desc_ref, eng});
242         auto conv2_dst_ref = memory({conv2_dst_desc, eng});
243
244         auto conv1_depthwise_weights_data = is_int8 ? &conv1_depthwise_weights[0] : nullptr;
245         auto conv2_depthwise_weights_data = is_int8 ? &conv2_depthwise_weights[0] : nullptr;
246
247         compute_ref_conv_fwd<data_t_src, data_t_wei, data_t_acc, data_t_dst>(conv1_desc_ref.data,
248                 conv1_src, conv1_weights, conv1_bias, conv1_dst_ref, true, 0.0f, conv1_depthwise_weights_data);
249         compute_ref_conv_fwd<data_t_dst, data_t_wei, data_t_acc, data_t_dst>(conv2_desc.data,
250                 conv1_dst_ref, conv2_weights, conv2_bias, conv2_dst_ref, true, 0.0f, conv2_depthwise_weights_data);
251
252         compare_data<data_t_dst>(conv2_dst_ref, conv2_dst);
253     }
254 };
255
256 }