935bdc065978789099b16ff3461685336ac386cf
[platform/upstream/opencv.git] / modules / dnn / src / int8layers / reduce_layer.cpp
1 // This file is part of OpenCV project.
2 // It is subject to the license terms in the LICENSE file found in the top-level directory
3 // of this distribution and at http://opencv.org/license.html.
4
5 #include "../precomp.hpp"
6 #include "layers_common.hpp"
7
8 #include <algorithm>
9 #include <stdlib.h>
10 #include <numeric>
11
12 namespace cv
13 {
14 namespace dnn
15 {
16
17 class ReduceLayerInt8Impl CV_FINAL : public ReduceLayerInt8
18 {
19 public:
20     ReduceLayerInt8Impl(const LayerParams& params)
21     {
22         // Set reduce type
23         CV_Assert(params.has("reduce"));
24         String typeString = toLowerCase(params.get<String>("reduce"));
25         if (typeString == "max")
26             reduceType = MAX;
27         else if (typeString == "min")
28             reduceType = MIN;
29         else
30             CV_Error(Error::StsBadArg, "Unknown reduce type \"" + typeString + "\"");
31
32         // Set deleted dims
33         CV_Assert(params.has("deleted_dims"));
34         DictValue tempDims = params.get("deleted_dims");
35         int i, n = tempDims.size();
36         reduceDims.resize(n);
37         for (i = 0; i < n; i++)
38         {
39             reduceDims[i] = tempDims.get<int>(i);
40         }
41     }
42
43     virtual bool supportBackend(int backendId) CV_OVERRIDE
44     {
45         if (backendId == DNN_BACKEND_OPENCV)
46         {
47             return true;
48         }
49         return false;
50     }
51
52     // reduceType == MIN
53     struct ReduceOpMIN
54     {
55         int8_t apply(const int8_t* first, const int8_t* last)
56         {
57             return std::accumulate(first, last, *first,
58                                    [](int8_t a, int8_t b)
59                                    {
60                                        return std::min(a, b);
61                                    });
62         }
63     };
64
65     // reduceType == MAX
66     struct ReduceOpMAX
67     {
68         int8_t apply(const int8_t* first, const int8_t* last)
69         {
70             return std::accumulate(first, last, *first,
71                                    [](int8_t a, int8_t b)
72                                    {
73                                        return std::max(a, b);
74                                    });
75         }
76     };
77
78     template<typename Func>
79     class ReduceInvoker : public ParallelLoopBody
80     {
81     public:
82         const Mat* src;
83         Mat *dst;
84         std::vector<size_t> reduceDims;
85         int nstripes;
86         int reduceType;
87         Ptr<Func> func;
88
89         ReduceInvoker() : src(0), dst(0), nstripes(0), reduceType(MAX), func(makePtr<Func>()) {}
90
91         static void run(const Mat& src, Mat& dst, std::vector<size_t> reduceDims, int reduceType, int nstripes)
92         {
93             CV_Assert_N(src.isContinuous(), dst.isContinuous(), src.type() == CV_8S, src.type() == dst.type());
94
95             ReduceInvoker<Func> p;
96
97             p.src = &src;
98             p.dst = &dst;
99
100             p.reduceDims = reduceDims;
101             p.nstripes = nstripes;
102             p.reduceType = reduceType;
103
104             parallel_for_(Range(0, nstripes), p, nstripes);
105         }
106
107         void operator()(const Range& r) const CV_OVERRIDE
108         {
109             size_t total = dst->total();
110             size_t stripeSize = (total + nstripes - 1)/nstripes;
111             size_t stripeStart = r.start*stripeSize;
112             size_t stripeEnd = std::min(r.end*stripeSize, total);
113             size_t totalDeleted = std::accumulate(reduceDims.begin(), reduceDims.end(), 1, std::multiplies<size_t>());
114
115             int8_t *dstData = (int8_t *)dst->data;
116             int8_t *srcData = (int8_t *)src->data;
117
118             for (size_t ofs = stripeStart; ofs < stripeEnd;)
119             {
120                 const int8_t* first = srcData + ofs * totalDeleted;
121                 const int8_t* last = srcData + (ofs + 1) * totalDeleted;
122
123                 dstData[ofs] = func->apply(first, last);
124                 ofs += 1;
125             }
126         }
127     };
128
129     void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
130     {
131         CV_TRACE_FUNCTION();
132         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
133
134         std::vector<Mat> inputs, outputs;
135         inputs_arr.getMatVector(inputs);
136         outputs_arr.getMatVector(outputs);
137         CV_Assert(inputs.size() == 1);
138         const int nstripes = getNumThreads();
139
140         switch (reduceType)
141         {
142             case MIN:
143             {
144                 ReduceInvoker<ReduceOpMIN>::run(inputs[0], outputs[0], reduceDims, reduceType, nstripes);
145                 break;
146             }
147             case MAX:
148             {
149                 ReduceInvoker<ReduceOpMAX>::run(inputs[0], outputs[0], reduceDims, reduceType, nstripes);
150                 break;
151             }
152             default:
153                 CV_Error(Error::StsNotImplemented, "Not implemented");
154                 break;
155         }
156     }
157
158     bool getMemoryShapes(const std::vector<MatShape> &inputs,
159                          const int requiredOutputs,
160                          std::vector<MatShape> &outputs,
161                          std::vector<MatShape> &internals) const CV_OVERRIDE
162     {
163         CV_Assert(inputs.size() > 0);
164         CV_Assert(reduceDims.size() != 0 && inputs[0].size() >= reduceDims.size());
165
166         std::vector<int> outShape;
167         if (inputs[0].size() == reduceDims.size())
168             outShape.push_back(1);
169         else
170         {
171             for (int i = 0; i < inputs[0].size() - reduceDims.size(); i++)
172             {
173                 outShape.push_back(inputs[0][i]);
174             }
175         }
176         outputs.assign(1, outShape);
177
178         return false;
179     }
180
181     virtual bool tryQuantize(const std::vector<std::vector<float> > &scales,
182                              const std::vector<std::vector<int> > &zeropoints, LayerParams& params) CV_OVERRIDE
183     {
184         return false;
185     }
186
187     virtual int64 getFLOPS(const std::vector<MatShape> &inputs,
188                            const std::vector<MatShape> &outputs) const CV_OVERRIDE
189     {
190         CV_UNUSED(inputs); // suppress unused variable warning
191         long flops = 0;
192         size_t totalDeleted = std::accumulate(reduceDims.begin(), reduceDims.end(), 1, std::multiplies<size_t>());
193         for (int i = 0; i < outputs.size(); i++)
194         {
195             flops += total(outputs[i])*(totalDeleted);
196         }
197         return flops;
198     }
199 private:
200     enum Type
201     {
202         MAX,
203         MIN
204     };
205 };
206
207 Ptr<ReduceLayerInt8> ReduceLayerInt8::create(const LayerParams& params)
208 {
209     return Ptr<ReduceLayerInt8>(new ReduceLayerInt8Impl(params));
210 }
211
212 }
213 }