Compute Library
 21.02
list.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #ifndef SRC_CORE_NEON_KERNELS_SCALE_LIST_H
25 #define SRC_CORE_NEON_KERNELS_SCALE_LIST_H
26 
30 #include "src/core/NEON/NEMath.h"
35 #include "support/Rounding.h"
36 
37 namespace arm_compute
38 {
39 namespace cpu
40 {
41 #define DECLARE_SCALE_KERNEL(func_name) \
42  void func_name(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, \
43  InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, \
44  bool align_corners, const Window &window)
45 
48 
49 #undef DECLARE_SCALE_KERNEL
50 
51 template <typename T>
52 void nearest_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, float sampling_offset,
53  bool align_corners, const Window &window)
54 {
55  const size_t in_stride_c = src->info()->dimension(0) + src->info()->padding().left + src->info()->padding().right;
56  const size_t in_stride_w = src->info()->dimension(1) + src->info()->padding().top + src->info()->padding().bottom;
57  const size_t in_stride_wc = in_stride_w * in_stride_c;
58  const size_t in_dim_h = src->info()->dimension(2);
59 
60  // Compute the ratio between source height and destination height
61  const auto hr = scale_utils::calculate_resize_ratio(in_dim_h, dst->info()->dimension(2), align_corners);
62  const auto window_start_x = static_cast<int32_t>(window.x().start());
63  const auto window_end_x = static_cast<int32_t>(window.x().end());
64  const int window_step_x = 16 / sizeof(T);
65 
66  Window win(window);
67  win.set(Window::DimX, Window::Dimension(0, 1, 1));
68  Iterator out(dst, win);
69 
70  const uint8_t *in_ptr_start = src->buffer() + src->info()->offset_first_element_in_bytes();
71  const unsigned int in_stride_bytes_hwc = src->info()->strides_in_bytes()[3];
72 
73  execute_window_loop(win, [&](const Coordinates & id)
74  {
75  const int32_t offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z()))) * in_stride_c;
76  const auto in_hi = static_cast<int>(align_corners ? utils::rounding::round_half_away_from_zero((id.z() + sampling_offset) * hr) : std::floor((id.z() + sampling_offset) * hr));
77  const int offset_row = in_hi * in_stride_wc;
78  int32_t x = window_start_x;
79  const T *in_ptr = reinterpret_cast<const T *>(in_ptr_start + in_stride_bytes_hwc * id[3]);
80 
81  for(; x <= window_end_x - window_step_x; x += window_step_x)
82  {
83  wrapper::vstore(reinterpret_cast<T *>(out.ptr()) + x,
84  wrapper::vloadq(in_ptr + offset + offset_row + x));
85  }
86  for(; x < window_end_x; ++x)
87  {
88  *(reinterpret_cast<T *>(out.ptr()) + x) = *(in_ptr + offset + offset_row + x);
89  }
90  },
91  out);
92 }
93 
94 template <typename T>
95 void bilinear_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy,
96  BorderMode border_mode, PixelValue constant_border_value, float sampling_offset,
97  bool align_corners, const Window &window)
98 {
99  // Compute the ratio between source height and destination height
100  const auto hr = scale_utils::calculate_resize_ratio(src->info()->dimension(2), dst->info()->dimension(2), align_corners);
101 
102  Iterator out(dst, window);
103  const int in_stride_c = src->info()->dimension(0) + src->info()->padding().left + src->info()->padding().right;
104  const int in_dim_w = src->info()->dimension(1);
105  const int in_dim_h = src->info()->dimension(2);
106  const int in_stride_wc = in_stride_c * (in_dim_w + src->info()->padding().top + src->info()->padding().bottom);
107 
108  // Don't increment in Y and Z direction for the input tensor
109  // A pointer to the start of this plane is needed as base for the precomputed offsets
110  Window win_in(window);
111  win_in.set(Window::DimY, Window::Dimension(0, 0, 0));
112  win_in.set(Window::DimZ, Window::Dimension(0, 0, 0));
113  Iterator in(src, win_in);
114 
115  if(border_mode == BorderMode::CONSTANT)
116  {
117 #ifdef __ARM_FEATURE_FP16_VECTOR_ARITHMETIC
118  using ConstType = typename std::conditional<std::is_same<T, float16_t>::value, half, T>::type;
119 #else /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
120  using ConstType = T;
121 #endif /* __ARM_FEATURE_FP16_VECTOR_ARITHMETIC */
122  const T const_border_value = static_cast<T>(constant_border_value.get<ConstType>());
123  execute_window_loop(window, [&](const Coordinates & id)
124  {
125  const auto offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z())));
126  const auto dx_val = *reinterpret_cast<const float *>(dx->ptr_to_element(Coordinates(id.y(), id.z())));
127  const auto dy_val = *reinterpret_cast<const float *>(dy->ptr_to_element(Coordinates(id.y(), id.z())));
128  const int32_t in_hi = std::floor((id.z() + sampling_offset) * hr - sampling_offset);
129  const T *in_ptr = reinterpret_cast<const T *>(in.ptr()) + offset * in_stride_c + in_hi * in_stride_wc;
130 
131  const auto a00 = (0 <= offset && offset < in_dim_w && 0 <= in_hi && in_hi < in_dim_h) ? *in_ptr : const_border_value;
132  const auto a01 = (-1 <= offset && offset < in_dim_w - 1 && 0 <= in_hi && in_hi < in_dim_h) ? *(in_ptr + in_stride_c) : const_border_value;
133  const auto a10 = (0 <= offset && offset < in_dim_w && -1 <= in_hi && in_hi < in_dim_h - 1) ? *(in_ptr + in_stride_wc) : const_border_value;
134  const auto a11 = (-1 <= offset && offset < in_dim_w - 1 && -1 <= in_hi && in_hi < in_dim_h - 1) ? *(in_ptr + in_stride_c + in_stride_wc) : const_border_value;
135 
136  *reinterpret_cast<T *>(out.ptr()) = static_cast<T>(scale_helpers::delta_bilinear(a00, a01, a10, a11, dx_val, dy_val));
137  },
138  in, out);
139  }
140  else if(border_mode == BorderMode::REPLICATE)
141  {
142  execute_window_loop(window, [&](const Coordinates & id)
143  {
144  const auto offset = *reinterpret_cast<const int32_t *>(offsets->ptr_to_element(Coordinates(id.y(), id.z())));
145  const auto dx_val = *reinterpret_cast<const float *>(dx->ptr_to_element(Coordinates(id.y(), id.z())));
146  const auto dy_val = *reinterpret_cast<const float *>(dy->ptr_to_element(Coordinates(id.y(), id.z())));
147  const int in_hi = std::floor((id.z() + sampling_offset) * hr - sampling_offset);
148 
149  auto clamped_w = utility::clamp<int>(offset, 0, in_dim_w - 1);
150  auto clamped_w1 = utility::clamp<int>(offset + 1, 0, in_dim_w - 1);
151  auto clamped_h = utility::clamp<int>(in_hi, 0, in_dim_h - 1);
152  auto clamped_h1 = utility::clamp<int>(in_hi + 1, 0, in_dim_h - 1);
153 
154  const auto a00 = *(reinterpret_cast<const T *>(in.ptr()) + clamped_w * in_stride_c + clamped_h * in_stride_wc);
155  const auto a01 = *(reinterpret_cast<const T *>(in.ptr()) + clamped_w1 * in_stride_c + clamped_h * in_stride_wc);
156  const auto a10 = *(reinterpret_cast<const T *>(in.ptr()) + clamped_w * in_stride_c + clamped_h1 * in_stride_wc);
157  const auto a11 = *(reinterpret_cast<const T *>(in.ptr()) + clamped_w1 * in_stride_c + clamped_h1 * in_stride_wc);
158 
159  *reinterpret_cast<T *>(out.ptr()) = static_cast<T>(scale_helpers::delta_bilinear(a00, a01, a10, a11, dx_val, dy_val));
160  },
161  in, out);
162  }
163  else
164  {
165  ARM_COMPUTE_ERROR("Not implemented");
166  }
167 }
168 
169 template <typename T>
170 void common_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy,
171  InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, float sampling_offset,
172  bool align_corners, const Window &window)
173 {
174  if(policy == InterpolationPolicy::BILINEAR)
175  {
176  bilinear_neon_scale<T>(src, dst, offsets, dx, dy, border_mode, constant_border_value, sampling_offset, align_corners, window);
177  }
178  else if(policy == InterpolationPolicy::NEAREST_NEIGHBOR)
179  {
180  nearest_neon_scale<T>(src, dst, offsets, sampling_offset, align_corners, window);
181  }
182 }
183 } // namespace cpu
184 } // namespace arm_compute
185 
186 #endif /* SRC_CORE_NEON_KERNELS_SCALE_LIST_H */
BorderMode
Methods available to handle borders.
Definition: Types.h:265
__global uchar * offset(const Image *img, int x, int y)
Get the pointer position of a Image.
Definition: helpers.h:846
unsigned int top
top of the border
Definition: Types.h:375
Class describing the value of a pixel for any image format.
Definition: PixelValue.h:34
InterpolationPolicy
Interpolation method.
Definition: Types.h:392
uint8_t * ptr_to_element(const Coordinates &id) const
Return a pointer to the element at the passed coordinates.
Definition: ITensor.h:63
virtual size_t dimension(size_t index) const =0
Return the size of the requested dimension.
#define ARM_COMPUTE_ERROR(msg)
Print the given message then throw an std::runtime_error.
Definition: Error.h:352
void get(uint8_t &v) const
Interpret the pixel value as a U8.
Definition: PixelValue.h:241
uint8x16_t vloadq(const uint8_t *ptr)
Definition: load.h:58
half_float::half half
16-bit floating point type
Definition: Types.h:46
Output values are defined by bilinear interpolation between the pixels.
Describe one of the image&#39;s dimensions with a start, end and step.
Definition: Window.h:77
unsigned int bottom
bottom of the border
Definition: Types.h:377
void nearest_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, float sampling_offset, bool align_corners, const Window &window)
Definition: list.h:52
T round_half_away_from_zero(T value)
Round floating-point value with half value rounding away from zero.
Definition: Rounding.h:106
Output values are defined to match the source pixel whose center is nearest to the sample position...
decltype(strategy::transforms) typedef type
Interface for Neon tensor.
Definition: ITensor.h:36
SimpleTensor< float > src
Definition: DFT.cpp:155
Copyright (c) 2017-2021 Arm Limited.
static constexpr size_t DimX
Alias for dimension 0 also known as X dimension.
Definition: Window.h:43
Coordinates of an item.
Definition: Coordinates.h:37
virtual uint8_t * buffer() const =0
Interface to be implemented by the child class to return a pointer to CPU memory. ...
void qasymm8_signed_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, bool align_corners, const Window &window)
virtual ITensorInfo * info() const =0
Interface to be implemented by the child class to return the tensor&#39;s metadata.
constexpr uint8_t * ptr() const
Return a pointer to the current pixel.
Definition: Helpers.inl:139
void set(size_t dimension, const Dimension &dim)
Set the values of a given dimension.
Definition: Window.inl:49
virtual PaddingSize padding() const =0
Padding of tensor.
unsigned int left
left of the border
Definition: Types.h:378
unsigned int right
right of the border
Definition: Types.h:376
void bilinear_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, bool align_corners, const Window &window)
Definition: list.h:95
virtual size_t offset_first_element_in_bytes() const =0
The offset from the beginning of the memory allocation to the first element of the tensor...
static constexpr size_t DimY
Alias for dimension 1 also known as Y dimension.
Definition: Window.h:45
static constexpr size_t DimZ
Alias for dimension 2 also known as Z dimension.
Definition: Window.h:47
Pixels outside the image are assumed to have the same value as the closest image pixel.
void vstore(uint8_t *ptr, uint8x8_t val)
Definition: store.h:39
void execute_window_loop(const Window &w, L &&lambda_function, Ts &&... iterators)
Iterate through the passed window, automatically adjusting the iterators and calling the lambda_funct...
Definition: Helpers.inl:77
#define DECLARE_SCALE_KERNEL(func_name)
Definition: list.h:41
void common_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, bool align_corners, const Window &window)
Definition: list.h:170
float calculate_resize_ratio(size_t input_size, size_t output_size, bool align_corners=false)
Returns resize ratio between input and output with consideration of aligned corners.
Definition: ScaleUtils.cpp:27
Includes all wrapper headers at once.
virtual const Strides & strides_in_bytes() const =0
The strides in bytes for accessing each dimension of the tensor.
constexpr int end() const
Return the end of the dimension.
Definition: Window.h:99
Iterator updated by execute_window_loop for each window element.
Definition: Helpers.h:46
float delta_bilinear(float a00, float a01, float a10, float a11, float dx_val, float dy_val)
Computes bilinear interpolation using the top-left, top-right, bottom-left, bottom-right pixels and t...
Definition: ScaleHelpers.h:343
constexpr int start() const
Return the start of the dimension.
Definition: Window.h:94
void qasymm8_neon_scale(const ITensor *src, ITensor *dst, const ITensor *offsets, const ITensor *dx, const ITensor *dy, InterpolationPolicy policy, BorderMode border_mode, PixelValue constant_border_value, float sampling_offset, bool align_corners, const Window &window)
Definition: qasymm8.cpp:135
Describe a multidimensional execution window.
Definition: Window.h:39
constexpr const Dimension & x() const
Alias to access the first dimension of the window.
Definition: Window.h:145