1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include <gtest/gtest.h>
6 #include <gmock/gmock-spec-builders.h>
7 #include "mkldnn_plugin/mkldnn_graph.h"
9 #include "single_layer_common.hpp"
10 #include <mkldnn_plugin/mkldnn_extension_utils.h>
11 #include <mkldnn_plugin/mkldnn_extension_mngr.h>
12 #include "tests_common.hpp"
13 #include "../test_graph.hpp"
16 using namespace ::testing;
18 using namespace mkldnn;
20 class MKLDNNGraphOptimizationTests: public TestsCommon {};
22 TEST_F(MKLDNNGraphOptimizationTests, TestNoFuseConvSumWithOneInput) {
23 std::string model = R"V0G0N(
24 <net name="AlexNet" version="2" batch="1">
26 <layer name="data" type="Input" precision="FP32" id="0">
36 <layer name="conv1" type="Convolution" precision="FP32" id="1">
37 <convolution_data stride-x="1" stride-y="1" pad-x="0" pad-y="0" kernel-x="1" kernel-y="1" output="3" group="1"/>
54 <weights offset="0" size="36"/>
55 <biases offset="36" size="12"/>
57 <layer name="res2a" type="Eltwise" precision="FP32" id="2">
58 <elementwise_data operation="sum"/>
84 <edge from-layer="0" from-port="0" to-layer="1" to-port="1"/>
85 <edge from-layer="0" from-port="0" to-layer="2" to-port="3"/>
86 <edge from-layer="1" from-port="2" to-layer="2" to-port="4"/>
92 InferenceEngine::CNNNetReader net_reader;
93 ASSERT_NO_THROW(net_reader.ReadNetwork(model.data(), model.length()));
95 InferenceEngine::TBlob<uint8_t> *weights = new InferenceEngine::TBlob<uint8_t>(InferenceEngine::Precision::U8, InferenceEngine::C, {48});
97 float * data = weights->buffer();
99 fill_data((float *) weights->buffer(), weights->size() / sizeof(float));
101 InferenceEngine::TBlob<uint8_t>::Ptr weights_ptr = InferenceEngine::TBlob<uint8_t>::Ptr(weights);
103 net_reader.SetWeights(weights_ptr);
105 MKLDNNGraphTestClass graph;
106 ASSERT_NO_THROW(graph.CreateGraph(net_reader.getNetwork()));
109 auto& nodes = graph.getNodes();
110 for (auto &node : nodes) {
111 if (node->getType() == MKLDNNPlugin::Convolution) {
118 TEST_F(MKLDNNGraphOptimizationTests, TestNoCrashForFuseConvSumAndInput) {
119 std::string model = R"V0G0N(
120 <net name="AlexNet" version="2" batch="1">
122 <layer name="data" type="Input" precision="FP32" id="0">
132 <layer name="conv1" type="Convolution" precision="FP32" id="1">
133 <convolution_data stride-x="1" stride-y="1" pad-x="0" pad-y="0" kernel-x="1" kernel-y="1" output="3" group="1"/>
150 <weights offset="0" size="36"/>
151 <biases offset="36" size="12"/>
153 <layer name="relu1" type="ReLU" precision="FP32" id="2">
171 <layer name="res2a" type="Eltwise" precision="FP32" id="3">
172 <elementwise_data operation="sum"/>
198 <edge from-layer="0" from-port="0" to-layer="1" to-port="1"/>
199 <edge from-layer="0" from-port="0" to-layer="2" to-port="1"/>
200 <edge from-layer="1" from-port="2" to-layer="3" to-port="3"/>
201 <edge from-layer="2" from-port="2" to-layer="3" to-port="4"/>
207 InferenceEngine::CNNNetReader net_reader;
208 ASSERT_NO_THROW(net_reader.ReadNetwork(model.data(), model.length()));
210 InferenceEngine::TBlob<uint8_t> *weights = new InferenceEngine::TBlob<uint8_t>(InferenceEngine::Precision::U8, InferenceEngine::C, {48});
212 float * data = weights->buffer();
214 fill_data((float *) weights->buffer(), weights->size() / sizeof(float));
216 InferenceEngine::TBlob<uint8_t>::Ptr weights_ptr = InferenceEngine::TBlob<uint8_t>::Ptr(weights);
218 net_reader.SetWeights(weights_ptr);
220 MKLDNNGraphTestClass graph;
221 ASSERT_NO_THROW(graph.CreateGraph(net_reader.getNetwork()));
224 auto& nodes = graph.getNodes();
225 for (auto &node : nodes) {
226 if (node->getType() == MKLDNNPlugin::Convolution_Sum) {
233 namespace GraphOptimizationUtils {
235 using fake_ext_factory = std::function<InferenceEngine::ILayerImplFactory*(const InferenceEngine::CNNLayer *)>;
237 class FakeReLUImpl : public InferenceEngine::ILayerExecImpl {
239 FakeReLUImpl(const InferenceEngine::CNNLayer *layer) {
240 cnnLayer = const_cast<InferenceEngine::CNNLayer *>(layer);
242 InferenceEngine::StatusCode getSupportedConfigurations(std::vector<InferenceEngine::LayerConfig>& conf, InferenceEngine::ResponseDesc *resp) noexcept override {
243 InferenceEngine::LayerConfig config;
244 config.dynBatchSupport = 0;
245 if (cnnLayer->outData.size() != 1 && cnnLayer->insData.size() != 1)
246 return InferenceEngine::GENERAL_ERROR;
247 InferenceEngine::DataConfig cfg;
248 cfg.constant = false;
250 InferenceEngine::SizeVector order;
251 for(size_t i = 0; i < cnnLayer->outData[0]->getTensorDesc().getDims().size(); i++) {
254 cfg.desc = InferenceEngine::TensorDesc(cnnLayer->outData[0]->getTensorDesc().getPrecision(),
255 cnnLayer->outData[0]->getTensorDesc().getDims(),
256 {cnnLayer->outData[0]->getTensorDesc().getDims(), order});
257 config.outConfs.push_back(cfg);
258 config.inConfs.push_back(cfg);
259 conf.push_back(config);
260 return InferenceEngine::OK;
262 InferenceEngine::StatusCode init(InferenceEngine::LayerConfig& config, InferenceEngine::ResponseDesc *resp) noexcept override {
263 if (config.dynBatchSupport)
264 return InferenceEngine::NOT_IMPLEMENTED;
265 for(auto input : config.inConfs) {
267 return InferenceEngine::GENERAL_ERROR;
269 for(auto output : config.outConfs) {
271 return InferenceEngine::GENERAL_ERROR;
273 return InferenceEngine::OK;
275 InferenceEngine::StatusCode execute(std::vector<InferenceEngine::Blob::Ptr>& inputs, std::vector<InferenceEngine::Blob::Ptr>& outputs, InferenceEngine::ResponseDesc *resp) noexcept override {
276 const float *src_data = inputs[0]->buffer();
277 float *dst_data = outputs[0]->buffer();
278 if (src_data != dst_data)
279 return InferenceEngine::GENERAL_ERROR;
280 return InferenceEngine::OK;
284 InferenceEngine::CNNLayer* cnnLayer;
287 class FakeReLUFactory : public InferenceEngine::ILayerImplFactory {
289 FakeReLUFactory(const InferenceEngine::CNNLayer *layer) {
290 cnnLayer = const_cast<InferenceEngine::CNNLayer *>(layer);
292 // set output shapes by input shapes.
293 InferenceEngine::StatusCode getShapes(const std::vector<InferenceEngine::TensorDesc>& inShapes, std::vector<InferenceEngine::TensorDesc>& outShapes, InferenceEngine::ResponseDesc *resp) noexcept override {
294 outShapes.push_back(inShapes[0]);
295 return InferenceEngine::OK;
297 // First implementation has more priority than next
298 InferenceEngine::StatusCode getImplementations(std::vector<InferenceEngine::ILayerImpl::Ptr>& impls, InferenceEngine::ResponseDesc *resp) noexcept override {
299 impls.push_back(InferenceEngine::ILayerImpl::Ptr(new FakeReLUImpl(cnnLayer)));
300 return InferenceEngine::OK;
304 InferenceEngine::CNNLayer * cnnLayer;
307 class FakeFabric : public InferenceEngine::IExtension {
310 factories["ReLU"] = [](const InferenceEngine::CNNLayer * cnnLayer) -> InferenceEngine::ILayerImplFactory* { return new FakeReLUFactory(cnnLayer); };
313 virtual ~FakeFabric() {
317 void GetVersion(const InferenceEngine::Version *&versionInfo) const noexcept override {}
318 void SetLogCallback(InferenceEngine::IErrorListener &listener) noexcept override {}
319 void Unload() noexcept override {}
320 void Release() noexcept override {
323 InferenceEngine::StatusCode getPrimitiveTypes(char**& types, unsigned int& size, InferenceEngine::ResponseDesc* resp) noexcept override {
324 types = new char *[factories.size()];
326 for (auto it = factories.begin(); it != factories.end(); it++, count ++) {
327 types[count] = new char[it->first.size() + 1];
328 std::copy(it->first.begin(), it->first.end(), types[count]);
329 types[count][it->first.size() ] = '\0';
331 return InferenceEngine::OK;
333 InferenceEngine::StatusCode getFactoryFor(InferenceEngine::ILayerImplFactory *&factory,
334 const InferenceEngine::CNNLayer *cnnLayer,
335 InferenceEngine::ResponseDesc *resp) noexcept override {
336 if (factories.find(cnnLayer->type) == factories.end()) {
337 std::string errorMsg = std::string("Factory for ") + cnnLayer->type + " wasn't found!";
338 errorMsg.copy(resp->msg, sizeof(resp->msg) - 1);
339 return InferenceEngine::NOT_FOUND;
341 factory = factories[cnnLayer->type](cnnLayer);
342 return InferenceEngine::OK;
345 InferenceEngine::StatusCode getShapeInferImpl(InferenceEngine::IShapeInferImpl::Ptr& impl, const char* type,
346 InferenceEngine::ResponseDesc* resp) noexcept override {
347 return InferenceEngine::NOT_IMPLEMENTED;
351 std::map<std::string, fake_ext_factory> factories;
355 TEST_F(MKLDNNGraphOptimizationTests, TestNoFuseCustomActivation) {
356 std::string model = R"V0G0N(
357 <net name="AlexNet" version="2" batch="1">
359 <layer name="data" type="Input" precision="FP32" id="0">
369 <layer name="conv1" type="Convolution" precision="FP32" id="1">
370 <convolution_data stride-x="4" stride-y="4" pad-x="0" pad-y="0" kernel-x="11" kernel-y="11" output="96" group="1"/>
387 <weights offset="0" size="139392"/>
388 <biases offset="139392" size="384"/>
390 <layer name="relu1" type="ReLU" precision="FP32" id="2">
410 <edge from-layer="0" from-port="0" to-layer="1" to-port="1"/>
411 <edge from-layer="1" from-port="2" to-layer="2" to-port="3"/>
416 std::shared_ptr<InferenceEngine::IExtension> extension;
417 extension.reset(new GraphOptimizationUtils::FakeFabric());
418 MKLDNNPlugin::MKLDNNExtensionManager::Ptr extMgr(new MKLDNNPlugin::MKLDNNExtensionManager());
419 extMgr->AddExtension(extension);
421 InferenceEngine::CNNNetReader net_reader;
422 ASSERT_NO_THROW(net_reader.ReadNetwork(model.data(), model.length()));
424 InferenceEngine::TBlob<uint8_t> *weights = new InferenceEngine::TBlob<uint8_t>(InferenceEngine::Precision::U8, InferenceEngine::C, {139776});
426 float * data = weights->buffer();
428 fill_data((float *) weights->buffer(), weights->size() / sizeof(float));
430 InferenceEngine::TBlob<uint8_t>::Ptr weights_ptr = InferenceEngine::TBlob<uint8_t>::Ptr(weights);
432 net_reader.SetWeights(weights_ptr);
434 MKLDNNGraphTestClass graph;
435 ASSERT_NO_THROW(graph.CreateGraph(net_reader.getNetwork(), extMgr));
438 auto& nodes = graph.getNodes();
439 for (auto &node : nodes) {
440 if (node->getType() == MKLDNNPlugin::Convolution) {