Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / inference_engine / ie_cnn_layer_builder.h
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #pragma once
6
7 #include <details/caseless.hpp>
8 #include <ie_network.hpp>
9 #include <ie_builders.hpp>
10 #include <ie_layers.h>
11 #include <ie_blob.h>
12 #include <memory>
13 #include <string>
14 #include <vector>
15 #include <map>
16
17 namespace InferenceEngine {
18
19 namespace Builder {
20
21 template<class T>
22 inline std::string convertParameter2String(const Parameter& parameter) {
23     if (parameter.is<std::vector<T>>()) {
24         std::vector<T> params = parameter.as<std::vector<T>>();
25         std::string result;
26         for (const auto& param : params) {
27             if (!result.empty())
28                 result += ",";
29             result += convertParameter2String<T>(param);
30         }
31         return result;
32     }
33     return std::to_string(parameter.as<T>());
34 }
35 template<>
36 inline std::string convertParameter2String<std::string>(const Parameter& parameter) {
37     return parameter.as<std::string>();
38 }
39
40 std::map<std::string, std::string> convertParameters2Strings(const std::map<std::string, Parameter>& parameters);
41 Layer builderFromCNNLayer(const CNNLayerPtr& cnnLayer);
42
43 struct ConvertersHolder {
44     details::caseless_map<std::string, std::function<void(const CNNLayerPtr& cnnLayer, Layer&)>> converters;
45 };
46
47 /**
48  * @brief This class registers layer validators
49  */
50 class ConverterRegister {
51 public:
52     /**
53      * @brief The constructor registers new layer validator
54      * @param type Layer type
55      * @param validator Layer validator
56      */
57     explicit ConverterRegister(const std::string& type, const std::function<void(const CNNLayerPtr&, Layer&)>& converter);
58
59     static void convert(const CNNLayerPtr& cnnLayer, Layer& layer) {
60         if (getConvertersHolder().converters.find(layer.getType()) != getConvertersHolder().converters.end())
61             getConvertersHolder().converters[layer.getType()](cnnLayer, layer);
62     }
63
64 private:
65     static ConvertersHolder& getConvertersHolder();
66 };
67
68 #define REG_CONVERTER_FOR(__type, __converter) \
69 static InferenceEngine::Builder::ConverterRegister _reg_converter_##__type(#__type, __converter)
70
71 class BaseConverter {
72 public:
73     explicit BaseConverter(const std::string& type): type(type) {}
74
75     virtual CNNLayer::Ptr createLayer(const std::shared_ptr<const ILayer>& layer, Precision precision) = 0;
76     virtual bool canCreate(const std::string& nodeType) const = 0;
77
78 protected:
79     std::string type;
80 };
81
82 template <class CLT>
83 class LayerConverter: public BaseConverter {
84 public:
85     explicit LayerConverter(const std::string& type): BaseConverter(type) {}
86
87     CNNLayer::Ptr createLayer(const std::shared_ptr<const ILayer>& layer, Precision precision) override {
88         LayerParams params = {layer->getName(), layer->getType(), precision};
89         auto res = std::make_shared<CLT>(params);
90
91         auto * weightLayerPtr = dynamic_cast<WeightableLayer *>(res.get());
92
93         for (const auto& port : layer->getInputPorts()) {
94             if (port.getParameters().find("type") == port.getParameters().end() ||
95                     port.getData()->getData()->cbuffer() == nullptr)
96                 continue;
97             res->blobs[port.getParameters().at("type")] = port.getData()->getData();
98             if (weightLayerPtr == nullptr)
99                 continue;
100             if (port.getParameters().at("type").as<std::string>() == "weights") {
101                 weightLayerPtr->_weights = port.getData()->getData();
102             } else if (port.getParameters().at("type").as<std::string>() == "biases") {
103                 weightLayerPtr->_biases = port.getData()->getData();
104             }
105         }
106
107         // For constant layers
108         for (auto& it : layer->getParameters()) {
109             if (it.second.is<Blob::CPtr>()) {
110                 res->blobs[it.first] = std::const_pointer_cast<Blob>(it.second.as<Blob::CPtr>());
111             } else if (it.second.is<Blob::Ptr>()) {
112                 res->blobs[it.first] = it.second.as<Blob::Ptr>();
113             }
114         }
115
116         res->params = convertParameters2Strings(layer->getParameters());
117         return res;
118     }
119
120     bool canCreate(const std::string& nodeType) const override {
121         details::CaselessEq<std::string> comparator;
122         return comparator(nodeType, type);
123     }
124 };
125
126 class ActivationConverter: public BaseConverter {
127 public:
128     ActivationConverter(): BaseConverter("Activation") {}
129
130     CNNLayer::Ptr createLayer(const std::shared_ptr<const ILayer>& layer, Precision precision) override {
131         LayerParams params = {layer->getName(), layer->getType(), precision};
132         static details::caseless_map<std::string, std::shared_ptr<BaseConverter>> activationCreators = {
133                 {"relu", std::make_shared<LayerConverter<InferenceEngine::ReLULayer>>("ReLU")},
134                 {"prelu", std::make_shared<LayerConverter<InferenceEngine::PReLULayer>>("PReLU")},
135                 {"clamp", std::make_shared<LayerConverter<InferenceEngine::ClampLayer>>("Clamp")},
136                 {"elu", std::make_shared<LayerConverter<InferenceEngine::CNNLayer>>("ELU")},
137                 {"sigmoid", std::make_shared<LayerConverter<InferenceEngine::CNNLayer>>("Sigmoid")},
138                 {"tanh", std::make_shared<LayerConverter<InferenceEngine::CNNLayer>>("TanH")},
139         };
140
141         auto typeIt = layer->getParameters().find("type");
142         if (typeIt == layer->getParameters().end())
143             THROW_IE_EXCEPTION << "Unsupported Activation layer. Type is unknown.";
144
145         auto activationBuilder = activationCreators.find(typeIt->second);
146         if (activationBuilder == activationCreators.end()) {
147             THROW_IE_EXCEPTION << "Unsupported Activation layer type: " << typeIt->second.as<std::string>();
148         }
149
150         auto activation = activationBuilder->second->createLayer(layer, precision);
151
152         activation->type = activationBuilder->first;
153         activation->params.erase("type");
154         activation->validateLayer();
155         return activation;
156     }
157
158     bool canCreate(const std::string& nodeType) const override {
159         details::CaselessEq<std::string> comparator;
160         return comparator(nodeType, type);
161     }
162 };
163
164 class RNNSequenceConverter: public BaseConverter {
165 public:
166     RNNSequenceConverter(): BaseConverter("RNN") {}
167
168     CNNLayer::Ptr createLayer(const std::shared_ptr<const ILayer>& layer, Precision precision) override {
169         auto rnnLayer = LayerConverter<InferenceEngine::RNNSequenceLayer>("RNN").createLayer(layer, precision);
170         rnnLayer->type = "RNN";
171         std::string type = layer->getType();
172         size_t pos = type.find("Sequence");
173         if (pos != std::string::npos)
174             type.erase(pos);
175         rnnLayer->params["cell_type"] = type;
176         return rnnLayer;
177     }
178
179     bool canCreate(const std::string& nodeType) const override {
180         static const details::caseless_set<std::string> supportedRnnTypes {
181             "LSTMSequence", "GRUSequence", "RNNSequence"
182         };
183         return supportedRnnTypes.find(nodeType) != supportedRnnTypes.end();
184     }
185 };
186
187 }  // namespace Builder
188 }  // namespace InferenceEngine