Merge pull request #14827 from YashasSamaga:cuda4dnn-csl-low
[platform/upstream/opencv.git] / modules / dnn / src / layers / padding_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 // Copyright (C) 2017, Intel Corporation, all rights reserved.
6 // Third party copyrights are property of their respective owners.
7
8 /*
9 Implementation of padding layer, which adds paddings to input blob.
10 */
11
12 #include "../precomp.hpp"
13 #include "layers_common.hpp"
14 #include "../op_cuda.hpp"
15 #include "../op_halide.hpp"
16 #include "../op_inf_engine.hpp"
17 #include <vector>
18
19 #ifdef HAVE_CUDA
20 #include "../cuda4dnn/primitives/padding.hpp"
21 using namespace cv::dnn::cuda4dnn;
22 #endif
23
24 namespace cv
25 {
26 namespace dnn
27 {
28
29 class PaddingLayerImpl CV_FINAL : public PaddingLayer
30 {
31 public:
32     PaddingLayerImpl(const LayerParams &params)
33     {
34         setParamsFrom(params);
35         paddingValue = params.get<float>("value", 0);
36         inputDims = params.get<int>("input_dims", -1);
37         paddingType = params.get<String>("type", "constant");
38
39         CV_Assert(params.has("paddings"));
40         const DictValue& paddingsParam = params.get("paddings");
41         CV_Assert((paddingsParam.size() & 1) == 0);
42
43         paddings.resize(paddingsParam.size() / 2);
44         for (int i = 0; i < paddings.size(); ++i)
45         {
46             paddings[i].first = paddingsParam.get<int>(i * 2);  // Pad before.
47             paddings[i].second = paddingsParam.get<int>(i * 2 + 1);  // Pad after.
48             CV_Assert_N(paddings[i].first >= 0, paddings[i].second >= 0);
49         }
50     }
51
52     bool getMemoryShapes(const std::vector<MatShape> &inputs,
53                          const int requiredOutputs,
54                          std::vector<MatShape> &outputs,
55                          std::vector<MatShape> &internals) const CV_OVERRIDE
56     {
57         CV_Assert(inputs.size() == 1);
58         const MatShape& inpShape = inputs[0];
59         CV_Assert(inpShape.size() >= paddings.size());
60         CV_Assert(inputDims == -1 || inpShape.size() == inputDims || inpShape.size() > paddings.size());
61
62         outputs.resize(1, inpShape);
63         int offset = (inputDims == -1 ? 0 : (inpShape.size() > inputDims ? 1 : 0));
64         for (int i = 0; i < paddings.size(); ++i)
65         {
66             outputs[0][offset + i] = inpShape[offset + i] + paddings[i].first + paddings[i].second;
67         }
68         return false;
69     }
70
71     void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays) CV_OVERRIDE
72     {
73         std::vector<Mat> inputs;
74         inputs_arr.getMatVector(inputs);
75
76         // Compute dstRanges.
77         const MatSize& inpShape = inputs[0].size;
78
79         if (inputDims != -1 && inputs[0].dims != inputDims)
80         {
81             paddings.insert(paddings.begin(), std::make_pair(0, 0));
82         }
83
84         dstRanges.resize(paddings.size());
85         for (int i = 0; i < paddings.size(); ++i)
86         {
87             dstRanges[i].start = paddings[i].first;
88             dstRanges[i].end = paddings[i].first + inpShape[i];
89         }
90
91         // Add the rest of dimensions.
92         for (int i = dstRanges.size(); i < inputs[0].dims; ++i)
93         {
94             dstRanges.push_back(Range::all());
95             paddings.push_back(std::make_pair(0, 0));
96         }
97         inputDims = -1;  // Next time paddings are filled for all the dimensions.
98     }
99
100     virtual bool supportBackend(int backendId) CV_OVERRIDE
101     {
102 #ifdef HAVE_INF_ENGINE
103         if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
104             return INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2019R1) &&
105                    (preferableTarget != DNN_TARGET_MYRIAD ||
106                     (dstRanges.size() == 4 && paddings[0].first == 0 && paddings[0].second == 0));
107 #endif
108         return backendId == DNN_BACKEND_OPENCV ||
109                backendId == DNN_BACKEND_CUDA ||
110                (backendId == DNN_BACKEND_HALIDE && haveHalide() && dstRanges.size() == 4);
111     }
112
113     void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
114     {
115         CV_TRACE_FUNCTION();
116         CV_TRACE_ARG_VALUE(name, "name", name.c_str());
117
118         std::vector<Mat> inputs, outputs;
119         inputs_arr.getMatVector(inputs);
120         outputs_arr.getMatVector(outputs);
121
122         if (paddingType == "constant")
123         {
124             if (inputs_arr.depth() == CV_16S)
125             {
126                 std::vector<float> paddingValue_fp32(1, paddingValue);
127                 std::vector<int16_t> paddingValue_fp16(1);
128                 cv::convertFp16(paddingValue_fp32, paddingValue_fp16);
129                 outputs[0].setTo(paddingValue_fp16[0]);
130             }
131             else
132                 outputs[0].setTo(paddingValue);
133             inputs[0].copyTo(outputs[0](dstRanges));
134         }
135         else if (paddingType == "reflect")
136         {
137             CV_Assert(inputs.size() == 1);
138             CV_Assert(outputs.size() == 1);
139             CV_Assert(inputs[0].dims == 4);
140             CV_Assert(outputs[0].dims == 4);
141
142             if (inputs[0].size[0] != outputs[0].size[0] || inputs[0].size[1] != outputs[0].size[1])
143                 CV_Error(Error::StsNotImplemented, "Only spatial reflection padding is supported.");
144
145             const int inpHeight = inputs[0].size[2];
146             const int inpWidth = inputs[0].size[3];
147             const int outHeight = outputs[0].size[2];
148             const int outWidth = outputs[0].size[3];
149             const int padTop = dstRanges[2].start;
150             const int padBottom = outHeight - dstRanges[2].end;
151             const int padLeft = dstRanges[3].start;
152             const int padRight = outWidth - dstRanges[3].end;
153             CV_CheckLT(padTop, inpHeight, ""); CV_CheckLT(padBottom, inpHeight, "");
154             CV_CheckLT(padLeft, inpWidth, ""); CV_CheckLT(padRight, inpWidth, "");
155
156             for (size_t n = 0; n < inputs[0].size[0]; ++n)
157             {
158                 for (size_t ch = 0; ch < inputs[0].size[1]; ++ch)
159                 {
160                     copyMakeBorder(getPlane(inputs[0], n, ch),
161                                    getPlane(outputs[0], n, ch),
162                                    padTop, padBottom, padLeft, padRight,
163                                    BORDER_REFLECT_101);
164                 }
165             }
166         }
167         else
168             CV_Error(Error::StsNotImplemented, "Unknown padding type: " + paddingType);
169     }
170
171 #ifdef HAVE_CUDA
172     Ptr<BackendNode> initCUDA(
173         void *context_,
174         const std::vector<Ptr<BackendWrapper>>& inputs,
175         const std::vector<Ptr<BackendWrapper>>& outputs
176     ) override
177     {
178         auto context = reinterpret_cast<csl::CSLContext*>(context_);
179
180         cuda4dnn::PaddingType ptype;
181         if (paddingType == "constant")
182             ptype = PaddingType::CONSTANT;
183         else if (paddingType == "reflect")
184             ptype = PaddingType::REFLECTION101;
185         else
186             CV_Error(Error::StsNotImplemented, "Unsupported padding mode");
187
188         return make_cuda_node<cuda4dnn::PaddingOp>(preferableTarget, std::move(context->stream), ptype, paddingValue, dstRanges);
189     }
190 #endif
191
192     virtual Ptr<BackendNode> initHalide(const std::vector<Ptr<BackendWrapper> > &inputs) CV_OVERRIDE
193     {
194 #ifdef HAVE_HALIDE
195         int inW, inH, inC, inN;
196         int minN = std::max(dstRanges[0].start, 0);
197         int minC = std::max(dstRanges[1].start, 0);
198         int minY = std::max(dstRanges[2].start, 0);
199         int minX = std::max(dstRanges[3].start, 0);
200         Halide::Buffer<float> inputBuffer = halideBuffer(inputs[0]);
201         getCanonicalSize(inputBuffer, &inW, &inH, &inC, &inN);
202
203         Halide::Var x("x"), y("y"), c("c"), n("n");
204         Halide::Func top = (name.empty() ? Halide::Func() : Halide::Func(name));
205         Halide::Func padded =
206             Halide::BoundaryConditions::constant_exterior(inputBuffer, paddingValue);
207         top(x, y, c, n) = padded(x - minX, y - minY, c - minC, n - minN);
208         return Ptr<BackendNode>(new HalideBackendNode(top));
209 #endif  // HAVE_HALIDE
210         return Ptr<BackendNode>();
211     }
212
213 #ifdef HAVE_INF_ENGINE
214     virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> >&) CV_OVERRIDE
215     {
216         InferenceEngine::Builder::Layer ieLayer(name);
217         ieLayer.setName(name);
218         ieLayer.setType("Pad");
219
220         std::vector<int> begins(paddings.size(), 0), ends(paddings.size(), 0);
221         for (int i = 0; i < paddings.size(); ++i)
222         {
223             begins[i] = paddings[i].first;
224             ends[i] = paddings[i].second;
225         }
226         ieLayer.getParameters()["pads_begin"] = begins;
227         ieLayer.getParameters()["pads_end"] = ends;
228         ieLayer.getParameters()["pad_mode"] = paddingType;
229         if (paddingType == "constant")
230             ieLayer.getParameters()["pad_value"] = paddingValue;
231
232         ieLayer.setInputPorts(std::vector<InferenceEngine::Port>(1));
233         ieLayer.setOutputPorts(std::vector<InferenceEngine::Port>(1));
234         return Ptr<BackendNode>(new InfEngineBackendNode(ieLayer));
235     }
236 #endif
237
238 private:
239     std::vector<std::pair<int, int> > paddings;  // Pairs pad before, pad after.
240     std::vector<Range> dstRanges;
241     int inputDims;
242     float paddingValue;
243     std::string paddingType;
244 };
245
246 Ptr<PaddingLayer> PaddingLayer::create(const LayerParams &params)
247 {
248     return Ptr<PaddingLayer>(new PaddingLayerImpl(params));
249 }
250
251 }
252 }