1 /**
2 * Copyright 2023 Huawei Technologies Co., Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #ifndef MINDSPORE_CCSRC_KERNEL_OPS_UTILS_H_
17 #define MINDSPORE_CCSRC_KERNEL_OPS_UTILS_H_
18
19 #include <memory>
20 #include <string>
21 #include <vector>
22 #include <utility>
23 #include <algorithm>
24 #include "kernel/kernel.h"
25 #include "kernel/common_utils.h"
26
27 namespace mindspore {
28 namespace kernel {
29 BACKEND_EXPORT float Scaling(size_t in_size, size_t out_size, bool align_corners);
30 float ScaleGrid(const int x, const float scale);
Scaler(const size_t x,const float scale,bool half_pixel_centers)31 inline float Scaler(const size_t x, const float scale, bool half_pixel_centers) {
32 if (half_pixel_centers) {
33 /**
34 * function with a std::floor(), so instead of subtracting the 0.5 as we
35 * do in HalfPixelScale, we leave it as is, as the std::floor does the
36 * correct thing.
37 * */
38 return (static_cast<float>(x) + 0.5f) * scale;
39 } else {
40 /**
41 * Older incorrect scaling method that causes all resizes to have a slight
42 * translation leading to inconsistent results. For example, a flip then a
43 * resize gives different results then a resize then a flip.
44 * */
45 return static_cast<float>(x) * scale;
46 }
47 }
48
49 struct CachedInterpolation {
50 size_t lower;
51 size_t upper;
52 float lerp;
53 };
54
55 template <typename T>
56 struct AlignCornersFunc {
operatorAlignCornersFunc57 T operator()(const T &new_x, const int &old_length, const int &new_length) const {
58 return new_length != 1 ? new_x * (old_length - 1) / (new_length - 1) : 0;
59 }
60 };
61
62 template <typename T>
63 struct HalfPixelFunc {
operatorHalfPixelFunc64 T operator()(const T &new_x, const int &old_length, const int &new_length) const {
65 constexpr auto half_pixel = 0.5;
66 return new_length > 1 ? (new_x + half_pixel) * old_length / new_length - half_pixel : 0;
67 }
68 };
69
70 void ComputeInterpolationWeights(const size_t out_size, const size_t in_size, const float scale,
71 CachedInterpolation *interpolation, bool half_pixel_centers);
72
73 template <typename T>
ComputeLerp(T top_left,T top_right,T bottom_left,T bottom_right,T x_lerp,T y_lerp)74 inline T ComputeLerp(T top_left, T top_right, T bottom_left, T bottom_right, T x_lerp, T y_lerp) {
75 T top = top_left + (top_right - top_left) * x_lerp;
76 T bottom = bottom_left + (bottom_right - bottom_left) * x_lerp;
77 return top + (bottom - top) * y_lerp;
78 }
79
80 BACKEND_EXPORT std::vector<bool> Dec2Bin(const int64_t &mask);
81 // ===========================New interface==========================================================
82 BACKEND_EXPORT void FillEmptyDims(const std::string &kernel_name, std::vector<int64_t> *begin,
83 std::vector<int64_t> *end, std::vector<int64_t> *stride, ShapeVector *input_shape,
84 bool is_gpu_strided = false);
85 BACKEND_EXPORT void ParseStrideSliceMasks(const std::vector<kernel::KernelTensor *> &inputs,
86 std::vector<int64_t> *begin, std::vector<int64_t> *end,
87 std::vector<int64_t> *stride, const ShapeVector &input_shape);
88
89 // ===========================Old interface==========================================================
90 BACKEND_EXPORT void FillEmptyDims(const BaseOperatorPtr &base_operator, std::vector<int64_t> *begin,
91 std::vector<int64_t> *end, std::vector<int64_t> *stride, ShapeVector *input_shape,
92 bool is_gpu_strided = false);
93
94 template <typename T>
ComputeScales(const double & scale,const size_t & input_size,const size_t & output_size)95 inline T ComputeScales(const double &scale, const size_t &input_size, const size_t &output_size) {
96 if (scale > 0.) {
97 return static_cast<T>(1.0 / scale);
98 } else if (output_size > 0) {
99 return (static_cast<T>(input_size) / output_size);
100 }
101 return 0;
102 }
103
104 template <typename T>
ComputeScalesBackward(const double scale,const int64_t src_size,const int64_t dst_size)105 inline T ComputeScalesBackward(const double scale, const int64_t src_size, const int64_t dst_size) {
106 if (scale > 0.) {
107 return static_cast<T>(scale);
108 } else if (dst_size > 0) {
109 return static_cast<T>(src_size) / dst_size;
110 }
111 return 0;
112 }
113
NearestNeighborSourceIndex(const float & scale,const size_t & dst_index,const size_t & input_size)114 inline size_t NearestNeighborSourceIndex(const float &scale, const size_t &dst_index, const size_t &input_size) {
115 size_t src_index = std::min(static_cast<size_t>(floorf(SizeToFloat(dst_index) * scale)), input_size - 1);
116 return src_index;
117 }
118
NearestIndex(const size_t & output_index,const size_t & input_size,const size_t & output_size,const double & scales)119 inline size_t NearestIndex(const size_t &output_index, const size_t &input_size, const size_t &output_size,
120 const double &scales) {
121 constexpr size_t kNumberTwo = 2;
122 if (output_size == input_size) {
123 // scale_factor = 1
124 return output_index;
125 } else if (output_size == kNumberTwo * input_size) {
126 // scale_factor = 2, shift input index
127 return output_index >> 1;
128 } else {
129 auto scale = ComputeScales<float>(scales, input_size, output_size);
130 return NearestNeighborSourceIndex(scale, output_index, input_size);
131 }
132 }
133
134 template <typename T>
AreaPixelComputeScale(int64_t input_size,int64_t output_size,bool align_corners,double scale)135 inline T AreaPixelComputeScale(int64_t input_size, int64_t output_size, bool align_corners, double scale) {
136 if (align_corners) {
137 if (output_size > 1) {
138 return static_cast<T>(input_size - 1) / (output_size - 1);
139 } else {
140 return static_cast<T>(0);
141 }
142 } else {
143 return ComputeScales<T>(scale, input_size, output_size);
144 }
145 }
146
147 template <typename T>
AreaPixelComputeSourceIndex(T scale,int64_t dst_index,bool align_corners)148 inline T AreaPixelComputeSourceIndex(T scale, int64_t dst_index, bool align_corners) {
149 if (align_corners) {
150 return scale * static_cast<T>(dst_index);
151 } else {
152 constexpr T zero = 0.;
153 T src_idx = scale * (LongToDouble(dst_index) + 0.5) - 0.5;
154 return src_idx < zero ? zero : src_idx;
155 }
156 }
157
158 template <typename T>
DataIndexInit(const T * offset)159 inline T DataIndexInit(const T *offset) {
160 return *offset;
161 }
162
163 template <typename T, typename... Args>
DataIndexInit(T * offset,T * x,const T * X,Args &&...args)164 inline T DataIndexInit(T *offset, T *x, const T *X, Args &&... args) {
165 auto off = DataIndexInit(offset, std::forward<Args>(args)...);
166 *x = off % *X;
167 return off / *X;
168 }
169
DataIndexStep()170 inline bool DataIndexStep() { return true; }
171
172 template <typename T, typename... Args>
DataIndexStep(T * x,const T * X,Args &&...args)173 inline bool DataIndexStep(T *x, const T *X, Args &&... args) {
174 if (DataIndexStep(std::forward<Args>(args)...)) {
175 *x = ((*x + 1) == *X) ? 0 : (*x + 1);
176 return *x == 0;
177 }
178 return false;
179 }
180
181 template <typename T>
ComputeSourceIndexAndLambda(int64_t * const input_index0,int64_t * const input_index1,T * const lambda0,T * const lambda1,T ratio,int64_t output_index,int64_t input_size,int64_t output_size,bool align_corners)182 inline void ComputeSourceIndexAndLambda(int64_t *const input_index0, int64_t *const input_index1, T *const lambda0,
183 T *const lambda1, T ratio, int64_t output_index, int64_t input_size,
184 int64_t output_size, bool align_corners) {
185 if (output_size == input_size) {
186 // scale_factor = 1
187 *input_index0 = output_index;
188 *input_index1 = output_index;
189 *lambda0 = static_cast<T>(1);
190 *lambda1 = static_cast<T>(0);
191 } else {
192 const T real_input_index = AreaPixelComputeSourceIndex<T>(ratio, output_index, align_corners);
193 *input_index0 = static_cast<int64_t>(real_input_index);
194 int64_t offset = (*input_index0 < input_size - 1) ? 1 : 0;
195 *input_index1 = *input_index0 + offset;
196 *lambda1 = real_input_index - static_cast<T>(*input_index0);
197 constexpr T one = 1.0;
198 *lambda0 = one - *lambda1;
199 }
200 }
201
202 BACKEND_EXPORT void CheckSliceValid(const std::vector<int64_t> &start, const std::vector<int64_t> &stop,
203 const std::vector<int64_t> &step, const std::vector<int64_t> &input_shape);
204 BACKEND_EXPORT size_t CalOffset(const std::vector<int64_t> &start, const std::vector<int64_t> &stop,
205 const std::vector<int64_t> &dim_offset);
206 BACKEND_EXPORT std::vector<int64_t> CalDimOffset(const std::vector<int64_t> &input_shape);
207 BACKEND_EXPORT size_t GetCopySize(const std::vector<int64_t> &dim_offset, const std::vector<int64_t> &start,
208 const std::vector<int64_t> &stop);
209
210 BACKEND_EXPORT std::pair<MatrixDiag::Alignment, MatrixDiag::Alignment> GetAlignments(const std::string &alignment);
211
212 namespace broadcast_utils {
213 BACKEND_EXPORT bool AlignedBroadCastShape(size_t align_rank, std::vector<size_t> *broadcast, std::vector<size_t> *lhs,
214 std::vector<size_t> *rhs);
215 } // namespace broadcast_utils
216
217 #define CHECK_KERNEL_WORKSPACE_SIZE(actual_size, expect_size, kernel_name) \
218 do { \
219 if ((actual_size) != (expect_size)) { \
220 MS_LOG(EXCEPTION) << (kernel_name) << " requires " << (expect_size) << " workspace, but got " << (actual_size) \
221 << "."; \
222 } \
223 } while (0)
224 } // namespace kernel
225 } // namespace mindspore
226
227 #endif // MINDSPORE_CCSRC_KERNEL_OPS_UTILS_H_
228