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.
5 #ifndef OPENCV_DNN_SRC_CUDA4DNN_PRIMITIVES_MAX_UNPOOLING_HPP
6 #define OPENCV_DNN_SRC_CUDA4DNN_PRIMITIVES_MAX_UNPOOLING_HPP
8 #include "../../op_cuda.hpp"
10 #include "../csl/stream.hpp"
12 #include "../kernels/max_unpooling.hpp"
14 #include <opencv2/core.hpp>
20 namespace cv { namespace dnn { namespace cuda4dnn {
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;
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 */
35 /* explicit paddings are used if and only if padMode is set to manual */
36 std::vector<std::size_t> pads_begin;
38 /* full shape inclusive of channel and batch axis */
39 std::vector<std::size_t> input_shape;
43 class MaxPoolingOp final : public CUDABackendNode {
45 using wrapper_type = GetCUDABackendWrapperType<T>;
47 MaxPoolingOp(csl::Stream stream_, const MaxPoolingConfiguration& config)
48 : stream(std::move(stream_))
50 window_size = config.window_size;
52 const auto pooling_order = window_size.size();
53 CV_Assert(pooling_order >= 1);
55 strides = config.strides;
56 CV_Assert(pooling_order == strides.size());
58 if (pooling_order != 2 && pooling_order != 3)
59 CV_Error(Error::StsNotImplemented, "Only 2D/3D max-pooling are supported.");
61 padding_left.resize(pooling_order);
62 if (config.padMode == MaxPoolingConfiguration::PaddingMode::MANUAL)
64 const auto& pads_begin = config.pads_begin;
65 CV_Assert(pooling_order == pads_begin.size());
67 padding_left.assign(std::begin(pads_begin), std::end(pads_begin));
69 else if (config.padMode == MaxPoolingConfiguration::PaddingMode::VALID)
71 /* nothing to do as the paddings are already preset to zero */
73 else if (config.padMode == MaxPoolingConfiguration::PaddingMode::SAME)
76 * total_padding[i] = (o[i] - 1) * s[i] + effective_k[i] - i[i]
78 * if total padding is odd, the extra is added towards the end
80 const auto& input_shape = config.input_shape;
81 CV_Assert(input_shape.size() == pooling_order + 2);
83 for (int i = 0; i < pooling_order; i++)
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]);
89 padding_left[i] = required_total_padding / 2;
95 const std::vector<cv::Ptr<BackendWrapper>>& inputs,
96 const std::vector<cv::Ptr<BackendWrapper>>& outputs,
97 csl::Workspace& workspace) override
99 CV_Assert(inputs.size() == 1 && outputs.size() == 2);
101 auto input_wrapper = inputs[0].dynamicCast<wrapper_type>();
102 auto input_data = input_wrapper->getView();
104 auto output_wrapper = outputs[0].dynamicCast<wrapper_type>();
105 auto output_data = output_wrapper->getSpan();
107 auto indices_wrapper = outputs[1].dynamicCast<wrapper_type>();
108 auto output_indices = indices_wrapper->getSpan();
110 kernels::max_pooling_with_indices<T>(
111 stream, output_data, output_indices, input_data, window_size, strides, padding_left
118 std::vector<std::size_t> window_size, strides, padding_left;
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;
129 class MaxUnpoolingOp final : public CUDABackendNode {
131 using wrapper_type = GetCUDABackendWrapperType<T>;
133 MaxUnpoolingOp(csl::Stream stream_, const MaxUnpoolingConfiguration& config)
134 : stream(std::move(stream_))
136 window_size = config.window_size;
138 const auto pooling_order = window_size.size();
139 CV_Assert(pooling_order >= 1);
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);
146 if (pooling_order != 2 && pooling_order != 3)
147 CV_Error(Error::StsNotImplemented, "Only 2D/3D max-unpooling are supported.");
151 const std::vector<cv::Ptr<BackendWrapper>>& inputs,
152 const std::vector<cv::Ptr<BackendWrapper>>& outputs,
153 csl::Workspace& workspace) override
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);
159 for(int i = 0; i < outputs.size(); i++)
161 auto input_wrapper = inputs[0].dynamicCast<wrapper_type>();
162 auto input_data = input_wrapper->getView();
164 auto indices_wrapper = inputs[1].dynamicCast<wrapper_type>();
165 auto input_indices = indices_wrapper->getView();
167 auto output_wrapper = outputs[i].dynamicCast<wrapper_type>();
168 auto output_data = output_wrapper->getSpan();
170 kernels::max_unpooling<T>(stream, output_data, input_data, input_indices, window_size, strides, padding_left);
177 std::vector<std::size_t> window_size, strides, padding_left;
180 }}} /* namespace cv::dnn::cuda4dnn */
182 #endif /* OPENCV_DNN_SRC_CUDA4DNN_PRIMITIVES_MAX_UNPOOLING_HPP */