Publishing R3
[platform/upstream/dldt.git] / inference-engine / tests / unit / engines / mkldnn / graph / layers / internal / graph_batchnorm_scaleshift_test.cpp
1 // Copyright (C) 2018 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5
6 #include <gtest/gtest.h>
7 #include <gmock/gmock-spec-builders.h>
8 #include <inference_engine/cnn_network_impl.hpp>
9 #include "mkldnn_plugin/mkldnn_graph.h"
10 #include "mock_mkldnn_primitive.hpp"
11
12 #include "test_graph.hpp"
13
14 #include "single_layer_common.hpp"
15 #include "tests_common.hpp"
16
17 using namespace ::testing;
18 using namespace std;
19 using namespace mkldnn;
20
21 struct batchnorm_scaleshift_test_params {
22     struct {
23         size_t n;
24         size_t c;
25         size_t h;
26         size_t w;
27     } in;
28
29     // BatchNorm specific param
30     double epsilon;
31     // ScaleShift specific param
32     int broadcast;
33
34     size_t num_prim_desc;
35
36     MKLDNNPlugin::impl_desc_type selectedType;
37     std::vector<MKLDNNPlugin::impl_desc_type> preferTypes;
38
39     std::vector<std::function<void(MKLDNNPlugin::PrimitiveDescInfo)>> comp;
40 };
41
42 template <typename data_t>
43 void ref_batchnorm4DWithScale(const InferenceEngine::TBlob<data_t> &src, const data_t *variance, const data_t *mean, const data_t *scaleShift,
44                               InferenceEngine::TBlob<data_t> &dst, double eps) {
45     size_t MB = src.dims()[0];
46     size_t IC = src.dims()[1];
47     size_t IH = src.dims()[2];
48     size_t IW = src.dims()[3];
49
50     const data_t *src_data = src.readOnly();
51     data_t *dst_data = dst.data();
52
53     const data_t *scale_data = scaleShift;
54     const data_t *shift_data = scaleShift + IC;
55 #   pragma omp parallel for schedule(static)
56     for (int c = 0; c < IC; ++c) {
57         data_t v_mean = mean[c];
58         data_t v_variance = variance[c];
59         data_t sqrt_variance = 0;
60         data_t scale = scale_data[c];
61         data_t shift = shift_data[c];
62
63         sqrt_variance = 1. / sqrt(v_variance + eps);
64
65         for (int n = 0; n < MB; ++n)
66             for (int h = 0; h < IH; ++h)
67                 for (int w = 0; w < IW; ++w) {
68                     size_t idx = n * IC * IH * IW
69                                  + c * IH * IW
70                                  + h * IW + w;
71                     // BatchNorm
72                     dst_data[idx] = (src_data[idx] - v_mean) * sqrt_variance;
73                     // ScaleShift
74                     dst_data[idx] = dst_data[idx] * scale + shift;
75                 }
76     }
77 }
78
79 class MKLDNNGraphBatchNormScaleShiftTests: public TestsCommon,
80                                      public WithParamInterface<batchnorm_scaleshift_test_params> {
81     std::string model_t = R"V0G0N(
82 <Net Name="BatchNorm_With_Scale_Fusion" version="2" precision="FP32" batch="1">
83     <layers>
84         <layer name="in1" type="Input" precision="FP32" id="0">
85             <output>
86                 <port id="0">
87                     <dim>_IN_</dim>
88                     <dim>_IC_</dim>
89                     <dim>_IH_</dim>
90                     <dim>_IW_</dim>
91                 </port>
92             </output>
93         </layer>
94         <layer name="batchNorm" id="1" type="BatchNormalization" precision="FP32">
95             <batch_norm_data epsilon="_EPSILON_" PrimitivesPriority="_IMPLS_"/>
96
97             <weights offset="0" size="_S1_" />
98             <biases offset="_S1_" size="_S1_" />
99
100             <input>
101                 <port id="1">
102                     <dim>_IN_</dim>
103                     <dim>_IC_</dim>
104                     <dim>_IH_</dim>
105                     <dim>_IW_</dim>
106                 </port>
107             </input>
108             <output>
109                 <port id="2">
110                     <dim>_IN_</dim>
111                     <dim>_IC_</dim>
112                     <dim>_IH_</dim>
113                     <dim>_IW_</dim>
114                 </port>
115             </output>
116         </layer>
117          <layer name="scaleshift" id="2" type="ScaleShift" precision="FP32">
118             <scale_shift_data broadcast="_BROADCAST_" PrimitivesPriority="_IMPLS_"/>
119
120             <weights offset="_S2_" size="_S1_" />
121             <biases offset="_S3_" size="_S1_" />
122
123             <input>
124                 <port id="3">
125                     <dim>_IN_</dim>
126                     <dim>_IC_</dim>
127                     <dim>_IH_</dim>
128                     <dim>_IW_</dim>
129                 </port>
130             </input>
131             <output>
132                 <port id="4">
133                     <dim>_IN_</dim>
134                     <dim>_IC_</dim>
135                     <dim>_IH_</dim>
136                     <dim>_IW_</dim>
137                 </port>
138             </output>
139         </layer>
140     </layers>
141     <edges>
142        <edge from-layer="0" from-port="0" to-layer="1" to-port="1"/>
143        <edge from-layer="1" from-port="2" to-layer="2" to-port="3"/>
144     </edges>
145 </Net>
146 )V0G0N";
147
148 protected:
149     virtual void TearDown() {
150     }
151
152     std::string getModel(batchnorm_scaleshift_test_params p) {
153         std::string model = model_t;
154
155         REPLACE_WITH_NUM(model, "_IW_", p.in.w);
156         REPLACE_WITH_NUM(model, "_IH_", p.in.h);
157         REPLACE_WITH_NUM(model, "_IC_", p.in.c);
158         REPLACE_WITH_NUM(model, "_IN_", p.in.n);
159         REPLACE_WITH_NUM(model, "_EPSILON_", p.epsilon);
160         REPLACE_WITH_NUM(model, "_BROADCAST_", p.broadcast);
161
162         size_t w_data_size = p.in.c * sizeof(float);
163         REPLACE_WITH_NUM(model, "_S1_", w_data_size);
164         REPLACE_WITH_NUM(model, "_S2_", 2*w_data_size);
165         REPLACE_WITH_NUM(model, "_S3_", 3*w_data_size);
166
167         std::string impls;
168         for (const auto& preferType : p.preferTypes) {
169             if (!impls.empty())
170                 impls += ",";
171             impls += "cpu:" + MKLDNNGraphTestClass::getStrPrimitiveDescriptorType(preferType);
172         }
173         REPLACE_WITH_STR(model, "_IMPLS_", impls);
174
175         return model;
176     }
177
178     virtual void SetUp() {
179         try {
180             TestsCommon::SetUp();
181             batchnorm_scaleshift_test_params p = ::testing::WithParamInterface<batchnorm_scaleshift_test_params>::GetParam();
182             std::string model = getModel(p);
183
184             InferenceEngine::CNNNetReader net_reader;
185             ASSERT_NO_THROW(net_reader.ReadNetwork(model.data(), model.length()));
186
187             InferenceEngine::TBlob<uint8_t> *weights = new InferenceEngine::TBlob<uint8_t>(InferenceEngine::Precision::U8, InferenceEngine::C, {p.in.c * 4 * sizeof(float)});
188             weights->allocate();
189             fill_data( weights->data().as<float*>(), weights->size() / sizeof(float));
190             float * data = weights->buffer();
191             for (size_t i = 0; i < weights->size() / sizeof(float); i++) {
192                 if (data[i] < 0) {
193                     data[i] *= -1;
194                 }
195             }
196             InferenceEngine::TBlob<uint8_t>::Ptr weights_ptr = InferenceEngine::TBlob<uint8_t>::Ptr(weights);
197             net_reader.SetWeights(weights_ptr);
198
199             MKLDNNGraphTestClass graph;
200             graph.CreateGraph(net_reader.getNetwork());
201             auto& nodes = graph.getNodes();
202             for (int i = 0; i < nodes.size(); i++) {
203                 if ((nodes[i]->getType() == MKLDNNPlugin::Depthwise && nodes[i]->getCnnLayer()->type == "ScaleShift")
204                     || nodes[i]->getType() == MKLDNNPlugin::BatchNormalization) {
205                     ASSERT_LE(p.num_prim_desc, nodes[i]->getSupportedPrimitiveDescriptors().size());
206                     for (size_t j = 0; j < p.num_prim_desc && j < p.comp.size(); j++) {
207                         p.comp.at(j)(nodes[i]->getSupportedPrimitiveDescriptors().at(j));
208                     }
209                     ASSERT_NE(nullptr, nodes[i]->getSelectedPrimitiveDescriptor());
210                     ASSERT_TRUE(nodes[i]->getSelectedPrimitiveDescriptor()->getImplementationType() | p.selectedType);
211                 }
212             }
213
214             InferenceEngine::SizeVector dims_src = {p.in.n, p.in.c, p.in.h, p.in.w};
215             InferenceEngine::Blob::Ptr src = InferenceEngine::make_shared_blob<float, const InferenceEngine::SizeVector>(InferenceEngine::Precision::FP32, InferenceEngine::NCHW, dims_src);
216             InferenceEngine::TBlob<float>* srcPtr = dynamic_cast<InferenceEngine::TBlob<float>*>(src.get());
217             if (srcPtr == nullptr)
218                 FAIL() << "Cannot cast blob to TBlob<float>.";
219
220             src->allocate();
221             fill_data(src->buffer(), src->size());
222
223             InferenceEngine::BlobMap srcs;
224             srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("in1", src));
225
226             InferenceEngine::OutputsDataMap out;
227             out = net_reader.getNetwork().getOutputsInfo();
228             InferenceEngine::BlobMap outputBlobs;
229
230             std::pair<std::string, InferenceEngine::DataPtr> item = *out.begin();
231
232             InferenceEngine::TBlob<float>::Ptr output;
233             output = InferenceEngine::make_shared_blob<float>(item.second->getTensorDesc());
234             output->allocate();
235             outputBlobs[item.first] = output;
236
237             graph.Infer(srcs, outputBlobs);
238
239             InferenceEngine::TBlob<float> dst_ref(item.second->getTensorDesc());
240             dst_ref.allocate();
241
242             ref_batchnorm4DWithScale(*srcPtr, (const float*) weights->buffer(), ((const float*) weights->buffer() + p.in.c), (const float*) weights->buffer() + p.in.c*2, dst_ref, p.epsilon);
243             compare(*output, dst_ref);
244         } catch (const InferenceEngine::details::InferenceEngineException &e) {
245             FAIL() << e.what();
246         }
247     }
248 };
249
250 TEST_P(MKLDNNGraphBatchNormScaleShiftTests, TestsBatchNormWithScaleShift) {}
251
252 INSTANTIATE_TEST_CASE_P(
253         TestsBatchNormWithScaleShift, MKLDNNGraphBatchNormScaleShiftTests,
254         ::testing::Values(
255                 batchnorm_scaleshift_test_params{{1, 32, 128, 256}, 1e-6, 2, 5, MKLDNNPlugin::impl_desc_type::jit},
256                 batchnorm_scaleshift_test_params{{4, 3, 227, 227}, 1e-6, 2, 5, MKLDNNPlugin::impl_desc_type::jit},
257                 batchnorm_scaleshift_test_params{{1, 32, 128, 256}, 1e-6, 2, 5, MKLDNNPlugin::impl_desc_type::ref, {MKLDNNPlugin::impl_desc_type::ref_any}},
258                 batchnorm_scaleshift_test_params{{4, 3, 227, 227}, 1e-6, 2, 5, MKLDNNPlugin::impl_desc_type::ref, {MKLDNNPlugin::impl_desc_type::ref_any}}));
259
260
261 class MKLDNNGraphDynBatchBatchNormScaleShiftTests: public MKLDNNGraphBatchNormScaleShiftTests {
262 protected:
263     virtual void SetUp() {
264         try {
265             TestsCommon::SetUp();
266             batchnorm_scaleshift_test_params p = ::testing::WithParamInterface<batchnorm_scaleshift_test_params>::GetParam();
267             std::string model = getModel(p);
268             size_t MB = p.in.n;
269             if (MB < 2)
270                 MB = 2;
271
272             InferenceEngine::CNNNetReader net_reader;
273             ASSERT_NO_THROW(net_reader.ReadNetwork(model.data(), model.length()));
274
275             InferenceEngine::TBlob<uint8_t> *weights = new InferenceEngine::TBlob<uint8_t>(InferenceEngine::Precision::U8, InferenceEngine::C, {p.in.c * 4 * sizeof(float)});
276             weights->allocate();
277             fill_data( weights->data().as<float*>(), weights->size() / sizeof(float));
278             float * data = weights->buffer();
279             for (size_t i = 0; i < weights->size() / sizeof(float); i++) {
280                 if (data[i] < 0) {
281                     data[i] *= -1;
282                 }
283             }
284             InferenceEngine::TBlob<uint8_t>::Ptr weights_ptr = InferenceEngine::TBlob<uint8_t>::Ptr(weights);
285             net_reader.SetWeights(weights_ptr);
286             InferenceEngine::CNNNetwork network = net_reader.getNetwork();
287             auto implNet = dynamic_cast<InferenceEngine::details::CNNNetworkImpl *>(&((InferenceEngine::ICNNNetwork&)network));
288             ASSERT_NE(nullptr, implNet) << "Failed to cast ICNNNetwork to CNNNetworkImpl";
289             InferenceEngine::ResponseDesc resp;
290             InferenceEngine::StatusCode sts  = implNet->setBatchSizeReshape(MB, &resp);
291             ASSERT_EQ((int)InferenceEngine::StatusCode::OK, sts) << resp.msg;
292
293
294             MKLDNNGraphTestClass graph;
295             graph.setProperty({{InferenceEngine::PluginConfigParams::KEY_DYN_BATCH_ENABLED, InferenceEngine::PluginConfigParams::YES}});
296             graph.CreateGraph(net_reader.getNetwork());
297
298             InferenceEngine::SizeVector dims_src = {MB, p.in.c, p.in.h, p.in.w};
299             InferenceEngine::Blob::Ptr src = InferenceEngine::make_shared_blob<float, const InferenceEngine::SizeVector>(InferenceEngine::Precision::FP32, InferenceEngine::NCHW, dims_src);
300             InferenceEngine::TBlob<float>* srcPtr = dynamic_cast<InferenceEngine::TBlob<float>*>(src.get());
301             if (srcPtr == nullptr)
302                 FAIL() << "Cannot cast blob to TBlob<float>.";
303
304             src->allocate();
305             fill_data(src->buffer(), src->size());
306
307             InferenceEngine::BlobMap srcs;
308             srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("in1", src));
309
310             InferenceEngine::OutputsDataMap out;
311             out = net_reader.getNetwork().getOutputsInfo();
312             InferenceEngine::BlobMap outputBlobs;
313
314             std::pair<std::string, InferenceEngine::DataPtr> item = *out.begin();
315
316             InferenceEngine::TBlob<float>::Ptr output;
317             output = InferenceEngine::make_shared_blob<float>(item.second->getTensorDesc());
318             output->allocate();
319             outputBlobs[item.first] = output;
320
321             auto checkScaleShift = [](const MKLDNNPlugin::MKLDNNNodePtr& node) {
322                 return (node->getType() == MKLDNNPlugin::Depthwise && node->getCnnLayer()->type == "ScaleShift")
323                        || node->getType() == MKLDNNPlugin::BatchNormalization;
324             };
325
326             graph.checkDynBatch(srcs, outputBlobs, MB, MB, checkScaleShift);
327             graph.checkDynBatch(srcs, outputBlobs, 1, MB, checkScaleShift);
328         } catch (const InferenceEngine::details::InferenceEngineException &e) {
329             FAIL() << e.what();
330         }
331     }
332 };
333
334 TEST_P(MKLDNNGraphDynBatchBatchNormScaleShiftTests, TestsDynBatchBatchNormWithScaleShift) {}
335
336 INSTANTIATE_TEST_CASE_P(
337         TestsDynBatchBatchNormWithScaleShift, MKLDNNGraphDynBatchBatchNormScaleShiftTests,
338         ::testing::Values(
339                 batchnorm_scaleshift_test_params{{1, 32, 128, 256}, 1e-6, 2, 5, MKLDNNPlugin::impl_desc_type::jit},
340                 batchnorm_scaleshift_test_params{{4, 3, 227, 227}, 1e-6, 2, 5, MKLDNNPlugin::impl_desc_type::jit},
341                 batchnorm_scaleshift_test_params{{1, 32, 128, 256}, 1e-6, 2, 5, MKLDNNPlugin::impl_desc_type::ref, {MKLDNNPlugin::impl_desc_type::ref_any}},
342                 batchnorm_scaleshift_test_params{{4, 3, 227, 227}, 1e-6, 2, 5, MKLDNNPlugin::impl_desc_type::ref, {MKLDNNPlugin::impl_desc_type::ref_any}}));