1 /*******************************************************************************
2 * Copyright 2018 Intel Corporation
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *******************************************************************************/
17 #include "mkldnn_test_common.hpp"
18 #include "gtest/gtest.h"
19 #include "math_utils.hpp"
22 using namespace mkldnn::impl::math;
26 template <typename data_t_src, typename data_t_wei,
27 typename data_t_acc, typename data_t_dst>
28 void compute_ref_conv_eltwise_fwd(const test_convolution_sizes_t &c,
29 const memory &src, const memory &weights, const memory &bias,
30 const memory &dst, bool w_bias, algorithm elt_alg,
31 float elt_alpha, float elt_beta)
33 data_t_src *src_data = (data_t_src *)src.get_data_handle();
34 data_t_wei *weights_data = (data_t_wei *)weights.get_data_handle();
36 = (data_t_dst *)(w_bias ? bias.get_data_handle() : nullptr);
37 data_t_dst *dst_data = (data_t_dst *)dst.get_data_handle();
39 const memory::desc src_d = src.get_primitive_desc().desc();
40 const memory::desc weights_d = weights.get_primitive_desc().desc();
41 const memory::desc dst_d = dst.get_primitive_desc().desc();
43 size_t padded_ic = src_d.data.layout_desc.blocking.padding_dims[1];
44 size_t padded_oc = dst_d.data.layout_desc.blocking.padding_dims[1];
46 size_t padded_ic_w = weights_d.data.format == mkldnn_OhIw8o4i ? weights_d.data.layout_desc.blocking.padding_dims[1] :
47 src_d.data.layout_desc.blocking.padding_dims[1];
48 size_t padded_oc_w = weights_d.data.format == mkldnn_OhIw8o4i ? weights_d.data.layout_desc.blocking.padding_dims[0] :
49 dst_d.data.layout_desc.blocking.padding_dims[1];
51 mkldnn::impl::parallel_nd(c.mb, c.ng, c.oc / c.ng, c.oh, c.ow,
52 [&](int n, int g, int oc, int oh, int ow) {
53 size_t oidx = n * padded_oc * c.oh * c.ow
54 + g * padded_oc / c.ng * c.oh * c.ow
55 + oc * c.oh * c.ow + oh * c.ow + ow;
57 size_t didx = map_index(dst_d, oidx);
58 dst_data[didx] = bias_data
59 ? bias_data[g * c.oc / c.ng + oc] : data_t_dst{0};
61 for (int ic = 0; ic < c.ic / c.ng; ic++)
62 for (int kh = 0; kh < c.kh; kh++)
63 for (int kw = 0; kw < c.kw; kw++)
65 int ih = oh * c.strh - c.padh + kh * (1 + c.dilh);
66 if (ih < 0 || ih >= c.ih) continue;
67 int iw = ow * c.strw - c.padw + kw * (1 + c.dilw);
68 if (iw < 0 || iw >= c.iw) continue;
70 size_t iidx = n * padded_ic * c.ih * c.iw
71 + g * padded_ic / c.ng * c.ih * c.iw
72 + ic * c.ih * c.iw + ih * c.iw + iw;
73 size_t widx = g * padded_oc_w / c.ng * padded_ic_w
75 + oc * padded_ic_w / c.ng * c.kh * c.kw
76 + ic * c.kh * c.kw + kh * c.kw + kw;
78 dst_data[didx] += src_data[map_index(src_d, iidx)]
79 * weights_data[map_index(weights_d, widx)];
82 auto &d = dst_data[didx];
84 case eltwise_relu: d = relu_fwd(d, elt_alpha); break;
85 case eltwise_tanh: d = tanh_fwd(d); break;
86 case eltwise_elu: d = elu_fwd(d, elt_alpha); break;
87 case eltwise_square: d = square_fwd(d); break;
88 case eltwise_abs: d = abs_fwd(d); break;
89 case eltwise_sqrt: d = sqrt_fwd(d); break;
90 case eltwise_linear: d = linear_fwd(d, elt_alpha, elt_beta); break;
91 case eltwise_bounded_relu: d = bounded_relu_fwd(d, elt_alpha); break;
92 case eltwise_soft_relu: d = soft_relu_fwd(d); break;
93 case eltwise_logistic: d = logistic_fwd(d); break;
94 case eltwise_clamp: d = clamp_fwd(d, elt_alpha, elt_beta); break;
95 case eltwise_exp: d = exp_fwd(d); break;
96 default: assert(!"unknown alg_kind");
102 template <typename data_t_src, typename data_t_wei,
103 typename data_t_acc, typename data_t_dst>
104 class convolution_eltwise_test
105 : public ::testing::TestWithParam<test_convolution_eltwise_params_t> {
107 virtual void SetUp() {
108 test_convolution_eltwise_params_t p
109 = ::testing::TestWithParam<
110 test_convolution_eltwise_params_t>::GetParam();
112 ASSERT_TRUE(p.engine_kind == engine::kind::cpu);
113 ASSERT_EQ(p.aalgorithm, convolution_direct);
114 auto eng = engine(p.engine_kind, 0);
115 float eltwise_alpha = p.eltwise_alpha;
116 float eltwise_beta = p.eltwise_beta;
118 memory::data_type data_type_src = data_traits<data_t_src>::data_type;
119 memory::data_type data_type_dst = data_traits<data_t_dst>::data_type;
120 memory::data_type data_type_wei = data_traits<data_t_wei>::data_type;
122 test_convolution_sizes_t cd = p.sizes;
124 auto c_src_desc = create_md({ cd.mb, cd.ic, cd.ih, cd.iw },
125 data_type_src, p.formats.src_format);
126 auto c_weights_desc = cd.ng > 1 ?
127 create_md({ cd.ng, cd.oc / cd.ng, cd.ic / cd.ng, cd.kh, cd.kw },
128 data_type_wei, p.formats.weights_format) :
129 create_md({ cd.oc, cd.ic, cd.kh, cd.kw },
130 data_type_wei, p.formats.weights_format);
131 auto c_dst_desc = create_md({ cd.mb, cd.oc, cd.oh, cd.ow },
132 data_type_dst, p.formats.dst_format);
134 auto c_src = memory({c_src_desc, eng});
135 auto c_weights = memory({c_weights_desc, eng});
136 auto c_dst = memory({c_dst_desc, eng});
138 auto dst_ref = memory({c_dst_desc, eng});
140 fill_data<data_t_src>(c_src.get_primitive_desc().get_size()
141 / sizeof(data_t_src), (data_t_src *)c_src.get_data_handle(),
142 data_t_src(0), data_t_src(1));
143 check_zero_tail<data_t_src>(1, c_src);
145 fill_data<data_t_wei>(
146 c_weights.get_primitive_desc().get_size()
147 / sizeof(data_t_wei),(data_t_wei *)c_weights.get_data_handle(),
148 data_t_wei(0), data_t_wei(1));
149 check_zero_tail<data_t_wei>(1, c_weights);
151 bool with_bias = p.formats.bias_format != memory::format::format_undef;
152 auto c_bias_desc = with_bias ?
153 create_md({ cd.oc }, data_type_dst, p.formats.bias_format) :
154 create_md({}, data_type_dst, p.formats.bias_format);
155 auto c_bias = memory({c_bias_desc, eng});
157 fill_data<data_t_dst>(
158 c_bias.get_primitive_desc().get_size() / sizeof(data_t_dst),
159 (data_t_dst *)c_bias.get_data_handle(), 1., true);
162 std::vector<ptrdiff_t> padR = { cd.padh, cd.padw };
163 for (int i = 0; i < 2; ++i) {
164 if ((cd.ih - ((cd.kh - 1) * (cd.dilh + 1) + 1) + cd.padh + padR[0])
165 / cd.strh + 1 != cd.oh)
167 if ((cd.iw - ((cd.kw - 1) * (cd.dilw + 1) + 1) + cd.padw + padR[1])
168 / cd.strw + 1 != cd.ow)
173 mkldnn::post_ops ops;
174 ops.append_eltwise(1.0, p.alg, p.eltwise_alpha, p.eltwise_beta);
176 mkldnn::primitive_attr attr;
177 attr.set_post_ops(ops);
179 auto conv_desc = with_bias
180 ? convolution_forward::desc(prop_kind::forward_scoring,
181 p.aalgorithm, c_src_desc, c_weights_desc, c_bias_desc,
182 c_dst_desc, { cd.strh, cd.strw }, { cd.dilh, cd.dilw },
183 { cd.padh, cd.padw }, padR, padding_kind::zero)
184 : convolution_forward::desc(prop_kind::forward_scoring,
185 p.aalgorithm, c_src_desc, c_weights_desc, c_dst_desc,
186 { cd.strh, cd.strw }, { cd.dilh, cd.dilw },
187 { cd.padh, cd.padw }, padR, padding_kind::zero);
189 auto conv_primitive_desc =
190 convolution_forward::primitive_desc(conv_desc, attr, eng);
192 auto conv = with_bias
193 ? convolution_forward(conv_primitive_desc,
194 c_src, c_weights, c_bias, c_dst)
195 : convolution_forward(conv_primitive_desc,
196 c_src, c_weights, c_dst);
197 std::vector<primitive> pipeline;
198 pipeline.push_back(conv);
200 stream(stream::kind::lazy).submit(pipeline).wait();
203 if (catch_expected_failures(test, p.expect_to_fail, p.expected_status))
206 compute_ref_conv_eltwise_fwd<data_t_src, data_t_wei, data_t_wei,
207 data_t_dst>(cd, c_src, c_weights, c_bias, dst_ref, with_bias,
208 p.alg, eltwise_alpha, eltwise_beta);
209 check_zero_tail<data_t_dst>(1, dst_ref);
211 compare_data<data_t_dst>(dst_ref, c_dst, 1e-2);
212 check_zero_tail<data_t_dst>(0, c_dst);