Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / inference_engine / ie_layer_parsers.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include "ie_layer_parsers.h"
6 #include "ie_cnn_net_reader_impl.h"
7
8 #include <string>
9 #include <utility>
10 #include <memory>
11 #include <set>
12
13 namespace InferenceEngine {
14 namespace details {
15
16 CNNLayer::Ptr ActivationLayerCreator::CreateLayer(pugi::xml_node& node, LayerParseParameters& layerParsePrms)  {
17     pugi::xml_node dn = GetChild(node, { "data", "activation_data" }, false);
18     if (dn.empty()) {
19         THROW_IE_EXCEPTION << "Activation layer has no data node";
20     }
21
22     std::string type;
23     for (auto ait = dn.attributes_begin(); ait != dn.attributes_end(); ++ait) {
24         pugi::xml_attribute attr = *ait;
25         if (CaselessEq<std::string>()("type", attr.name())) {
26             if (!type.empty()) {
27                 THROW_IE_EXCEPTION << "Activation layer has multiple types";
28             }
29             type = attr.value();
30         }
31     }
32
33     static caseless_map<std::string, std::shared_ptr<BaseCreator>> activationCreators = {
34         {"relu", std::make_shared<LayerCreator<ReLULayer>>("ReLU")},
35         {"relu6", std::make_shared<LayerCreator<ReLU6Layer>>("ReLU6")},
36         {"prelu", std::make_shared<LayerCreator<PReLULayer>>("PReLU")},
37         {"clamp", std::make_shared<LayerCreator<ClampLayer>>("Clamp")},
38         {"elu", std::make_shared<LayerCreator<CNNLayer>>("ELU")},
39         {"sigmoid", std::make_shared<LayerCreator<CNNLayer>>("Sigmoid")},
40         {"tanh", std::make_shared<LayerCreator<CNNLayer>>("TanH")},
41     };
42
43     auto activationBuilder = activationCreators.find(type);
44     if (activationBuilder == activationCreators.end()) {
45         THROW_IE_EXCEPTION << "Unsupported Activation layer type: " << type;
46     }
47
48     auto activation = activationBuilder->second->CreateLayer(node, layerParsePrms);
49
50     activation->type = activationBuilder->first;
51     activation->params.erase("type");
52
53     return activation;
54 }
55
56 /***********************************************************************************/
57 /*******  Tensor Iterator parser  **************************************************/
58 /***********************************************************************************/
59
60 using PortInf = std::pair<int, int>;
61 using PortSet = std::set<PortInf>;
62 using PortMap = std::map<PortInf, DataPtr>;
63
64 static PortSet allRequiredInputs(pugi::xml_node &ti) {
65     PortSet res;  // duplicates are possible
66
67     FOREACH_CHILD(p, ti.child("port_map"), "input") {
68         int internal_layer_id = GetIntAttr(p, "internal_layer_id");
69         int internal_port_id = GetIntAttr(p, "internal_port_id");
70         res.emplace(internal_layer_id, internal_port_id);
71     }
72     FOREACH_CHILD(ec, ti.child("back_edges"), "edge") {
73         int to_layer_id = GetIntAttr(ec, "to-layer");
74         int to_port_id = GetIntAttr(ec, "to-port");
75         res.emplace(to_layer_id, to_port_id);
76     }
77     return res;
78 }
79
80 static PortSet allRequiredOutputs(pugi::xml_node &ti) {
81     PortSet res;  // duplicates are possible
82
83     FOREACH_CHILD(p, ti.child("port_map"), "output") {
84         int internal_layer_id = GetIntAttr(p, "internal_layer_id");
85         int internal_port_id = GetIntAttr(p, "internal_port_id");
86         res.emplace(internal_layer_id, internal_port_id);
87     }
88     FOREACH_CHILD(edge, ti.child("back_edges"), "edge") {
89         int to_layer_id = GetIntAttr(edge, "from-layer");
90         int to_port_id = GetIntAttr(edge, "from-port");
91         res.emplace(to_layer_id, to_port_id);
92     }
93     return res;
94 }
95
96 /***********************************************************************************/
97 /*******  Body Parser Helper  ******************************************************/
98 /***********************************************************************************/
99 using WBlob = TBlob<uint8_t>::Ptr;
100
101 class BodyParser {
102 public:
103     BodyParser(pugi::xml_node &net_node, int ir_version) :
104         body(net_node), parser(FormatParser(ir_version)) {}
105
106     void parse(PortSet in_request, PortSet out_request) {
107         auto net = parser.Parse(body);
108
109         for (const auto &pi : in_request)
110             inputs[pi] = parser.GetDataBy(pi.first, pi.second);
111         for (const auto &pi : out_request)
112             outputs[pi] = parser.GetDataBy(pi.first, pi.second);
113
114         // Mark data as network output. Just for check
115         for (const auto &kvp : outputs) {
116             auto &data = kvp.second;
117             auto layer = data->creatorLayer.lock();
118             auto &outs = layer->outData;
119             auto o_idx = std::find(outs.begin(), outs.end(), data) - outs.begin();
120             auto sts = net->addOutput(layer->name, o_idx, nullptr);
121             IE_ASSERT(sts == OK) << "TI body. Cannot add output port for layer "
122                                  << layer->name << " port index " << o_idx;
123         }
124
125         // Verify that all input/output are in use
126         InputsDataMap in_info_map;
127         std::map<std::string, DataPtr> out_info_map;
128         net->getInputsInfo(in_info_map);
129         net->getOutputsInfo(out_info_map);
130
131         IE_ASSERT(in_info_map.size() == inputs.size())   << "TI body. There are unlinked inputs";
132         IE_ASSERT(out_info_map.size() == outputs.size()) << "TI body. There are unlinked outputs";
133     }
134
135     void setWeights(const WBlob &weights) {
136         parser.SetWeights(weights);
137     }
138
139     const PortMap& getInsMap()  const { return inputs;  }
140     const PortMap& getOutsMap() const { return outputs; }
141
142 private:
143     pugi::xml_node &body;
144     FormatParser parser;
145
146     PortMap inputs;
147     PortMap outputs;
148 };
149
150 CNNLayer::Ptr TILayerCreator::CreateLayer(pugi::xml_node& node, LayerParseParameters& layerParsePrms) {
151     std::string ti_name = node.attribute("name").as_string();
152
153     auto body = node.child("body");
154     if (body.empty())
155         THROW_IE_EXCEPTION << "TensorIterator " << ti_name << " has no body";
156
157     auto all_inputs = allRequiredInputs(node);
158     auto all_outputs = allRequiredOutputs(node);
159
160     auto parser = std::make_shared<BodyParser>(body, layerParsePrms.underIRVersion);
161     parser->parse(all_inputs, all_outputs);
162
163     auto ins = parser->getInsMap();
164     auto outs = parser->getOutsMap();
165
166     // fill in/outputs and map internal port to index
167     std::map<PortInf, int> p2i;
168     std::vector<DataPtr> inputs, outputs;
169     for (const auto &p : all_inputs) {
170         IE_ASSERT(ins.find(p) != ins.end());
171         p2i[p] = inputs.size();
172         inputs.push_back(ins[p]);
173     }
174     for (const auto &p : all_outputs) {
175         IE_ASSERT(outs.find(p) != outs.end());
176         p2i[p] = outputs.size();
177         outputs.push_back(outs[p]);
178     }
179
180     // fill map external port to index
181     std::map<int, int> e2i;
182     {
183         int in_indx = 0;
184         FOREACH_CHILD(in, node.child("input"), "port") {
185             int id = GetIntAttr(in, "id");
186             e2i[id] = in_indx++;
187         }
188         int out_indx = 0;
189         FOREACH_CHILD(in, node.child("output"), "port") {
190             int id = GetIntAttr(in, "id");
191             e2i[id] = out_indx++;
192         }
193     }
194
195     std::vector<TensorIterator::PortMap> in_ports_maping, out_ports_maping, back_edges;
196
197     auto parse_rule = [&] (pugi::xml_node &pm) {
198         int external_port_id  = GetIntAttr(pm, "external_port_id");
199         int internal_layer_id = GetIntAttr(pm, "internal_layer_id");
200         int internal_port_id  = GetIntAttr(pm, "internal_port_id");
201
202         int axis = GetIntAttr(pm, "axis", -1);
203         int stride = GetIntAttr(pm, "stride", 1);
204         int part_size = GetIntAttr(pm, "part_size", 1);
205         int start = GetIntAttr(pm, "start", 0);
206         int end = GetIntAttr(pm, "end", -1);
207
208         TensorIterator::PortMap res;
209         res.from = e2i[external_port_id];
210         res.to   = p2i[{internal_layer_id, internal_port_id}];
211         res.axis = axis;
212         res.stride    = stride;
213         res.part_size = part_size;
214         res.start     = start;
215         res.end       = end;
216         return res;
217     };
218
219     FOREACH_CHILD(pm, node.child("port_map"), "input") {
220         in_ports_maping.push_back(parse_rule(pm));
221     }
222     FOREACH_CHILD(pm, node.child("port_map"), "output") {
223         out_ports_maping.push_back(parse_rule(pm));
224     }
225
226     FOREACH_CHILD(ec, node.child("back_edges"), "edge") {
227         int from_l = GetIntAttr(ec, "from-layer");
228         int from_p = GetIntAttr(ec, "from-port");
229         int to_l = GetIntAttr(ec, "to-layer");
230         int to_p = GetIntAttr(ec, "to-port");
231
232         back_edges.push_back({ p2i[{from_l, from_p}], p2i[{to_l, to_p}],
233                                -1, 1, 0, -1, 1 });
234     }
235
236     // Hold parser as a shared_ptr into callback
237     // Will be called outside to set weight blobs
238     // for internal TI body layers
239     layerParsePrms.internalWeightSet = [=] (const WBlob &w) {
240         parser->setWeights(w);
241     };
242
243     auto res = std::make_shared<TensorIterator>(layerParsePrms.prms);
244     res->body.inputs = inputs;
245     res->body.outputs = outputs;
246     res->input_port_map = in_ports_maping;
247     res->output_port_map = out_ports_maping;
248     res->back_edges = back_edges;
249     return res;
250 }
251
252 }  // namespace details
253 }  // namespace InferenceEngine