1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
8 #include <gtest/gtest.h>
9 #include "xml_father.hpp"
10 #include "cnn_network_impl.hpp"
11 #include <tests_common.hpp>
12 #include "ie_format_parser.h"
14 #include "pugixml.hpp"
15 #include "xml_parse_utils.h"
16 #include "mean_image.h"
17 #include "ie_blob_proxy.hpp"
19 class FormatParserTest : public TestsCommon {
25 const char kPathSeparator =
26 #if defined _WIN32 || defined __CYGWIN__
31 const std::string parentDir = std::string("..") + std::to_string(FormatParserTest::kPathSeparator);
33 std::string getParentDir(std::string currentFile) const {
34 return parentDir + currentFile;
38 InferenceEngine::details::CNNNetworkImplPtr net;
39 ModelsPath _path_to_models;
41 InferenceEngine::InputInfo::Ptr getFirstInput() const {
42 return ::getFirstInput(net.get());
44 template <class LayerType>
45 std::shared_ptr<LayerType> getLayer(const std::string & name) const {
46 InferenceEngine::CNNLayerPtr ptr;
47 net->getLayerByName(name.c_str(), ptr, nullptr);
48 return std::dynamic_pointer_cast<LayerType>(ptr);
52 virtual void SetUp() {
53 _path_to_models += kPathSeparator;
56 void assertParseFail(const std::string& fileContent) {
59 FAIL() << "Parser didn't throw";
60 } catch (const std::exception& ex) {
61 SUCCEED() << ex.what();
65 void assertParseSucceed(const std::string& fileContent) {
66 ASSERT_NO_THROW(parse(fileContent));
69 void assertSetWeightsFail(const InferenceEngine::TBlob<uint8_t>::Ptr& binBlob) {
71 parser->SetWeights(binBlob);
72 FAIL() << "Parser didn't throw";
73 } catch (const std::exception& ex) {
74 SUCCEED() << ex.what();
78 void assertSetWeightsSucceed(const InferenceEngine::TBlob<uint8_t>::Ptr& binBlob) {
79 ASSERT_NO_THROW(parser->SetWeights(binBlob));
82 void parse(const std::string& fileContent) {
83 // check which version it is...
84 pugi::xml_document xmlDoc;
85 auto res = xmlDoc.load_string(fileContent.c_str());
87 EXPECT_EQ(pugi::status_ok, res.status) << res.description() << " at offset " << res.offset;
90 pugi::xml_node root = xmlDoc.document_element();
92 int version = XMLParseUtils::GetIntAttr(root, "version", 2);
93 if (version < 2) THROW_IE_EXCEPTION << "Deprecated IR's versions: " << version;
94 if (version > 3) THROW_IE_EXCEPTION << "cannot parse future versions: " << version;
95 parser.reset(new InferenceEngine::details::FormatParser(version));
97 net = parser->Parse(root);
100 #define initlayerIn(name, id, portid) \
101 node("layer").attr("type", "Power").attr("name", name).attr("id", id)\
102 .node("power_data").attr("power", 1).attr("scale", 1).attr("shift", 0).close()\
104 .node("port").attr("id", portid)\
105 .node("dim", MT_CHANNELS)\
106 .node("dim", MT_HEIGHT)\
107 .node("dim", MT_WIDTH)\
112 #define initlayerInV2(name, id, portid) \
113 node("layer").attr("type", "Power").attr("name", name).attr("id", id)\
114 .node("power_data").attr("power", 1).attr("scale", 1).attr("shift", 0).close()\
116 .node("port").attr("id", portid)\
117 .node("dim", MT_BATCH)\
118 .node("dim", MT_CHANNELS)\
119 .node("dim", MT_HEIGHT)\
120 .node("dim", MT_WIDTH)\
125 #define initInputlayer(name, id, portid) \
126 node("layer").attr("type", "Input").attr("name", name).attr("id", id)\
128 .node("port").attr("id", portid)\
129 .node("dim", MT_BATCH)\
130 .node("dim", MT_CHANNELS)\
131 .node("dim", MT_HEIGHT)\
132 .node("dim", MT_WIDTH)\
137 #define initInputlayer5D(name, id, portid) \
138 node("layer").attr("type", "Input").attr("name", name).attr("id", id)\
140 .node("port").attr("id", portid)\
141 .node("dim", MT_BATCH)\
142 .node("dim", MT_CHANNELS)\
143 .node("dim", MT_DEPTH)\
144 .node("dim", MT_HEIGHT)\
145 .node("dim", MT_WIDTH)\
150 #define initPowerlayerInOutV2(name, id, portid, outputid) \
151 node("layer").attr("type", "Power").attr("name", name).attr("id", id)\
152 .node("power_data").attr("power", 1).attr("scale", 1).attr("shift", 0).close()\
154 .node("port").attr("id", portid)\
155 .node("dim", MT_BATCH)\
156 .node("dim", MT_CHANNELS)\
157 .node("dim", MT_HEIGHT)\
158 .node("dim", MT_WIDTH)\
162 .node("port").attr("id", outputid)\
163 .node("dim", MT_BATCH)\
164 .node("dim", MT_CHANNELS)\
165 .node("dim", MT_HEIGHT)\
166 .node("dim", MT_WIDTH)\
172 #define initPowerlayerInOut(name, id, portid, outputid) \
173 node("layer").attr("type", "Power").attr("name", name).attr("id", id)\
174 .node("power_data").attr("power", 1).attr("scale", 1).attr("shift", 0).close()\
176 .node("port").attr("id", portid)\
177 .node("dim", MT_CHANNELS)\
178 .node("dim", MT_HEIGHT)\
179 .node("dim", MT_WIDTH)\
183 .node("port").attr("id", outputid)\
184 .node("dim", MT_CHANNELS)\
185 .node("dim", MT_HEIGHT)\
186 .node("dim", MT_WIDTH)\
191 #define initlayerInOut(name, type, id, portid, outputid) \
192 node("layer").attr("type", type).attr("name", name).attr("id", id)\
194 .node("port").attr("id", portid)\
195 .node("dim", MT_BATCH)\
196 .node("dim", MT_CHANNELS)\
197 .node("dim", MT_HEIGHT)\
198 .node("dim", MT_WIDTH)\
202 .node("port").attr("id", outputid)\
203 .node("dim", MT_BATCH)\
204 .node("dim", MT_CHANNELS)\
205 .node("dim", MT_HEIGHT)\
206 .node("dim", MT_WIDTH)\
211 #define initConv5DlayerInOut(name, id, group, output, kernel, pads_begin, pads_end, strides, dilations, inputid, outputid) \
212 node("layer").attr("type", "Convolution").attr("name", name).attr("id", id)\
213 .node("data").attr("group", group).attr("output", output).attr("kernel", kernel).attr("pads_begin", pads_begin).attr("pads_end", pads_end).attr("strides", strides).attr("dilations", dilations).close()\
215 .node("port").attr("id", inputid)\
216 .node("dim", MT_BATCH)\
217 .node("dim", MT_CHANNELS)\
218 .node("dim", MT_DEPTH)\
219 .node("dim", MT_HEIGHT)\
220 .node("dim", MT_WIDTH)\
224 .node("port").attr("id", outputid)\
225 .node("dim", MT_BATCH)\
226 .node("dim", MT_CHANNELS)\
227 .node("dim", MT_DEPTH)\
228 .node("dim", MT_HEIGHT)\
229 .node("dim", MT_WIDTH)\
234 #define initedge(fl, fp, tl, tp)\
235 node("edge").attr("from-layer", fl).attr("from-port", fp).attr("to-layer", tl).attr("to-port", tp).close()
238 auto net(const string & name1) const -> decltype(XMLFather().node("net").attr("name", name1).initlayers().initedges()) {
239 return XMLFather().node("net").attr("name", name1).initlayers().initedges();
242 #define MAKE_ALEXNET_FOR_MEAN_TESTS()\
243 xml().node("net").attr("name", "AlexNet")\
244 .node("input").attr("name", "data")\
245 .node("dim", MT_CHANNELS)\
246 .node("dim", MT_HEIGHT)\
247 .node("dim", MT_WIDTH)\
249 .initPowerlayerInOut("power", 0, 0, 1)\
250 .initlayerIn("power", 1, 0)\
253 .newnode("pre-process")
255 #define MAKE_ALEXNET_FOR_MEAN_TESTS_V2()\
256 xml().node("net").attr("name", "AlexNet").attr("version", 2)\
258 .initInputlayer("data", 0, 0)\
259 .initPowerlayerInOutV2("power1", 1, 1, 2)\
260 .initlayerInV2("power2", 2, 3)\
264 .newnode("pre-process")
270 #define BEGIN_NET_V3()\
273 #define BEGIN_NET_V2()\
276 #define _BEGIN_NET(x)\
277 xml().node("net").attr("name", "AlexNet").attr("version", x)\
279 .initInputlayer("data", 0, 0)\
289 InferenceEngine::TBlob<uint8_t>::Ptr makeBinBlobForMeanTest() {
290 typename InferenceEngine::TBlob<T>::Ptr binBlobFloat(new InferenceEngine::TBlob<T>(InferenceEngine::Precision::FP32, InferenceEngine::CHW, { MT_HEIGHT, MT_WIDTH, MT_CHANNELS }));
291 binBlobFloat->allocate();
292 binBlobFloat->set(MeanImage<T>::getValue());
293 InferenceEngine::SizeVector dims_dst = { MT_HEIGHT, MT_WIDTH * sizeof(T), MT_CHANNELS };
294 typename InferenceEngine::TBlobProxy<uint8_t>::Ptr binBlob(new InferenceEngine::TBlobProxy<uint8_t>(InferenceEngine::Precision::FP32, InferenceEngine::CHW, binBlobFloat, 0, dims_dst));
299 void assertMeanImagePerChannelCorrect() {
300 std::vector<T> meanImage = MeanImage<T>::getValue();
301 auto & pp = getFirstInput()->getPreProcess();
302 ASSERT_EQ(MT_CHANNELS, pp.getNumberOfChannels());
303 for (unsigned channel = 0, globalPixel = 0; channel < MT_CHANNELS; channel++) {
304 auto actualMeanChannel = std::dynamic_pointer_cast<InferenceEngine::TBlob<T> >(pp[channel]->meanData);
305 ASSERT_EQ(MT_HEIGHT * MT_WIDTH, actualMeanChannel->size());
306 for (unsigned pixel = 0; pixel < actualMeanChannel->size(); pixel++, globalPixel++) {
307 ASSERT_FLOAT_EQ(meanImage[globalPixel], actualMeanChannel->readOnly()[pixel]);
313 void assertMeanImageCorrect() {
314 std::vector<T> meanImage = MeanImage<T>::getValue();
316 auto & pp = getFirstInput()->getPreProcess();
317 ASSERT_EQ(MT_CHANNELS, pp.getNumberOfChannels());
318 for (size_t c = 0; c < pp.getNumberOfChannels(); c++) {
319 auto actualMeanTBlob = std::dynamic_pointer_cast<InferenceEngine::TBlob<T> >(pp[c]->meanData);
320 ASSERT_EQ(MT_WIDTH, actualMeanTBlob->dims()[0]);
321 ASSERT_EQ(MT_HEIGHT, actualMeanTBlob->dims()[1]);
322 ASSERT_EQ(MT_WIDTH*MT_HEIGHT, actualMeanTBlob->size());
323 for (unsigned index = 0; index < actualMeanTBlob->size(); index++) {
324 ASSERT_FLOAT_EQ(meanImage[index+c*MT_WIDTH*MT_HEIGHT], actualMeanTBlob->readOnly()[index]);
329 testing::XMLFather xml() {
330 return testing::XMLFather();
333 std::shared_ptr<InferenceEngine::details::FormatParser> parser;
337 int getXmlVersion(pugi::xml_node& root) {
338 if (!root.child("InputData").empty()) return 2;
344 std::string getXmlPath(const std::string& filePath) {
345 std::string xmlPath = filePath;
346 const auto openFlags = std::ios_base::ate | std::ios_base::binary;
347 std::ifstream fp(xmlPath, openFlags);
348 //TODO: Dueto multi directory build systems, and single directory build system
349 //, it is usualy a problem to deal with relative paths.
351 fp.open(getParentDir(xmlPath), openFlags);
352 EXPECT_TRUE(fp.is_open())
353 << "cannot open file " << xmlPath << " or " << getParentDir(xmlPath);
355 xmlPath = getParentDir(xmlPath);
360 std::string readFileContent(const std::string& filePath) {
362 const auto openFlags = std::ios_base::ate | std::ios_base::binary;
363 std::ifstream fp(getXmlPath(filePath), openFlags);
364 EXPECT_TRUE(fp.is_open()) << "Cannot open file: " << filePath;
366 return std::string();
368 std::streamsize size = fp.tellg();
369 EXPECT_GE(size, 1) << "file is empty: " << filePath;
371 return std::string();
375 str.reserve((size_t)size);
376 fp.seekg(0, std::ios::beg);
378 str.assign((std::istreambuf_iterator<char>(fp)),
379 std::istreambuf_iterator<char>());