Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / src / inference_engine / ie_utils.cpp
1 // Copyright (C) 2018-2019 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include "ie_util_internal.hpp"
6 #include "graph_tools.hpp"
7 #include "details/caseless.hpp"
8 #include "ie_utils.hpp"
9
10 #include <ie_layers.h>
11
12 #include <vector>
13 #include <unordered_set>
14 #include <unordered_map>
15 #include <functional>
16 #include <string>
17 #include <deque>
18 #include <cassert>
19 #include <memory>
20 #include <utility>
21 #include <iomanip>
22
23 using namespace InferenceEngine;
24 using namespace details;
25
26 namespace {
27
28 InferenceEngine::LayerComplexity getComplexity(const InferenceEngine::CNNLayerPtr &layer) {
29     using namespace InferenceEngine;
30     using namespace std::placeholders;
31     auto type = layer->type;
32     auto &outDims = layer->outData[0]->getDims();
33     auto &inDims = layer->insData[0].lock()->getDims();
34     unsigned long flops = 0, params = 0;
35
36     size_t out_size = accumulate(outDims.begin(), outDims.end(),
37         1u, std::multiplies<size_t>{});
38     size_t in_size = accumulate(inDims.begin(), inDims.end(),
39         1u, std::multiplies<size_t>{});
40
41     auto eltwise_complexity = [&](CNNLayer &l, size_t flops_rate, size_t params_rate) {
42         flops = flops_rate * out_size;
43         params = params_rate * out_size;
44     };
45
46     auto scale_complexity = [&](CNNLayer &l) {
47         flops = 2 * out_size;
48         params = 2 * outDims[1];
49     };
50     const caseless_unordered_map<std::string,
51                                  std::function<void(CNNLayer &)>> layerComplexityLookup = {
52         {"Convolution", [&](CNNLayer &l) {
53             auto* conv = dynamic_cast<ConvolutionLayer*>(&l);
54             unsigned long filter_m = conv->_kernel[X_AXIS] * conv->_kernel[Y_AXIS] * (inDims[1] / conv->_group);
55             flops = 2 * out_size * filter_m;
56             params = filter_m * conv->_out_depth + conv->_out_depth;
57         }},
58
59         {"Deconvolution", [&](CNNLayer &l) {
60             auto* deconv = dynamic_cast<DeconvolutionLayer*>(&l);
61             unsigned long filter_m = deconv->_kernel[X_AXIS] * deconv->_kernel[Y_AXIS] * (inDims[1] / deconv->_group);
62             flops = 2 * out_size * filter_m;
63             params = filter_m * deconv->_out_depth + deconv->_out_depth;
64         }},
65
66         {"FullyConnected", [&](CNNLayer &l) {
67             auto* fc = dynamic_cast<FullyConnectedLayer*>(&l);
68             flops = 2 * in_size * fc->_out_num;
69             params = (in_size + 1) * fc->_out_num;
70         }},
71
72         {"Norm", [&](CNNLayer &l) {
73             auto* lrn = dynamic_cast<NormLayer*>(&l);
74             int size = lrn->_size;
75             int flopsPerElement = lrn->_isAcrossMaps ? 2 * size * size : 2 * size;
76
77             flops = in_size * flopsPerElement;
78         }},
79
80         {"Pooling", [&](CNNLayer &l) {
81             auto* pool = dynamic_cast<PoolingLayer*>(&l);
82             if (pool->_type == PoolingLayer::PoolType::ROI) {
83                 // real kernel sizes are read from weights, so approximation is used.
84                 unsigned long kernel_w = inDims[2] / outDims[2];
85                 unsigned long kernel_h = inDims[3] / outDims[3];
86
87                 flops = out_size * kernel_h * kernel_w;
88             } else {
89                 flops = out_size * (pool->_kernel[Y_AXIS] * pool->_kernel[Y_AXIS]);
90             }
91         }},
92
93         {"Eltwise", [&](CNNLayer &l) {
94             auto* eltwise = dynamic_cast<EltwiseLayer*>(&l);
95             flops = in_size * (2 * eltwise->insData.size() - 1);
96         }},
97
98         {"Power", std::bind(eltwise_complexity, _1, 3, 0)},
99         {"Normalize", std::bind(eltwise_complexity, _1, 4, 0)},
100         {"ReLU", std::bind(eltwise_complexity, _1, 1, 0)},
101         {"Clamp", std::bind(eltwise_complexity, _1, 2, 0)},
102         {"BatchNormalization", scale_complexity},
103         {"ScaleShift", scale_complexity},
104
105         // roughly count exp as 1 flop
106         {"SoftMax", std::bind(eltwise_complexity, _1, 4, 0)},
107     };
108
109     if (layerComplexityLookup.count(type) > 0) {
110         layerComplexityLookup.at(type)(*layer);
111     }
112     return {flops, params};
113 }
114
115 }  // namespace
116
117 namespace InferenceEngine {
118
119 std::unordered_map<std::string,
120                    LayerComplexity> getNetworkComplexity(const InferenceEngine::ICNNNetwork &network) {
121     std::unordered_map<std::string, LayerComplexity> networkComplexity;
122     InferenceEngine::InputsDataMap networkInputs;
123     network.getInputsInfo(networkInputs);
124     if (networkInputs.empty()) {
125         THROW_IE_EXCEPTION << "No inputs detected.";
126     }
127
128     // Get all network inputs
129     CNNLayerSet inputs;
130     for (auto input : networkInputs) {
131         for (auto l : input.second->getInputData()->inputTo) {
132             inputs.insert(l.second);
133         }
134     }
135
136     CNNNetForestDFS(inputs, [&](InferenceEngine::CNNLayerPtr layer) {
137         networkComplexity.emplace(layer->name, getComplexity(layer));
138     }, false);
139     return networkComplexity;
140 }
141
142 }   // namespace InferenceEngine