Merge pull request #14827 from YashasSamaga:cuda4dnn-csl-low
[platform/upstream/opencv.git] / modules / dnn / src / layers / reshape_layer.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
14 // Copyright (C) 2017, Intel Corporation, all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
19 //
20 //   * Redistribution's of source code must retain the above copyright notice,
21 //     this list of conditions and the following disclaimer.
22 //
23 //   * Redistribution's in binary form must reproduce the above copyright notice,
24 //     this list of conditions and the following disclaimer in the documentation
25 //     and/or other materials provided with the distribution.
26 //
27 //   * The name of the copyright holders may not be used to endorse or promote products
28 //     derived from this software without specific prior written permission.
29 //
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
40 //
41 //M*/
42
43 #include "../precomp.hpp"
44 #include "layers_common.hpp"
45 #include "../op_cuda.hpp"
46 #include "../op_inf_engine.hpp"
47 #include <opencv2/dnn/shape_utils.hpp>
48
49 #ifdef HAVE_CUDA
50 #include "../cuda4dnn/primitives/reshape.hpp"
51 using namespace cv::dnn::cuda4dnn;
52 #endif
53
54 namespace cv
55 {
56 namespace dnn
57 {
58
59 static void computeShapeByReshapeMask(const MatShape &srcShape,
60                                       const MatShape &maskShape,
61                                       Range srcRange /*= Range::all()*/,
62                                       MatShape& dstShape)
63 {
64     int srcShapeSize = (int)srcShape.size();
65     int maskShapeSize = (int)maskShape.size();
66
67     if (srcRange == Range::all())
68         srcRange = Range(0, srcShapeSize);
69     else
70     {
71         int sz = srcRange.size();
72         srcRange.start = clamp(srcRange.start, srcShapeSize);
73         srcRange.end = srcRange.end == INT_MAX ? srcShapeSize : srcRange.start + sz;
74     }
75
76     bool explicitMask = !maskShape.empty();  // All mask values are positive.
77     for (int i = 0, n = maskShape.size(); i < n && explicitMask; ++i)
78     {
79         explicitMask = maskShape[i] > 0;
80     }
81     // Working range of source shape is a range where area(src) == area(mask).
82     if (explicitMask)
83     {
84         int maskTotal = total(maskShape);
85         // Go from the end of mask until we collect required total.
86         bool matched = false;
87         for (int i = srcRange.end - 1; i >= srcRange.start; --i)
88         {
89             if (matched)
90             {
91                 if (total(srcShape, i, srcRange.end) != maskTotal)
92                 {
93                     srcRange.start = i + 1;
94                     break;
95                 }
96                 else if (i == 0)
97                 {
98                     srcRange.start = 0;
99                     break;
100                 }
101             }
102             else
103             {
104                 matched = total(srcShape, i, srcRange.end) == maskTotal;
105             }
106         }
107         while (total(srcShape, srcRange.start, srcRange.end) != maskTotal && srcRange.start > 0)
108         {
109             srcRange.start -= 1;
110         }
111         CV_Assert(total(srcShape, srcRange.start, srcRange.end) == maskTotal);
112     }
113
114     CV_Assert(0 <= srcRange.start && srcRange.start <= srcRange.end && srcRange.end <= srcShapeSize);
115     int dstShapeSize = srcShapeSize - srcRange.size() + maskShapeSize;
116     dstShape.resize(dstShapeSize);
117
118     std::copy(srcShape.begin(), srcShape.begin() + srcRange.start, dstShape.begin());
119     std::copy(srcShape.begin() + srcRange.end, srcShape.begin() + srcShapeSize, dstShape.begin() + srcRange.start + maskShapeSize);
120
121     int inferDim = -1;
122     for (int i = 0; i < maskShapeSize; i++)
123     {
124         if (maskShape[i] > 0)
125         {
126             dstShape[srcRange.start + i] = maskShape[i];
127         }
128         else if (maskShape[i] == 0)
129         {
130             if (srcRange.start + i >= srcShapeSize)
131                 CV_Error(Error::StsBadArg, format("Copy dim[%d] (which has zero size) is out of the source shape bounds", srcRange.start + i));
132             dstShape[srcRange.start + i] = srcShape[srcRange.start + i];
133         }
134         else if (maskShape[i] == -1)
135         {
136             if (inferDim != -1)
137                 CV_Error(Error::StsAssert, "Duplicate of inferred dim (which is denoted by -1)");
138             inferDim = srcRange.start + i;
139             dstShape[inferDim] = 1;
140         }
141         else
142             CV_Error(Error::StsBadArg, "maskShape[i] >= -1");
143     }
144
145     size_t srcTotal = total(srcShape);
146     size_t dstTotal = total(dstShape);
147     CV_Assert(dstTotal != 0);
148
149     if (inferDim != -1)
150     {
151         if (srcTotal % dstTotal != 0)
152             CV_Error(Error::StsBackTrace, "Can't infer a dim denoted by -1");
153
154         dstShape[inferDim] = (int)(srcTotal / dstTotal);
155     }
156     else
157     {
158         CV_Assert(srcTotal == dstTotal);
159     }
160 }
161
162
163 class ReshapeLayerImpl CV_FINAL : public ReshapeLayer
164 {
165 public:
166     ReshapeLayerImpl(const LayerParams& params)
167     {
168         setParamsFrom(params);
169         int axis = params.get<int>("axis", 0);
170         int numAxes = params.get<int>("num_axes", -1);
171         CV_Assert(numAxes >= -1);
172         newShapeRange = (numAxes == -1) ? Range(axis, INT_MAX) : Range(axis, axis + numAxes);
173
174         newShapeDesc.clear();
175         if (params.has("dim"))
176         {
177             const DictValue &paramShape = params.get("dim");
178             int i, dims = paramShape.size();
179             newShapeDesc.resize(dims);
180             for (i = 0; i < dims; i++)
181                 newShapeDesc[i] = paramShape.get<int>(i);
182         }
183     }
184
185     virtual bool supportBackend(int backendId) CV_OVERRIDE
186     {
187         return backendId == DNN_BACKEND_OPENCV ||
188                backendId == DNN_BACKEND_CUDA ||
189                (backendId == DNN_BACKEND_INFERENCE_ENGINE && haveInfEngine());
190     }
191
192     bool getMemoryShapes(const std::vector<MatShape> &inputs,
193                          const int requiredOutputs,
194                          std::vector<MatShape> &outputs,
195                          std::vector<MatShape> &internals) const CV_OVERRIDE
196     {
197         if (inputs.size() == 1 || inputs.size() == requiredOutputs)
198         {
199             outputs.clear();
200             for (size_t i = 0; i < inputs.size(); i++)
201             {
202                 outputs.push_back(MatShape());
203                 computeShapeByReshapeMask(inputs[i], newShapeDesc, newShapeRange, outputs.back());
204             }
205         }
206         else
207         {
208             CV_Assert_N(inputs.size() == 2, total(inputs[0]) == total(inputs[1]));
209             outputs.assign(1, inputs[1]);
210         }
211         return true;
212     }
213
214     void finalize(InputArrayOfArrays, OutputArrayOfArrays outputs_arr) CV_OVERRIDE
215     {
216         std::vector<Mat> outputs;
217         outputs_arr.getMatVector(outputs);
218
219         CV_Assert(!outputs.empty());
220         outShapes.resize(outputs.size());
221         for (int i = 0; i < outputs.size(); ++i)
222             outShapes[i] = shape(outputs[i]);
223     }
224
225     bool forward_ocl(InputArrayOfArrays inps, OutputArrayOfArrays outs, OutputArrayOfArrays internals)
226     {
227         std::vector<UMat> inputs;
228         std::vector<UMat> outputs;
229
230         inps.getUMatVector(inputs);
231         outs.getUMatVector(outputs);
232
233         for (size_t i = 0; i < outputs.size(); i++)
234         {
235             UMat srcBlob = inputs[i];
236             void *src_handle = inputs[i].handle(ACCESS_READ);
237             void *dst_handle = outputs[i].handle(ACCESS_WRITE);
238             if (src_handle != dst_handle)
239             {
240                 UMat umat = srcBlob.reshape(1, (int)outShapes[i].size(), &outShapes[i][0]);
241                 umat.copyTo(outputs[i]);
242             }
243         }
244         outs.assign(outputs);
245
246         return true;
247     }
248
249     void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
250     {
251         CV_TRACE_FUNCTION();
252         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
253
254         CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget),
255                    forward_ocl(inputs_arr, outputs_arr, internals_arr))
256
257         std::vector<Mat> inputs, outputs;
258         inputs_arr.getMatVector(inputs);
259         outputs_arr.getMatVector(outputs);
260         for (size_t i = 0; i < outputs.size(); i++)
261         {
262             Mat srcBlob = inputs[i];
263             if (outputs[i].data != srcBlob.data)
264                 srcBlob.reshape(1, shape(outputs[i])).copyTo(outputs[i]);
265         }
266     }
267
268 #ifdef HAVE_CUDA
269     Ptr<BackendNode> initCUDA(
270         void *context_,
271         const std::vector<Ptr<BackendWrapper>>& inputs,
272         const std::vector<Ptr<BackendWrapper>>& outputs
273     ) override
274     {
275         auto context = reinterpret_cast<csl::CSLContext*>(context_);
276         return make_cuda_node<cuda4dnn::ReshapeOp>(preferableTarget, std::move(context->stream));
277     }
278 #endif
279
280 #ifdef HAVE_INF_ENGINE
281     virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >& inputs) CV_OVERRIDE
282     {
283         InferenceEngine::Builder::ReshapeLayer ieLayer(name);
284         CV_Assert(outShapes.size() == 1);
285         ieLayer.setDims(outShapes[0]);
286         return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
287     }
288 #endif  // HAVE_INF_ENGINE
289
290 private:
291     std::vector<MatShape> outShapes;
292 };
293
294 Ptr<ReshapeLayer> ReshapeLayer::create(const LayerParams& params)
295 {
296     return Ptr<ReshapeLayer>(new ReshapeLayerImpl(params));
297 }
298
299
300 }
301 }