Compute Library
 21.02
GCPoolingLayerKernel.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2020 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  */
25 
32 #include "arm_compute/core/Utils.h"
38 #include "support/StringSupport.h"
39 
40 #include <set>
41 #include <string>
42 #include <tuple>
43 
44 using namespace arm_compute;
45 
46 namespace
47 {
48 // Internal window config info
49 using GCPoolingConfig = std::pair<unsigned int, BorderSize>; //num_elems_processed_per_iteration, border_size
50 
51 void auto_init(const ITensorInfo *input, ITensorInfo *output, unsigned int pooled_w, unsigned int pooled_h)
52 {
54  output_shape.set(0, pooled_w);
55  output_shape.set(1, pooled_h);
56 
57  auto_init_if_empty(*output, input->clone()->set_tensor_shape(output_shape));
58 }
59 
60 Status validate_arguments(const ITensorInfo *input, const ITensorInfo *output, const PoolingLayerInfo &pool_info, const ITensorInfo *indices)
61 {
63  ARM_COMPUTE_RETURN_ERROR_ON_MSG(indices, "Indices not supported in GLES backend");
66  "Unsupported combination of parameters!");
68 
69  const bool is_global_pooling = pool_info.is_global_pooling;
70  const unsigned int pool_size = is_global_pooling ? input->tensor_shape().x() : pool_info.pool_size.width;
71 
72  ARM_COMPUTE_RETURN_ERROR_ON_MSG(is_global_pooling && (input->tensor_shape().x() != input->tensor_shape().y()),
73  "Global pooling is supported only with rectangular inputs!");
74  ARM_COMPUTE_RETURN_ERROR_ON_MSG(!is_global_pooling && ((pool_info.pad_stride_info.pad().first >= pool_size) || (pool_info.pad_stride_info.pad().second >= pool_size)),
75  "Invalid pool size and pool pad combination!");
76  ARM_COMPUTE_RETURN_ERROR_ON_MSG(pool_info.pool_size.width != pool_info.pool_size.height, "Invalid Pool size, width not equal to height!");
77 
78  // Checks performed when output is configured
79  if(output->total_size() != 0)
80  {
82 
83  unsigned int pooled_w = 0;
84  unsigned int pooled_h = 0;
85  std::tie(pooled_w, pooled_h) = scaled_dimensions(input->dimension(0),
86  input->dimension(1),
87  pool_size,
88  pool_size,
89  pool_info.pad_stride_info);
90  ARM_COMPUTE_RETURN_ERROR_ON_MSG((output->dimension(0) != pooled_w) || (output->dimension(1) != pooled_h),
91  "Invalid output pooling dimensions!");
92  }
93 
94  return Status{};
95 }
96 
97 std::tuple<Status, Window, GCPoolingConfig> validate_and_configure_window(ITensorInfo *input, ITensorInfo *output, const PoolingLayerInfo &pool_info)
98 {
99  int pool_pad_x = 0;
100  int pool_pad_y = 0;
101  int pool_stride_x = 0;
102  int pool_stride_y = 0;
103  unsigned int pooled_w = 0;
104  unsigned int pooled_h = 0;
105  int pool_size = pool_info.pool_size.width;
106  const PadStrideInfo pad_stride_info = pool_info.pad_stride_info;
107  std::tie(pool_pad_x, pool_pad_y) = pad_stride_info.pad();
108  std::tie(pool_stride_x, pool_stride_y) = pad_stride_info.stride();
109 
110  ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
111 
112  // Update pool size in case of global pooling
113  pool_size = pool_info.is_global_pooling ? input->dimension(0) : pool_size;
114 
115  // Check output dimensions
116  std::tie(pooled_w, pooled_h) = scaled_dimensions(input->dimension(0),
117  input->dimension(1),
118  pool_size,
119  pool_size,
120  pad_stride_info);
121 
122  auto_init(input, output, pooled_w, pooled_h);
123 
124  BorderSize border_size = BorderSize(pool_pad_y, pool_pad_x);
125 
126  const int input_width = input->dimension(0);
127  const int input_height = input->dimension(1);
128 
129  unsigned int num_elems_processed_per_iteration = 1;
130 
131  // Create kernel
132  if(pool_size == 3)
133  {
134  // Check if we have pool3x3 with stride_x less equal than 3. In these cases, run an optimized OpenGLES kernel where
135  // each thread computes 4 output elements
136  const bool is_pool3x3_stride_le3 = (pool_size == 3) && (pool_stride_x <= 3);
137 
138  int num_elems_read_per_iteration = pool_size;
139 
140  if(input->data_type() == DataType::F32)
141  {
142  if(is_pool3x3_stride_le3)
143  {
144  // Change the number of elements processed and number of elements read per iteration for pooling 3x3 with stride less equal than 3
145  num_elems_processed_per_iteration = 4;
146  num_elems_read_per_iteration = pool_size * (pool_stride_x + 1);
147  }
148  }
149  else
150  {
151  if(is_pool3x3_stride_le3)
152  {
153  num_elems_processed_per_iteration = 4;
154  }
155  else
156  {
157  num_elems_processed_per_iteration = 2;
158  }
159  }
160 
161  const int upper_bound_w = ((pooled_w - 1) * pool_stride_x - pool_pad_x + num_elems_read_per_iteration) - input_width;
162  const int upper_bound_h = ((pooled_h - 1) * pool_stride_y - pool_pad_y + pool_size) - input_height;
163 
164  border_size.right = std::max(upper_bound_w, pool_pad_x);
165  border_size.bottom = std::max(upper_bound_h, pool_pad_y);
166  }
167  else // Run general case
168  {
169  if(input->data_type() == DataType::F32)
170  {
171  num_elems_processed_per_iteration = 1;
172  }
173  else
174  {
175  num_elems_processed_per_iteration = 2;
176  }
177 
178  const int upper_bound_w = ((pooled_w - 1) * pool_stride_x - pool_pad_x + pool_size) - input_width;
179  const int upper_bound_h = ((pooled_h - 1) * pool_stride_y - pool_pad_y + pool_size) - input_height;
180 
181  border_size.right = std::max(upper_bound_w, pool_pad_x);
182  border_size.bottom = std::max(upper_bound_h, pool_pad_y);
183  }
184  // Configure kernel window
185  Window win = calculate_max_window(*output, Steps(num_elems_processed_per_iteration));
186 
187  if(input->data_type() == DataType::F32)
188  {
189  AccessWindowStatic input_access(input, -pool_pad_x, -pool_pad_y, input_width + border_size.right, input_height + border_size.bottom);
190  AccessWindowHorizontal output_access(output, 0, num_elems_processed_per_iteration);
191  bool window_changed = update_window_and_padding(win, input_access, output_access);
192  output_access.set_valid_region(win, ValidRegion(Coordinates(), output->tensor_shape()));
193  Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
194  return std::make_tuple(err, win, GCPoolingConfig(num_elems_processed_per_iteration, border_size));
195  }
196  else
197  {
198  // Calculate output right and bottom border
199  const int output_width = output->dimension(0);
200  const int output_height = output->dimension(1);
201  const int output_padding_right = ceil_to_multiple(output_width, num_elems_processed_per_iteration) - output_width;
202  const int output_padding_bottom = ceil_to_multiple(output_height, 1) - output_height;
203 
204  const int input_total_width = std::max(int(input->padding().left), int(pool_pad_x)) + input_width + std::max(int(input->padding().right), int(pool_pad_x));
205  const int input_padding_right = ceil_to_multiple(input_total_width, num_elems_processed_per_iteration) - input_width - pool_pad_x;
206  const int input_total_height = std::max(int(input->padding().top), int(pool_pad_y)) + input_height + std::max(int(input->padding().bottom), int(pool_pad_y));
207  const int input_padding_bottom = input_total_height - input_height - pool_pad_y;
208 
209  // Configure kernel window
210  AccessWindowStatic input_access(input, -pool_pad_x, -pool_pad_y, input_width + input_padding_right, input_height + input_padding_bottom);
211  AccessWindowStatic output_access(output, 0, 0, output_width + output_padding_right, output_height + output_padding_bottom);
212  bool window_changed = update_window_and_padding(win, input_access, output_access);
213  output_access.set_valid_region(win, ValidRegion(Coordinates(), output->tensor_shape()));
214  Status err = (window_changed) ? ARM_COMPUTE_CREATE_ERROR(ErrorCode::RUNTIME_ERROR, "Insufficient Padding!") : Status{};
215  return std::make_tuple(err, win, GCPoolingConfig(num_elems_processed_per_iteration, border_size));
216  }
217 }
218 } // namespace
219 
221  : _input(nullptr), _output(nullptr), _indices(nullptr), _pool_info(), _border_size(0), _num_elems_processed_per_iteration(1)
222 {
223 }
224 
226 {
227  return _border_size;
228 }
229 
230 void GCPoolingLayerKernel::configure(const IGCTensor *input, IGCTensor *output, const PoolingLayerInfo &pool_info, IGCTensor *indices)
231 {
232  int pool_pad_x = 0;
233  int pool_pad_y = 0;
234  int pool_stride_x = 0;
235  int pool_stride_y = 0;
236  unsigned int pooled_w = 0;
237  unsigned int pooled_h = 0;
238  const PoolingType pool_type = pool_info.pool_type;
239  int pool_size = pool_info.pool_size.width;
240  const PadStrideInfo pad_stride_info = pool_info.pad_stride_info;
241  const bool exclude_padding = pool_info.exclude_padding;
242  std::tie(pool_pad_x, pool_pad_y) = pad_stride_info.pad();
243  std::tie(pool_stride_x, pool_stride_y) = pad_stride_info.stride();
244 
245  ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
246 
247  // Update pool size in case of global pooling
248  pool_size = pool_info.is_global_pooling ? input->info()->dimension(0) : pool_size;
249 
250  // Check output dimensions
251  std::tie(pooled_w, pooled_h) = scaled_dimensions(input->info()->dimension(0),
252  input->info()->dimension(1),
253  pool_size,
254  pool_size,
255  pad_stride_info);
256 
257  auto_init(input->info(), output->info(), pooled_w, pooled_h);
258 
259  ARM_COMPUTE_ERROR_THROW_ON(validate_arguments(input->info(), output->info(), pool_info, (indices) ? indices->info() : nullptr));
260 
261  // Set instance variables
262  _input = input;
263  _output = output;
264  _pool_info = pool_info;
265  _indices = indices;
266  // Set build options
267  std::set<std::string> build_opts;
268  build_opts.emplace("#define LOCAL_SIZE_X " + support::cpp11::to_string(1));
269  build_opts.emplace("#define LOCAL_SIZE_Y " + support::cpp11::to_string(1));
270  build_opts.emplace("#define LOCAL_SIZE_Z " + support::cpp11::to_string(1));
271  if(input->info()->data_type() == DataType::F32)
272  {
273  build_opts.insert("#define DATA_TYPE_FP32");
274  }
275  else
276  {
277  build_opts.insert("#define DATA_TYPE_FP16");
278  }
279  if(exclude_padding)
280  {
281  build_opts.emplace("#define EXCLUDE_PADDING");
282  }
283  build_opts.emplace(("#define POOL_" + string_from_pooling_type(pool_type)));
284  build_opts.emplace(("#define STRIDE_X " + support::cpp11::to_string(pool_stride_x)));
285  build_opts.emplace(("#define MAX_WIDTH " + support::cpp11::to_string(input->info()->dimension(0) + (exclude_padding ? 0 : pool_pad_x))));
286  build_opts.emplace(("#define MAX_HEIGHT " + support::cpp11::to_string(input->info()->dimension(1) + (exclude_padding ? 0 : pool_pad_y))));
287  build_opts.emplace(("#define STRIDE_Y " + support::cpp11::to_string(pool_stride_y)));
288  build_opts.emplace(("#define PAD_X " + support::cpp11::to_string(pool_pad_x)));
289  build_opts.emplace(("#define PAD_Y " + support::cpp11::to_string(pool_pad_y)));
290 
291  // Create kernel
292  if((pool_size == 2) || (pool_size == 3) || (pool_size == 7))
293  {
294  // Check if we have pool3x3 with stride_x less equal than 3. In these cases, run an optimized OpenGLES kernel where
295  // each thread computes 4 output elements
296  const bool is_pool3x3_stride_le3 = (pool_size == 3) && (pool_stride_x <= 3);
297 
298  std::string kernel_name = "pooling_layer_" + support::cpp11::to_string(pool_size);
299  if(is_pool3x3_stride_le3)
300  {
301  build_opts.insert("#define POOLING_LAYER_3_OPTIMIZED");
302  _kernel = static_cast<GCKernel>(GCKernelLibrary::get().create_kernel(kernel_name + "_optimized", build_opts));
303  }
304  else
305  {
306  build_opts.insert("#define POOLING_LAYER_" + support::cpp11::to_string(pool_size));
307  _kernel = static_cast<GCKernel>(GCKernelLibrary::get().create_kernel(kernel_name, build_opts));
308  }
309  }
310  else // Run general case
311  {
312  build_opts.emplace(("#define POOL_SIZE " + support::cpp11::to_string(pool_size)));
313 
314  build_opts.insert("#define POOLING_LAYER_N");
315  _kernel = static_cast<GCKernel>(GCKernelLibrary::get().create_kernel("pooling_layer_n", build_opts));
316  }
317  // Configure kernel window
318  auto win_config = validate_and_configure_window(input->info(), output->info(), pool_info);
319  ARM_COMPUTE_ERROR_THROW_ON(std::get<0>(win_config));
320 
321  IGCKernel::configure(std::get<1>(win_config));
322  GCPoolingConfig pooling_config = std::get<2>(win_config);
323  _num_elems_processed_per_iteration = pooling_config.first;
324  _border_size = pooling_config.second;
325 }
326 
327 Status GCPoolingLayerKernel::validate(const ITensorInfo *input, const ITensorInfo *output, const PoolingLayerInfo &pool_info, const ITensorInfo *indices)
328 {
329  ARM_COMPUTE_RETURN_ON_ERROR(validate_arguments(input, output, pool_info, indices));
330  ARM_COMPUTE_RETURN_ON_ERROR(std::get<0>(validate_and_configure_window(input->clone().get(), output->clone().get(), pool_info)));
331 
332  return Status{};
333 }
334 
336 {
339 
340  unsigned int pool_pad_x;
341  unsigned int pool_pad_y;
342  unsigned int pool_stride_x;
343  unsigned int pool_stride_y;
344  std::tie(pool_pad_x, pool_pad_y) = _pool_info.pad_stride_info.pad();
345  std::tie(pool_stride_x, pool_stride_y) = _pool_info.pad_stride_info.stride();
346 
347  _kernel.use();
348 
349  _output->set_needs_shifting(true);
350 
351  Window window_collapsed = window.collapse_if_possible(IGCKernel::window(), Window::DimZ);
352 
353  Window slice = window_collapsed.first_slice_window_3D();
354  Window slice_in_orig = window_collapsed.first_slice_window_3D();
355 
356  slice.shift(Window::DimX, -(_output->info()->padding()).left);
357 
358  do
359  {
360  // Upsample input by pool size
361  Window in_slice(slice_in_orig); // NOLINT
362  in_slice.set(Window::DimX, Window::Dimension(in_slice.x().start() - pool_pad_x, in_slice.x().end() * pool_stride_x, pool_stride_x * _num_elems_processed_per_iteration));
363  in_slice.set(Window::DimY, Window::Dimension(in_slice.y().start() - pool_pad_y, in_slice.y().end() * pool_stride_y, pool_stride_y));
364 
365  // Set inputs
366  unsigned int idx = 0;
367  add_3D_tensor_argument(idx, _input, 1, in_slice);
368  add_3D_tensor_argument(idx, _output, 2, slice);
369 
370  _kernel.update_shader_params();
371  enqueue(*this, slice);
372  }
373  while(window_collapsed.slide_window_slice_3D(slice) && window_collapsed.slide_window_slice_3D(slice_in_orig));
374 }
unsigned int top
top of the border
Definition: Types.h:375
Window calculate_max_window(const ValidRegion &valid_region, const Steps &steps, bool skip_border, BorderSize border_size)
void configure(const IGCTensor *input, IGCTensor *output, const PoolingLayerInfo &pool_info, IGCTensor *indices=nullptr)
Set the input and output tensors.
const Window & window() const
The maximum window the kernel can be executed on.
Definition: IKernel.cpp:28
Shape of a tensor.
Definition: TensorShape.h:39
void add_3D_tensor_argument(unsigned int &idx, const IGCTensor *tensor, const unsigned int binding_point, const Window &window)
Add the passed 3D tensor&#39;s parameters to the object&#39;s kernel&#39;s arguments starting from the index idx...
Definition: IGCKernel.cpp:132
static Status validate(const ITensorInfo *input, const ITensorInfo *output, const PoolingLayerInfo &pool_info, const ITensorInfo *indices=nullptr)
Static function to check if given info will lead to a valid configuration of GCPoolingLayerKernel.
void enqueue(IGCKernel &kernel, const Window &window, const gles::NDRange &lws=gles::NDRange(1U, 1U, 1U))
Add the kernel to the command queue with the given window.
Definition: IGCKernel.cpp:41
virtual size_t dimension(size_t index) const =0
Return the size of the requested dimension.
void shift(size_t dimension, int shift_value)
Shift the values of a given dimension by the given shift_value.
Definition: Window.inl:133
Container for 2D border size.
Definition: Types.h:273
#define ARM_COMPUTE_RETURN_ON_ERROR(status)
Checks if a status contains an error and returns it.
Definition: Error.h:204
std::string to_string(T &&value)
Convert integer and float values to string.
virtual DataType data_type() const =0
Data type used for each element of the tensor.
1 channel, 1 F32 per channel
Store the tensor&#39;s metadata.
Definition: ITensorInfo.h:40
Interface for GLES Compute tensor.
Definition: IGCTensor.h:35
#define ARM_COMPUTE_ERROR_THROW_ON(status)
Definition: Error.h:455
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
GCKernel class.
Status class.
Definition: Error.h:52
#define ARM_COMPUTE_RETURN_ERROR_ON(cond)
If the condition is true, an error is returned.
Definition: Error.h:296
int pool_stride_x
Copyright (c) 2017-2021 Arm Limited.
size_t height
Height of the image region or rectangle.
Definition: Size2D.h:90
1 channel, 1 F16 per channel
std::pair< unsigned int, unsigned int > scaled_dimensions(int width, int height, int kernel_width, int kernel_height, const PadStrideInfo &pad_stride_info, const Size2D &dilation=Size2D(1U, 1U))
Returns expected width and height of output scaled tensor depending on dimensions rounding mode...
Definition: Utils.cpp:419
Implementation of a static rectangular access pattern.
#define ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(...)
Definition: Validate.h:163
T x() const
Alias to access the size of the first dimension.
Definition: Dimensions.h:87
static constexpr size_t DimX
Alias for dimension 0 also known as X dimension.
Definition: Window.h:43
bool update_window_and_padding(Window &win, Ts &&... patterns)
Update window and padding size for each of the access patterns.
Definition: WindowHelpers.h:46
Window collapse_if_possible(const Window &full_window, size_t first, size_t last, bool *has_collapsed=nullptr) const
Collapse the dimensions between first and last if possible.
Definition: Window.inl:68
bool padding_is_symmetric() const
Check whether the padding is symmetric.
Definition: Types.h:778
virtual const TensorShape & tensor_shape() const =0
Size for each dimension of the tensor.
auto ceil_to_multiple(S value, T divisor) -> decltype(((value+divisor - 1)/divisor) *divisor)
Computes the smallest number larger or equal to value that is a multiple of divisor.
Definition: Utils.h:71
Manages all the GLES kernels compilation and caching, provides accessors for the GLES Context...
Class to describe a number of elements in each dimension.
Definition: Steps.h:40
void set_needs_shifting(bool needs_shifting)
Set the flag indicating whether or not a tensor needs shifting.
Definition: IGCTensor.cpp:61
Coordinates of an item.
Definition: Coordinates.h:37
Implementation of a row access pattern.
std::pair< unsigned int, unsigned int > stride() const
Get the stride.
Definition: Types.h:770
std::string kernel_name
Pooling Layer Information struct.
Definition: Types.h:1214
BorderSize border_size() const override
The size of the border for that kernel.
bool auto_init_if_empty(ITensorInfo &info, const TensorShape &shape, int num_channels, DataType data_type, QuantizationInfo quantization_info=QuantizationInfo())
Auto initialize the tensor info (shape, number of channels and data type) if the current assignment i...
virtual std::unique_ptr< T > clone() const =0
Provide a clone of the current object of class T.
void run(const Window &window) override
Enqueue the OpenGL ES shader to process the given window.
virtual ITensorInfo * info() const =0
Interface to be implemented by the child class to return the tensor&#39;s metadata.
Padding and stride information class.
Definition: Types.h:722
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
bool slide_window_slice_3D(Window &slice) const
Slide the passed 3D window slice.
Definition: Window.h:335
unsigned int right
right of the border
Definition: Types.h:376
#define ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(k)
Definition: Validate.h:941
bool is_data_type_quantized_asymmetric(DataType dt)
Check if a given data type is of asymmetric quantized type.
Definition: Utils.h:1190
static constexpr size_t DimY
Alias for dimension 1 also known as Y dimension.
Definition: Window.h:45
Wrapper to configure the Khronos EGL and OpenGL ES C header.
static GCKernelLibrary & get()
Get the static instance of GCKernelLibrary.
PoolingType
Available pooling types.
Definition: Types.h:610
PadStrideInfo pad_stride_info
Definition: Types.h:1302
virtual size_t total_size() const =0
Returns the total size of the tensor in bytes.
#define ARM_COMPUTE_CREATE_ERROR(error_code, msg)
Creates an error with a given message.
Definition: Error.h:159
size_t width
Width of the image region or rectangle.
Definition: Size2D.h:89
static constexpr size_t DimZ
Alias for dimension 2 also known as Z dimension.
Definition: Window.h:47
#define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(...)
Definition: Validate.h:545
constexpr const Dimension & y() const
Alias to access the second dimension of the window.
Definition: Window.h:154
#define ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(t, c,...)
Definition: Validate.h:792
Status validate_arguments(const ITensorInfo *input, const ITensorInfo *bias, const ITensorInfo *output, const GEMMLowpOutputStageInfo *output_stage)
Size2D pool_size
GCKernel create_kernel(const std::string &shader_name, const StringSet &build_options_set={}) const
Creates a kernel from the kernel library.
unsigned int num_elems_processed_per_iteration
#define ARM_COMPUTE_RETURN_ERROR_ON_MSG(cond, msg)
If the condition is true, an error is returned.
Definition: Error.h:244
#define ARM_COMPUTE_ERROR_ON_NULLPTR(...)
Definition: Validate.h:161
std::pair< unsigned int, unsigned int > pad() const
Get the padding.
Definition: Types.h:788
T y() const
Alias to access the size of the second dimension.
Definition: Dimensions.h:92
Container for valid region of a window.
Definition: Types.h:188
constexpr int end() const
Return the end of the dimension.
Definition: Window.h:99
Window first_slice_window_3D() const
First 3D slice of the window.
Definition: Window.h:291
const std::string & string_from_pooling_type(PoolingType type)
Translates a given pooling type to a string.
Definition: Utils.cpp:248
constexpr int start() const
Return the start of the dimension.
Definition: Window.h:94
Describe a multidimensional execution window.
Definition: Window.h:39
TensorShape & set(size_t dimension, size_t value, bool apply_dim_correction=true, bool increase_dim_unit=true)
Accessor to set the value of one of the dimensions.
Definition: TensorShape.h:79
#define ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(f, s)
Definition: Validate.h:205
SimpleTensor< T > slice(const SimpleTensor< T > &src, Coordinates starts, Coordinates ends)
constexpr const Dimension & x() const
Alias to access the first dimension of the window.
Definition: Window.h:145