1 // Copyright (C) 2018 Intel Corporation
3 // SPDX-License-Identifier: Apache-2.0
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"
12 #include "test_graph.hpp"
14 #include "single_layer_common.hpp"
15 #include "tests_common.hpp"
17 using namespace ::testing;
19 using namespace mkldnn;
21 struct batchnorm_scaleshift_test_params {
29 // BatchNorm specific param
31 // ScaleShift specific param
36 MKLDNNPlugin::impl_desc_type selectedType;
37 std::vector<MKLDNNPlugin::impl_desc_type> preferTypes;
39 std::vector<std::function<void(MKLDNNPlugin::PrimitiveDescInfo)>> comp;
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];
50 const data_t *src_data = src.readOnly();
51 data_t *dst_data = dst.data();
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];
63 sqrt_variance = 1. / sqrt(v_variance + eps);
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
72 dst_data[idx] = (src_data[idx] - v_mean) * sqrt_variance;
74 dst_data[idx] = dst_data[idx] * scale + shift;
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">
84 <layer name="in1" type="Input" precision="FP32" id="0">
94 <layer name="batchNorm" id="1" type="BatchNormalization" precision="FP32">
95 <batch_norm_data epsilon="_EPSILON_" PrimitivesPriority="_IMPLS_"/>
97 <weights offset="0" size="_S1_" />
98 <biases offset="_S1_" size="_S1_" />
117 <layer name="scaleshift" id="2" type="ScaleShift" precision="FP32">
118 <scale_shift_data broadcast="_BROADCAST_" PrimitivesPriority="_IMPLS_"/>
120 <weights offset="_S2_" size="_S1_" />
121 <biases offset="_S3_" size="_S1_" />
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"/>
149 virtual void TearDown() {
152 std::string getModel(batchnorm_scaleshift_test_params p) {
153 std::string model = model_t;
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);
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);
168 for (const auto& preferType : p.preferTypes) {
171 impls += "cpu:" + MKLDNNGraphTestClass::getStrPrimitiveDescriptorType(preferType);
173 REPLACE_WITH_STR(model, "_IMPLS_", impls);
178 virtual void SetUp() {
180 TestsCommon::SetUp();
181 batchnorm_scaleshift_test_params p = ::testing::WithParamInterface<batchnorm_scaleshift_test_params>::GetParam();
182 std::string model = getModel(p);
184 InferenceEngine::CNNNetReader net_reader;
185 ASSERT_NO_THROW(net_reader.ReadNetwork(model.data(), model.length()));
187 InferenceEngine::TBlob<uint8_t> *weights = new InferenceEngine::TBlob<uint8_t>(InferenceEngine::Precision::U8, InferenceEngine::C, {p.in.c * 4 * sizeof(float)});
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++) {
196 InferenceEngine::TBlob<uint8_t>::Ptr weights_ptr = InferenceEngine::TBlob<uint8_t>::Ptr(weights);
197 net_reader.SetWeights(weights_ptr);
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));
209 ASSERT_NE(nullptr, nodes[i]->getSelectedPrimitiveDescriptor());
210 ASSERT_TRUE(nodes[i]->getSelectedPrimitiveDescriptor()->getImplementationType() | p.selectedType);
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>.";
221 fill_data(src->buffer(), src->size());
223 InferenceEngine::BlobMap srcs;
224 srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("in1", src));
226 InferenceEngine::OutputsDataMap out;
227 out = net_reader.getNetwork().getOutputsInfo();
228 InferenceEngine::BlobMap outputBlobs;
230 std::pair<std::string, InferenceEngine::DataPtr> item = *out.begin();
232 InferenceEngine::TBlob<float>::Ptr output;
233 output = InferenceEngine::make_shared_blob<float>(item.second->getTensorDesc());
235 outputBlobs[item.first] = output;
237 graph.Infer(srcs, outputBlobs);
239 InferenceEngine::TBlob<float> dst_ref(item.second->getTensorDesc());
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) {
250 TEST_P(MKLDNNGraphBatchNormScaleShiftTests, TestsBatchNormWithScaleShift) {}
252 INSTANTIATE_TEST_CASE_P(
253 TestsBatchNormWithScaleShift, MKLDNNGraphBatchNormScaleShiftTests,
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}}));
261 class MKLDNNGraphDynBatchBatchNormScaleShiftTests: public MKLDNNGraphBatchNormScaleShiftTests {
263 virtual void SetUp() {
265 TestsCommon::SetUp();
266 batchnorm_scaleshift_test_params p = ::testing::WithParamInterface<batchnorm_scaleshift_test_params>::GetParam();
267 std::string model = getModel(p);
272 InferenceEngine::CNNNetReader net_reader;
273 ASSERT_NO_THROW(net_reader.ReadNetwork(model.data(), model.length()));
275 InferenceEngine::TBlob<uint8_t> *weights = new InferenceEngine::TBlob<uint8_t>(InferenceEngine::Precision::U8, InferenceEngine::C, {p.in.c * 4 * sizeof(float)});
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++) {
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;
294 MKLDNNGraphTestClass graph;
295 graph.setProperty({{InferenceEngine::PluginConfigParams::KEY_DYN_BATCH_ENABLED, InferenceEngine::PluginConfigParams::YES}});
296 graph.CreateGraph(net_reader.getNetwork());
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>.";
305 fill_data(src->buffer(), src->size());
307 InferenceEngine::BlobMap srcs;
308 srcs.insert(std::pair<std::string, InferenceEngine::Blob::Ptr>("in1", src));
310 InferenceEngine::OutputsDataMap out;
311 out = net_reader.getNetwork().getOutputsInfo();
312 InferenceEngine::BlobMap outputBlobs;
314 std::pair<std::string, InferenceEngine::DataPtr> item = *out.begin();
316 InferenceEngine::TBlob<float>::Ptr output;
317 output = InferenceEngine::make_shared_blob<float>(item.second->getTensorDesc());
319 outputBlobs[item.first] = output;
321 auto checkScaleShift = [](const MKLDNNPlugin::MKLDNNNodePtr& node) {
322 return (node->getType() == MKLDNNPlugin::Depthwise && node->getCnnLayer()->type == "ScaleShift")
323 || node->getType() == MKLDNNPlugin::BatchNormalization;
326 graph.checkDynBatch(srcs, outputBlobs, MB, MB, checkScaleShift);
327 graph.checkDynBatch(srcs, outputBlobs, 1, MB, checkScaleShift);
328 } catch (const InferenceEngine::details::InferenceEngineException &e) {
334 TEST_P(MKLDNNGraphDynBatchBatchNormScaleShiftTests, TestsDynBatchBatchNormWithScaleShift) {}
336 INSTANTIATE_TEST_CASE_P(
337 TestsDynBatchBatchNormWithScaleShift, MKLDNNGraphDynBatchBatchNormScaleShiftTests,
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}}));