1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
7 #include "xml_father.hpp"
23 typedef std::vector<CropData> CropParams;
26 std::vector<std::vector<size_t>> inDims;
27 std::vector<std::vector<size_t>> outDims;
29 friend std::ostream& operator<<(std::ostream& os, InOutShapes const& inout) {
30 auto dumpVec = [](const std::vector<size_t>& vec) -> std::string {
31 if (vec.empty()) return "[]";
32 std::stringstream oss;
34 for (size_t i = 1; i < vec.size(); i++) oss << "," << vec[i];
39 for (size_t i = 0; i < inout.inDims.size(); i++) {
40 os << "input" << "[" << i << "]: " << dumpVec(inout.inDims[i]) << ", ";
42 for (size_t i = 0; i < inout.outDims.size(); i++) {
43 os << "output" << "[" << i << "]: " << dumpVec(inout.outDims[i]) << ", ";
50 struct get_recursion_level;
53 struct get_recursion_level<testing::Token<T>> : public get_recursion_level<T> {
54 static const int value = get_recursion_level<T>::value;
55 typedef testing::Token<T> type;
59 struct get_recursion_level<testing::Token<XMLFather>> {
60 static const int value = 1;
61 typedef testing::Token<XMLFather> type;
65 template<class T, int L = get_recursion_level<T>::value>
70 typedef testing::Token<typename TokenType<N - 1>::type> type;
75 typedef XMLFather type;
79 * @class Singletone that is responsible for generation unique indexes for layers and ports.
83 IDManager() = default;
84 // IDManager(IDManager const&) = delete;
85 void operator=(IDManager const&) = delete;
88 * @brief Returns new unique number for layer to be used in IR
90 size_t getNextLayerID();
93 * @brief Returns new unique number for port to be used in IR
95 size_t getNextPortID();
98 * @brief Reset numbers for layers and ports. It's convenient to always start new network from zero number.
108 * @class Contains basic information about layer that is used on IR creation
112 * @struct Contains basic information about port in terms of IR
114 struct LayerPortData {
116 std::vector<size_t> dims;
120 * @param _portID - unique port number
121 * @param _dims - shape of the port
123 LayerPortData(size_t _portID, std::vector<size_t> _dims) : portID(_portID), dims(std::move(_dims)) {}
126 size_t _currentInPort = 0;
127 size_t _currentOutPort = 0;
129 std::vector<LayerPortData> _inPortsID;
130 std::vector<LayerPortData> _outPortsID;
133 using Ptr = std::shared_ptr<LayerDesc>;
137 * @param type - string with type of the layer
138 * @param shapes - reference to the structure with input and output shapes
140 explicit LayerDesc(std::string type, InOutShapes& shapes, IDManager &id_manager);
143 * @brief Resets current input and output ports to iterate over all input and output ports
148 * @brief Returns basic information about next input port. It throws exception when current input post is the last.
149 * @return @LayerPortData
151 LayerPortData getNextInData();
154 * @brief Returns basic information about next output port. It throws exception when current output port is the last.
155 * @return @LayerPortData
157 LayerPortData getNextOutData();
160 * @brief Returns layer number
162 size_t getLayerID() const;
165 * @brief Returns layer number
167 std::string getLayerName() const;
170 * @brief Returns number of inputs
172 size_t getInputsSize() const;
175 * @brief Returns number of outputs
177 size_t getOutputsSize() const;
182 * @class Builder to add edges between layers in IR
185 testing::Token<testing::Token<XMLFather>>& nodeEdges;
186 std::vector<LayerDesc::Ptr> layersDesc;
191 * @param _nodeEdges - node with edges to add to
192 * @param _layersDesc - container with information about layers: id and dimensions of input/output ports, layer id
194 EdgesBuilder(typename testing::Token<testing::Token<XMLFather>>& _nodeEdges,
195 std::vector<LayerDesc::Ptr> _layersDesc) : nodeEdges(_nodeEdges), layersDesc(std::move(_layersDesc)) {
196 for (const auto& desc:layersDesc) {
197 desc->resetPortIDs();
202 * @brief Adds edge between 2 layers with layer1 and layer2 numbers.
203 * Current output port of layer1 is connected with current input port of layer2
205 EdgesBuilder& connect(size_t layer1, size_t layer2);
208 * @brief finalizes xml creation and returns its string representation
210 std::string finish();
214 template<int Version>
215 class XmlNetBuilder {
216 size_t layersNum = 0;
217 std::vector<LayerDesc::Ptr> layersDesc;
218 std::shared_ptr<XMLFather> root;
219 testing::Token<testing::Token<XMLFather>>& xml;
220 IDManager id_manager;
222 XmlNetBuilder(std::shared_ptr<XMLFather> _root,
223 typename testing::Token<testing::Token<XMLFather>>& _xml) : xml(_xml), root(_root) {};
226 static XmlNetBuilder buildNetworkWithOneInput(
227 std::string name = "AlexNet", std::vector<size_t> dims = {1, 3, 227, 227}, std::string precision = "Q78") {
228 std::shared_ptr<XMLFather> root = std::make_shared<XMLFather>();
229 auto &exp = root->node("net").attr("name", name).attr("precision", precision).attr("version", Version);
231 auto &expFinal = exp.node("input").attr("name", "data");
232 addDims(expFinal, dims);
233 return XmlNetBuilder(root, expFinal.close().node("layers"));
235 auto &expFinal = exp.attr("batch", 1);
236 return XmlNetBuilder(root, expFinal.node("layers")).addInputLayer(precision, dims);
240 static XmlNetBuilder buildBody() {
241 auto root = std::make_shared<XMLFather>(XMLFather::make_without_schema());
242 auto &exp = root->node("body");
243 return XmlNetBuilder(root, exp.node("layers"));
246 XmlNetBuilder& havingLayers() {
250 EdgesBuilder havingEdges() {
251 auto& exp = xml.close();
252 return EdgesBuilder(exp.node("edges"), layersDesc);
255 XmlNetBuilder& cropLayer(CropParams params, const InOutShapes& inout) {
256 std::map<std::string, std::string> generalParams;
257 for (CropData crop : params) {
258 generalParams["axis"] = std::to_string(crop.axis);
259 generalParams["offset"] = std::to_string(crop.offset);
260 generalParams["dim"] = std::to_string(crop.dim);
262 return addLayer("Crop", "", &generalParams, inout, 0, 0, "crop-data");
265 XmlNetBuilder& convolutionLayer(const std::string& precision, const InOutShapes& inout) {
266 std::map<std::string, std::string> params{
275 return addLayer("Convolution", precision, ¶ms, inout, 0, 0, "convolution_data");
278 XmlNetBuilder& poolingLayer(const InOutShapes& inout) {
279 std::map<std::string, std::string> params{
287 return addLayer("Pooling", "", ¶ms, inout, 0, 0, "pooling_data");
290 struct TIPortMap { int from_l, from_p, to_l, to_p, axis, stride, start, end; };
292 XmlNetBuilder& TILayer(InOutShapes inout,
294 std::vector<TIPortMap> inMap,
295 std::vector<TIPortMap> outMap,
296 std::vector<TIPortMap> backMap) {
297 auto builder = XMLFather::make_without_schema();
299 auto &ports = builder.node("port_map");
300 auto fill_port_map_info = [&] (std::string name, TIPortMap m) {
301 auto & exp = ports.node(name)
302 .attr("external_port_id", m.from_p)
303 .attr("internal_layer_id", m.to_l)
304 .attr("internal_port_id", m.to_p);
306 exp.attr("axis", m.axis).attr("stride", m.stride).attr("start", m.start).attr("end", m.end);
309 for (auto &m : inMap) fill_port_map_info("input", m);
310 for (auto &m : outMap) fill_port_map_info("output", m);
312 // BackEdge map section
313 auto &backedges = builder.node("back_edges");
314 for (auto &m : backMap) {
315 backedges.node("edge")
316 .attr("from-layer", m.from_l)
317 .attr("from-port", m.from_p)
318 .attr("to-layer", m.to_l)
319 .attr("to-port", m.to_p).close();
322 // Serialize all TI info
323 std::string content = builder;
326 return addLayer("TensorIterator", "FP32", nullptr, inout, 0,0, "data", content);
329 XmlNetBuilder& addLayer(const std::string& type,
330 const std::string& precision,
331 std::map<std::string, std::string>* params,
335 std::string layerDataName = "data",
336 std::string content = "") {
338 auto layerDesc = std::make_shared<LayerDesc>(type, inout, id_manager);
339 layersDesc.push_back(layerDesc);
341 auto& layer = xml.node("layer").attr("name", layerDesc->getLayerName()).attr("precision", precision)
342 .attr("type", type).attr("id", layerDesc->getLayerID());
343 if (params != nullptr) {
344 auto& data = layer.node(layerDataName);
345 for (auto& kv : *params) {
346 data = data.attr(kv.first, kv.second);
348 layer = data.close();
350 addPorts(layer, layerDesc);
351 if (weightsSize != 0) {
352 layer = layer.node("weights").attr("offset", 0).attr("size", weightsSize).close();
353 if (biasesSize != 0) {
354 layer = layer.node("biases").attr("offset", weightsSize).attr("size", biasesSize).close();
357 if (!content.empty())
358 layer.add_content(content);
363 XmlNetBuilder& addInputLayer(const std::string& precision, const std::vector<size_t>& out) {
365 inout.outDims.push_back(out);
366 return addLayer("Input", precision, nullptr, inout);
369 std::string finish(std::vector<std::pair<std::string, std::string>>* edges) {
370 auto& exp = xml.close();
371 auto& node_edges = exp.node("edges");
373 for (auto& kv : *edges) {
374 std::string from[] = {kv.first.substr(0, kv.first.find(',')),
375 kv.first.substr(kv.first.find(',') + 1, kv.first.length())};
376 std::string to[] = {kv.second.substr(0, kv.second.find(',')),
377 kv.second.substr(kv.second.find(',') + 1, kv.second.length())};
378 node_edges.node("edge").attr("from-layer", from[0]).attr("from-port", from[1])
379 .attr("to-layer", to[0]).attr("to-port", to[1]).close();
386 std::string finish(bool addInputPreProcess = true) {
387 auto& exp = xml.close();
389 if (addInputPreProcess) {
397 static void addDims(T& place, std::vector<size_t> dims) {
398 for (auto dim : dims) {
399 place.node("dim", dim);
404 void addPorts(T& layer, const LayerDesc::Ptr& layerDesc) {
405 layerDesc->resetPortIDs();
406 size_t numPorts = layerDesc->getInputsSize();
408 auto& node = layer.node("input");
409 for (size_t i = 0; i < numPorts; i++) {
410 auto inData = layerDesc->getNextInData();
411 addPortInfo(node, inData.portID, inData.dims);
415 numPorts = layerDesc->getOutputsSize();
417 auto& node = layer.node("output");
418 for (size_t i = 0; i < numPorts; i++) {
419 auto outData = layerDesc->getNextOutData();
420 addPortInfo(node, outData.portID, outData.dims);
427 static void addPortInfo(T& layer, size_t portNum, std::vector<size_t> dims) {
428 auto& place = layer.node("port").attr("id", portNum);
429 addDims(place, dims);
434 void addEdges(T& mainContent) {
435 size_t firstLayerNum = Version >= 2 ? 0 : 1;
436 if (layersNum <= firstLayerNum) {
439 auto& edges = mainContent.node("edges");
440 for (size_t i = 0; i < layersDesc.size(); i++) {
441 layersDesc[i]->resetPortIDs();
443 for (size_t i = firstLayerNum; i < layersDesc.size() - 1; i++) {
445 .attr("from-layer", layersDesc[i]->getLayerID())
446 .attr("from-port", layersDesc[i]->getNextOutData().portID)
447 .attr("to-layer", layersDesc[i + 1]->getLayerID())
448 .attr("to-port", layersDesc[i + 1]->getNextInData().portID).close();
454 void addPreProcess(T& mainContent) {
455 auto& preProcess = mainContent.node("pre-process");
457 preProcess.attr("reference-layer-name", layersDesc[0]->getLayerName());
463 typedef XmlNetBuilder<1> V1NetBuilder;
464 typedef XmlNetBuilder<2> V2NetBuilder;
466 } // namespace testing