Merge pull request #14827 from YashasSamaga:cuda4dnn-csl-low
[platform/upstream/opencv.git] / modules / dnn / src / cuda4dnn / csl / cudnn / transform.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_CUDA4DNN_CSL_CUDNN_TRANSFORM_HPP
6 #define OPENCV_DNN_CUDA4DNN_CSL_CUDNN_TRANSFORM_HPP
7
8 #include "../pointer.hpp"
9
10 #include "cudnn.hpp"
11
12 #include <cudnn.h>
13 #include <vector>
14 #include <type_traits>
15 #include <iterator>
16
17 namespace cv { namespace dnn { namespace cuda4dnn { namespace csl { namespace cudnn {
18
19     /** describes a tensor transform operation
20      *
21      * Supported transformations:
22      * - add or remove asymmetric padding
23      */
24     class TensorTransformDescriptor {
25     public:
26         TensorTransformDescriptor() noexcept : descriptor{ nullptr } { }
27         TensorTransformDescriptor(const TensorTransformDescriptor&) = delete;
28         TensorTransformDescriptor(TensorTransformDescriptor&& other) noexcept
29             : descriptor{ other.descriptor } {
30             other.descriptor = nullptr;
31         }
32
33         /** constructs a convolution descriptor
34          *
35          * Pre-conditions:
36          * - \p padding_left and \p padding_right must have the same size
37          *
38          * The length of the containers is interpreted as the rank of the tensors which will be given.
39          *
40          * @note \p padding_left and \p padding_right may have negative values to remove padding
41          *
42          * Exception Guarantee: Basic
43          */
44         template <class SequenceContainer, typename = decltype(std::begin(std::declval<SequenceContainer>()))>
45         TensorTransformDescriptor(
46             const SequenceContainer& padding_left,
47             const SequenceContainer& padding_right)
48         {
49             constructor(padding_left, padding_right);
50         }
51
52         ~TensorTransformDescriptor() noexcept {
53             if (descriptor != nullptr) {
54                 /* cudnnDestroyTensorTransformDescriptor will not fail for a valid descriptor */
55                 CUDA4DNN_CHECK_CUDNN(cudnnDestroyTensorTransformDescriptor(descriptor));
56             }
57         }
58
59         TensorTransformDescriptor& operator=(const TensorTransformDescriptor&) = delete;
60         TensorTransformDescriptor& operator=(TensorTransformDescriptor&& other) noexcept {
61             descriptor = other.descriptor;
62             other.descriptor = nullptr;
63             return *this;
64         };
65
66         cudnnTensorTransformDescriptor_t get() const noexcept { return descriptor; }
67
68     private:
69         template <class SequenceContainer>
70         void constructor(
71             const SequenceContainer& padding_left,
72             const SequenceContainer& padding_right
73         )
74         {
75             CV_Assert(padding_left.size() == padding_right.size());
76
77             auto ipadding_left  = std::vector<int32_t>(std::begin(padding_left), std::end(padding_left));
78             auto ipadding_right = std::vector<int32_t>(std::begin(padding_right), std::end(padding_right));
79             CUDA4DNN_CHECK_CUDNN(cudnnCreateTensorTransformDescriptor(&descriptor));
80             try {
81                 CUDA4DNN_CHECK_CUDNN(
82                     cudnnSetTensorTransformDescriptor(
83                         descriptor,
84                         ipadding_left.size(), CUDNN_TENSOR_NCHW,
85                         ipadding_left.data(), ipadding_right.data(),
86                         NULL, CUDNN_TRANSFORM_FOLD
87                     )
88                 );
89             } catch (...) {
90                 /* cudnnDestroyTensorTransformDescriptor will not fail for a valid descriptor */
91                 CUDA4DNN_CHECK_CUDNN(cudnnDestroyTensorTransformDescriptor(descriptor));
92                 throw;
93             }
94         }
95
96         cudnnTensorTransformDescriptor_t descriptor;
97     };
98
99     template <class T>
100     void transform(
101         const Handle& handle,
102         const TensorTransformDescriptor& transDesc,
103         const TensorDescriptor<T>& inputDesc,
104         DevicePtr<const T> inputPtr,
105         const TensorDescriptor<T>& outputDesc,
106         DevicePtr<T> outputPtr)
107     {
108         T alpha = 1.0, beta = 0.0;
109         CUDA4DNN_CHECK_CUDNN(
110             cudnnTransformTensorEx(
111                 handle.get(),
112                 transDesc.get(),
113                 &alpha, inputDesc.get(), inputPtr.get(),
114                 &beta, outputDesc.get(), outputPtr.get()
115             )
116         );
117     }
118
119     template <> inline
120     void transform(
121         const Handle& handle,
122         const TensorTransformDescriptor& transDesc,
123         const TensorDescriptor<half>& inputDesc,
124         DevicePtr<const half> inputPtr,
125         const TensorDescriptor<half>& outputDesc,
126         DevicePtr<half> outputPtr)
127     {
128         /* we specalize for fp16 as the scaling factors must be provided as `float` */
129         float alpha = 1.0, beta = 0.0;
130         CUDA4DNN_CHECK_CUDNN(
131             cudnnTransformTensorEx(
132                 handle.get(),
133                 transDesc.get(),
134                 &alpha, inputDesc.get(), inputPtr.get(),
135                 &beta, outputDesc.get(), outputPtr.get()
136             )
137         );
138     }
139
140 }}}}} /* namespace cv::dnn::cuda4dnn::csl::cudnn */
141
142 #endif /* OPENCV_DNN_CUDA4DNN_CSL_CUDNN_TRANSFORM_HPP */