1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
5 #include "ie_layer_parsers.h"
6 #include "ie_cnn_net_reader_impl.h"
13 namespace InferenceEngine {
16 CNNLayer::Ptr ActivationLayerCreator::CreateLayer(pugi::xml_node& node, LayerParseParameters& layerParsePrms) {
17 pugi::xml_node dn = GetChild(node, { "data", "activation_data" }, false);
19 THROW_IE_EXCEPTION << "Activation layer has no data node";
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())) {
27 THROW_IE_EXCEPTION << "Activation layer has multiple types";
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")},
43 auto activationBuilder = activationCreators.find(type);
44 if (activationBuilder == activationCreators.end()) {
45 THROW_IE_EXCEPTION << "Unsupported Activation layer type: " << type;
48 auto activation = activationBuilder->second->CreateLayer(node, layerParsePrms);
50 activation->type = activationBuilder->first;
51 activation->params.erase("type");
56 /***********************************************************************************/
57 /******* Tensor Iterator parser **************************************************/
58 /***********************************************************************************/
60 using PortInf = std::pair<int, int>;
61 using PortSet = std::set<PortInf>;
62 using PortMap = std::map<PortInf, DataPtr>;
64 static PortSet allRequiredInputs(pugi::xml_node &ti) {
65 PortSet res; // duplicates are possible
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);
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);
80 static PortSet allRequiredOutputs(pugi::xml_node &ti) {
81 PortSet res; // duplicates are possible
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);
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);
96 /***********************************************************************************/
97 /******* Body Parser Helper ******************************************************/
98 /***********************************************************************************/
99 using WBlob = TBlob<uint8_t>::Ptr;
103 BodyParser(pugi::xml_node &net_node, int ir_version) :
104 body(net_node), parser(FormatParser(ir_version)) {}
106 void parse(PortSet in_request, PortSet out_request) {
107 auto net = parser.Parse(body);
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);
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;
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);
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";
135 void setWeights(const WBlob &weights) {
136 parser.SetWeights(weights);
139 const PortMap& getInsMap() const { return inputs; }
140 const PortMap& getOutsMap() const { return outputs; }
143 pugi::xml_node &body;
150 CNNLayer::Ptr TILayerCreator::CreateLayer(pugi::xml_node& node, LayerParseParameters& layerParsePrms) {
151 std::string ti_name = node.attribute("name").as_string();
153 auto body = node.child("body");
155 THROW_IE_EXCEPTION << "TensorIterator " << ti_name << " has no body";
157 auto all_inputs = allRequiredInputs(node);
158 auto all_outputs = allRequiredOutputs(node);
160 auto parser = std::make_shared<BodyParser>(body, layerParsePrms.underIRVersion);
161 parser->parse(all_inputs, all_outputs);
163 auto ins = parser->getInsMap();
164 auto outs = parser->getOutsMap();
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]);
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]);
180 // fill map external port to index
181 std::map<int, int> e2i;
184 FOREACH_CHILD(in, node.child("input"), "port") {
185 int id = GetIntAttr(in, "id");
189 FOREACH_CHILD(in, node.child("output"), "port") {
190 int id = GetIntAttr(in, "id");
191 e2i[id] = out_indx++;
195 std::vector<TensorIterator::PortMap> in_ports_maping, out_ports_maping, back_edges;
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");
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);
208 TensorIterator::PortMap res;
209 res.from = e2i[external_port_id];
210 res.to = p2i[{internal_layer_id, internal_port_id}];
213 res.part_size = part_size;
219 FOREACH_CHILD(pm, node.child("port_map"), "input") {
220 in_ports_maping.push_back(parse_rule(pm));
222 FOREACH_CHILD(pm, node.child("port_map"), "output") {
223 out_ports_maping.push_back(parse_rule(pm));
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");
232 back_edges.push_back({ p2i[{from_l, from_p}], p2i[{to_l, to_p}],
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);
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;
252 } // namespace details
253 } // namespace InferenceEngine