Merge pull request #14827 from YashasSamaga:cuda4dnn-csl-low
[platform/upstream/opencv.git] / modules / dnn / src / cuda4dnn / primitives / max_unpooling.hpp
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 #ifndef OPENCV_DNN_SRC_CUDA4DNN_PRIMITIVES_MAX_UNPOOLING_HPP
6 #define OPENCV_DNN_SRC_CUDA4DNN_PRIMITIVES_MAX_UNPOOLING_HPP
7
8 #include "../../op_cuda.hpp"
9
10 #include "../csl/stream.hpp"
11
12 #include "../kernels/max_unpooling.hpp"
13
14 #include <opencv2/core.hpp>
15
16 #include <cstddef>
17 #include <vector>
18 #include <utility>
19
20 namespace cv { namespace dnn { namespace cuda4dnn {
21
22     struct MaxPoolingConfiguration {
23         /* the size of the following vectors must be equal to the pooling order */
24         std::vector<std::size_t> window_size;
25         std::vector<std::size_t> strides;
26
27         enum class PaddingMode {
28             MANUAL, /* uses explicit padding values provided in `pads_begin` and `pads_end` */
29             VALID, /* no padding is added */
30             SAME /* TensorFlow logic is used for same padding */
31         };
32
33         PaddingMode padMode;
34
35         /* explicit paddings are used if and only if padMode is set to manual */
36         std::vector<std::size_t> pads_begin;
37
38         /* full shape inclusive of channel and batch axis */
39         std::vector<std::size_t> input_shape;
40     };
41
42     template <class T>
43     class MaxPoolingOp final : public CUDABackendNode {
44     public:
45         using wrapper_type = GetCUDABackendWrapperType<T>;
46
47         MaxPoolingOp(csl::Stream stream_, const MaxPoolingConfiguration& config)
48             : stream(std::move(stream_))
49         {
50             window_size = config.window_size;
51
52             const auto pooling_order = window_size.size();
53             CV_Assert(pooling_order >= 1);
54
55             strides = config.strides;
56             CV_Assert(pooling_order == strides.size());
57
58             if (pooling_order != 2 && pooling_order != 3)
59                 CV_Error(Error::StsNotImplemented, "Only 2D/3D max-pooling are supported.");
60
61             padding_left.resize(pooling_order);
62             if (config.padMode == MaxPoolingConfiguration::PaddingMode::MANUAL)
63             {
64                 const auto& pads_begin = config.pads_begin;
65                 CV_Assert(pooling_order == pads_begin.size());
66
67                 padding_left.assign(std::begin(pads_begin), std::end(pads_begin));
68             }
69             else if (config.padMode == MaxPoolingConfiguration::PaddingMode::VALID)
70             {
71                 /* nothing to do as the paddings are already preset to zero */
72             }
73             else if (config.padMode == MaxPoolingConfiguration::PaddingMode::SAME)
74             {
75                 /* TensorFlow Logic:
76                  * total_padding[i] = (o[i] - 1) * s[i] + effective_k[i] - i[i]
77                  *
78                  * if total padding is odd, the extra is added towards the end
79                  */
80                 const auto& input_shape = config.input_shape;
81                 CV_Assert(input_shape.size() == pooling_order + 2);
82
83                 for (int i = 0; i < pooling_order; i++)
84                 {
85                     const auto output_dim = (input_shape[i + 2] - 1 + strides[i]) / strides[i];
86                     const auto required_total_padding =
87                         std::max<std::int64_t>(0, (output_dim - 1) * strides[i] + window_size[i] - input_shape[i + 2]);
88
89                     padding_left[i] = required_total_padding / 2;
90                 }
91             }
92         }
93
94         void forward(
95             const std::vector<cv::Ptr<BackendWrapper>>& inputs,
96             const std::vector<cv::Ptr<BackendWrapper>>& outputs,
97             csl::Workspace& workspace) override
98         {
99             CV_Assert(inputs.size() == 1 && outputs.size() == 2);
100
101             auto input_wrapper = inputs[0].dynamicCast<wrapper_type>();
102             auto input_data = input_wrapper->getView();
103
104             auto output_wrapper = outputs[0].dynamicCast<wrapper_type>();
105             auto output_data = output_wrapper->getSpan();
106
107             auto indices_wrapper = outputs[1].dynamicCast<wrapper_type>();
108             auto output_indices = indices_wrapper->getSpan();
109
110             kernels::max_pooling_with_indices<T>(
111                 stream, output_data, output_indices, input_data, window_size, strides, padding_left
112             );
113         }
114
115     private:
116         csl::Stream stream;
117
118         std::vector<std::size_t> window_size, strides, padding_left;
119     };
120
121     struct MaxUnpoolingConfiguration {
122         /* the size of the following vectors must be equal to the unpooling order */
123         std::vector<std::size_t> window_size;
124         std::vector<std::size_t> strides;
125         std::vector<std::size_t> pads_begin;
126     };
127
128     template <class T>
129     class MaxUnpoolingOp final : public CUDABackendNode {
130     public:
131         using wrapper_type = GetCUDABackendWrapperType<T>;
132
133         MaxUnpoolingOp(csl::Stream stream_, const MaxUnpoolingConfiguration& config)
134             : stream(std::move(stream_))
135         {
136             window_size = config.window_size;
137
138             const auto pooling_order = window_size.size();
139             CV_Assert(pooling_order >= 1);
140
141             strides = config.strides;
142             padding_left = config.pads_begin;
143             CV_Assert(strides.size() == pooling_order);
144             CV_Assert(padding_left.size() == pooling_order);
145
146             if (pooling_order != 2 && pooling_order != 3)
147                 CV_Error(Error::StsNotImplemented, "Only 2D/3D max-unpooling are supported.");
148         }
149
150         void forward(
151             const std::vector<cv::Ptr<BackendWrapper>>& inputs,
152             const std::vector<cv::Ptr<BackendWrapper>>& outputs,
153             csl::Workspace& workspace) override
154         {
155             /* sometimes a third input is passed to provide the output shape; we won't need it */
156             CV_Assert(inputs.size() == 2 || inputs.size() == 3);
157             CV_Assert(outputs.size() >= 1);
158
159             for(int i = 0;  i < outputs.size(); i++)
160             {
161                 auto input_wrapper = inputs[0].dynamicCast<wrapper_type>();
162                 auto input_data = input_wrapper->getView();
163
164                 auto indices_wrapper = inputs[1].dynamicCast<wrapper_type>();
165                 auto input_indices = indices_wrapper->getView();
166
167                 auto output_wrapper = outputs[i].dynamicCast<wrapper_type>();
168                 auto output_data = output_wrapper->getSpan();
169
170                 kernels::max_unpooling<T>(stream, output_data, input_data, input_indices, window_size, strides, padding_left);
171             }
172         }
173
174     private:
175         csl::Stream stream;
176
177         std::vector<std::size_t> window_size, strides, padding_left;
178     };
179
180 }}} /* namespace cv::dnn::cuda4dnn */
181
182 #endif /* OPENCV_DNN_SRC_CUDA4DNN_PRIMITIVES_MAX_UNPOOLING_HPP */