Compute Library
 20.02.1
NEGEMMConvolutionLayer.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 
27 #include "arm_compute/core/Utils.h"
32 
33 #include <set>
34 #include <tuple>
35 
36 namespace arm_compute
37 {
39 
41  : _weights_reshape_kernel()
42 {
43 }
44 
46 {
47  // Perform validation step
50  (biases != nullptr) ? biases->info() : nullptr,
51  output->info()));
52  const bool append_biases = (biases != nullptr) && !is_data_type_quantized_asymmetric(weights->info()->data_type());
53  const ITensor *biases_to_use = (append_biases) ? biases : nullptr;
54 
55  _weights_reshape_kernel.configure(weights, biases_to_use, output);
56 
58 }
59 
61 {
66  ARM_COMPUTE_RETURN_ERROR_ON(weights->num_dimensions() > 4);
67 
68  if(biases != nullptr)
69  {
70  const int idx_kernels = get_data_layout_dimension_index(weights->data_layout(), DataLayoutDimension::BATCHES);
73  ARM_COMPUTE_RETURN_ERROR_ON(biases->dimension(0) != weights->dimension(idx_kernels));
75  }
76 
77  if((output != nullptr) && (output->total_size() != 0))
78  {
80 
82  }
83 
84  return Status{};
85 }
86 
88 {
89  NEScheduler::get().schedule(&_weights_reshape_kernel, 3);
90 }
91 
92 NEGEMMConvolutionLayer::NEGEMMConvolutionLayer(const std::shared_ptr<IMemoryManager> &memory_manager, IWeightsManager *weights_manager)
93  : _memory_group(memory_manager), _weights_manager(weights_manager), _reshape_weights(), _reshape_weights_managed(), _im2col_kernel(), _mm_gemm(memory_manager), _mm_gemmlowp(memory_manager),
94  _col2im_kernel(), _reshape_layer(), _original_weights(nullptr), _im2col_output(), _weights_reshaped(), _gemm_output(), _tmp_output(), _data_layout(DataLayout::NCHW), _skip_im2col(false),
95  _skip_col2im(false), _is_quantized(false), _is_prepared(false)
96 {
97 }
98 
99 void NEGEMMConvolutionLayer::configure_mm(const ITensor *input, const ITensor *weights, const ITensor *biases, ITensor *output, const ActivationLayerInfo &act_info, int gemm_3d_depth)
100 {
102  ARM_COMPUTE_ERROR_THROW_ON(validate_mm(input->info(), weights->info(), biases == nullptr ? nullptr : biases->info(), output == nullptr ? nullptr : output->info(),
103  act_info, gemm_3d_depth, _skip_im2col));
104 
105  // Create GEMMInfo structure
106  const GEMMInfo &gemm_info = GEMMInfo(false, false, true /* Reshape weights only for the first run */,
107  gemm_3d_depth, _skip_im2col /* Reinterpret the input as 3D if im2col is skipped */,
108  false, GEMMLowpOutputStageInfo(), false, false, act_info);
109 
110  // Supported activations in GEMM
111  const std::set<ActivationLayerInfo::ActivationFunction> supported_acts = { ActivationLayerInfo::ActivationFunction::RELU,
114  };
115 
116  if(_is_quantized)
117  {
118  // Since we need negative offsets for computing convolution, we need to change QuantizationInfo()
119  // Extract and negate input and weights offset
120  const QuantizationInfo iqinfo = input->info()->quantization_info();
121  const QuantizationInfo wqinfo = weights->info()->quantization_info();
122  const QuantizationInfo oqinfo = (output->info()->total_size() == 0) ? iqinfo : output->info()->quantization_info();
123  const UniformQuantizationInfo uiqinfo = iqinfo.uniform();
124  const UniformQuantizationInfo uoqinfo = oqinfo.uniform();
125  const DataType data_type = input->info()->data_type();
126 
127  input->info()->set_quantization_info(QuantizationInfo(uiqinfo.scale, -uiqinfo.offset));
129  {
130  const UniformQuantizationInfo uwqinfo = wqinfo.uniform();
131  weights->info()->set_quantization_info(QuantizationInfo(uwqinfo.scale, -uwqinfo.offset));
132  }
133 
134  // Merge activation with output stage
135  PixelValue type_min{};
136  PixelValue type_max{};
137  std::tie(type_min, type_max) = get_min_max(data_type);
138  int32_t min_activation = type_min.get<int32_t>();
139  int32_t max_activation = type_max.get<int32_t>();
140 
141  if(supported_acts.count(act_info.activation()) != 0)
142  {
143  std::tie(min_activation, max_activation) = get_quantized_activation_min_max(act_info, data_type, uoqinfo);
144  }
145 
146  GEMMLowpOutputStageInfo output_info;
148  output_info.gemmlowp_offset = uoqinfo.offset;
149  output_info.gemmlowp_min_bound = min_activation;
150  output_info.gemmlowp_max_bound = max_activation;
151  output_info.is_quantized_per_channel = (weights->info()->data_type() == DataType::QSYMM8_PER_CHANNEL);
153 
154  _mm_gemmlowp.configure(input, weights, biases, output, GEMMInfo(false, false, true, gemm_3d_depth, _skip_im2col, false, output_info));
155 
156  // Revert back QuantizatioInfo as input and weights could be used in other convolution layers
157  input->info()->set_quantization_info(iqinfo);
158  weights->info()->set_quantization_info(wqinfo);
159  }
160  else
161  {
162  // Configure matrix multiply function
163  _mm_gemm.configure(input, weights, biases, output, 1.0f, 0.0f, gemm_info);
164  }
165 }
166 
167 Status NEGEMMConvolutionLayer::validate_mm(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output,
168  const ActivationLayerInfo &act_info, int gemm_3d_depth, bool skip_im2col)
169 {
170  const DataType data_type = input->data_type();
171  const bool is_quantized = is_data_type_quantized_asymmetric(data_type);
172  const bool is_activation_enabled = act_info.enabled();
173 
174  // Create GEMMInfo structure
175  const GEMMInfo gemm_info = GEMMInfo(false, false, true /* Reshape weights only for the first run */,
176  gemm_3d_depth, skip_im2col /* Reinterpret the input as 3D if im2col is skipped */,
177  false, GEMMLowpOutputStageInfo(), false, false, act_info);
178 
179  if(is_quantized)
180  {
181  // Since we need negative offsets for computing convolution, we need to change QuantizationInfo()
182  // Extract and negate input and weights offset
183  const QuantizationInfo &iqinfo = input->quantization_info();
184  const QuantizationInfo &wqinfo = weights->quantization_info();
185  const QuantizationInfo &oqinfo = (output->total_size() == 0) ? iqinfo : output->quantization_info();
186  const UniformQuantizationInfo uoqinfo = oqinfo.uniform();
187 
188  // Merge activation with output stage
189  PixelValue type_min{};
190  PixelValue type_max{};
191  std::tie(type_min, type_max) = get_min_max(data_type);
192  int32_t min_activation = type_min.get<int32_t>();
193  int32_t max_activation = type_max.get<int32_t>();
194 
195  const std::set<ActivationLayerInfo::ActivationFunction> supported_acts = { ActivationLayerInfo::ActivationFunction::RELU,
198  };
199  if(is_activation_enabled && supported_acts.count(act_info.activation()) != 0)
200  {
201  std::tie(min_activation, max_activation) = get_quantized_activation_min_max(act_info, data_type, uoqinfo);
202  }
203 
204  GEMMLowpOutputStageInfo output_info;
206  output_info.gemmlowp_offset = uoqinfo.offset;
207  output_info.gemmlowp_min_bound = min_activation;
208  output_info.gemmlowp_max_bound = max_activation;
209  output_info.is_quantized_per_channel = (weights->data_type() == DataType::QSYMM8_PER_CHANNEL);
211 
212  // Perform validation step on GEMMLowp
213  std::unique_ptr<ITensorInfo> input_qa = input->clone();
214  std::unique_ptr<ITensorInfo> weights_qa = weights->clone();
215  input_qa->set_quantization_info(QuantizationInfo(iqinfo.uniform().scale, -iqinfo.uniform().offset));
216  weights_qa->set_quantization_info(QuantizationInfo(wqinfo.uniform().scale, -wqinfo.uniform().offset));
217  return NEGEMMLowpMatrixMultiplyCore::validate(input_qa.get(), weights_qa.get(), biases, output, GEMMInfo(false, false, true, gemm_3d_depth, skip_im2col, false, output_info));
218  }
219  else
220  {
221  // Perform validation step on Matrix multiply function
222  return NEGEMM::validate(input, weights, nullptr, output, 1.0f, 0.0f, gemm_info);
223  }
224 }
225 
226 Status NEGEMMConvolutionLayer::validate_gemm3d(const ITensorInfo *input_info, const ITensorInfo *weights_info, const ActivationLayerInfo &act_info, int gemm_3d_depth, bool skip_im2col)
227 {
228  const DataType data_type = input_info->data_type();
229  const unsigned int mult_y = skip_im2col ? 1U : gemm_3d_depth;
230  const unsigned int mult_z = skip_im2col ? gemm_3d_depth : 1U;
231 
232  // Set dummy tensor shapes for the validation
233  const TensorInfo dummy_input_info(TensorShape(4U, 4U * mult_y, 1U * mult_z), 1, data_type, input_info->quantization_info());
234  const TensorInfo dummy_weights_info(TensorShape(4U, 4U), 1, data_type, weights_info->quantization_info());
235  const TensorInfo dummy_output_info(TensorShape(4U, 4U, gemm_3d_depth), 1, data_type, input_info->quantization_info());
236 
237  return validate_mm(&dummy_input_info, &dummy_weights_info, nullptr, &dummy_output_info, act_info, gemm_3d_depth, skip_im2col);
238 }
239 
241  const Size2D &dilation, const ActivationLayerInfo &act_info, unsigned int num_groups)
242 {
246  weights->info(),
247  biases != nullptr ? biases->info() : nullptr,
248  output->info(),
249  conv_info,
250  weights_info,
251  dilation,
252  act_info,
253  num_groups));
254 
255  const DataType data_type = input->info()->data_type();
256  const DataLayout data_layout = input->info()->data_layout();
260 
261  const unsigned int kernel_width = weights->info()->dimension(idx_width);
262  const unsigned int kernel_height = weights->info()->dimension(idx_height);
263 
264  _is_prepared = weights_info.retain_internal_weights();
265  _original_weights = weights;
266  _is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
267  _data_layout = data_layout;
268  _skip_im2col = (data_layout == DataLayout::NHWC && kernel_width == 1 && kernel_height == 1 && conv_info.stride().first == 1 && conv_info.stride().second == 1);
269 
270  const ITensor *gemm_input_to_use = input;
271  ITensor *gemm_output_to_use = output;
272 
273  // Get convolved dimensions
274  unsigned int conv_w = 0;
275  unsigned int conv_h = 0;
276  std::tie(conv_w, conv_h) = scaled_dimensions(input->info()->dimension(idx_width),
277  input->info()->dimension(idx_height),
278  kernel_width,
279  kernel_height,
280  conv_info,
281  dilation);
282 
283  // Check if GEMM3D is supported
285  {
286  _skip_col2im = bool(validate_gemm3d(input->info(), weights->info(), act_info, conv_h, true));
287  // If not supported, we need to perform im2col and col2im (or reshape layer)
288  if(!_skip_col2im)
289  {
290  _skip_im2col = false;
291  }
292  }
293  else
294  {
295  _skip_col2im = false;
296  }
297 
298  // Get parameters from conv_info
299  unsigned int stride_x = 0;
300  unsigned int stride_y = 0;
301  std::tie(stride_x, stride_y) = conv_info.stride();
302 
303  unsigned int mat_weights_cols = weights->info()->dimension(idx_kernels);
304 
305  // _weights_reshaped will be auto configured in the kernel.
306  // Just append biases and do not transpose 1xW as it will be reshaped in NEGEMM
307  const ITensor *weights_to_use = weights;
308 
309  if(_weights_manager && _weights_manager->are_weights_managed(weights))
310  {
311  _reshape_weights_managed.configure(weights, nullptr);
312  weights_to_use = _weights_manager->acquire(weights, &_reshape_weights_managed);
313  }
314  else
315  {
316  _reshape_weights.configure(weights, nullptr, &_weights_reshaped);
317  weights_to_use = &_weights_reshaped;
318  }
319 
320  // Create tensor to store im2col reshaped inputs
321  if(!_skip_im2col)
322  {
323  _memory_group.manage(&_im2col_output);
324 
325  // Configure
326  _im2col_kernel.configure(input, &_im2col_output, Size2D(kernel_width, kernel_height), conv_info, false, dilation);
327 
328  // Update GEMM input
329  gemm_input_to_use = &_im2col_output;
330  }
331 
332  // Create temporary GEMM output tensor in case we cannot skip col2im
333  if(!_skip_col2im)
334  {
335  TensorShape shape_gemm;
336 
337  // Calculate GEMM output shape
338  shape_gemm = _im2col_output.info()->tensor_shape();
339  shape_gemm.set(0, mat_weights_cols);
340  shape_gemm.set(1, conv_w * conv_h);
341 
342  // FIXME: input->clone() doesn't work with subtensors for grouped convolutions.
343  TensorInfo info_gemm(shape_gemm, 1, data_type);
344  info_gemm.set_quantization_info(output->info()->quantization_info()).set_data_layout(input->info()->data_layout());
345  _gemm_output.allocator()->init(info_gemm);
346  _memory_group.manage(&_gemm_output);
347 
348  // Update GEMM output
349  gemm_output_to_use = &_gemm_output;
350  }
351 
352  // Configure GEMM
353  // In case we need to skip col2im, GEMM3D (gemm_3d_depth != 0) must be called in order to avoid reshaping the output matrix
354  const unsigned int gemm_3d_depth = _skip_col2im ? conv_h : 0;
355  configure_mm(gemm_input_to_use, weights_to_use, biases, gemm_output_to_use, act_info, gemm_3d_depth);
356 
357  if(!_skip_im2col)
358  {
359  _im2col_output.allocator()->allocate();
360  }
361 
362  if(!_skip_col2im)
363  {
364  if(_data_layout == DataLayout::NCHW)
365  {
366  // Configure col2im
367  _col2im_kernel.configure(gemm_output_to_use, output, Size2D(conv_w, conv_h));
368  }
369  else
370  {
371  // Configure reshape layer
372  _reshape_layer.configure(gemm_output_to_use, output);
373  }
374  }
375 
376  if(_is_quantized && !_skip_col2im)
377  {
378  _tmp_output.allocator()->allocate();
379  }
380 
381  if(!_skip_col2im || _is_quantized)
382  {
383  _gemm_output.allocator()->allocate();
384  }
385 
386  ARM_COMPUTE_ERROR_ON_MSG((output->info()->dimension(idx_width) != conv_w) || (output->info()->dimension(idx_height) != conv_h),
387  "Output shape does not match the expected one");
388 }
389 
391  const WeightsInfo &weights_info, const Size2D &dilation, const ActivationLayerInfo &act_info, unsigned int num_groups)
392 {
394  ARM_COMPUTE_RETURN_ERROR_ON_MSG(weights_info.are_reshaped(), "Weights already reshaped are not supported!");
398  ARM_COMPUTE_RETURN_ERROR_ON_MSG(num_groups > 1, "Grouping (num_groups != 1) is not supported on NEON");
399 
400  const DataLayout data_layout = input->data_layout();
401  const DataType data_type = input->data_type();
406 
407  const unsigned int kernel_width = weights->dimension(idx_width);
408  const unsigned int kernel_height = weights->dimension(idx_height);
409 
410  TensorInfo im2col_reshaped_info{};
411  TensorInfo info_gemm{};
412  TensorInfo tmp_info{};
413  TensorInfo weights_reshaped_info{};
414  const ITensorInfo *gemm_input_to_use = input;
415  const ITensorInfo *gemm_output_to_use = output;
416  const ITensorInfo *weights_to_use = weights;
417 
418  const bool append_bias = false;
419  const bool is_quantized = is_data_type_quantized_asymmetric(data_type);
420  bool skip_im2col = (data_layout == DataLayout::NHWC && kernel_width == 1 && kernel_height == 1 && conv_info.stride().first == 1 && conv_info.stride().second == 1);
421 
422  // Get convolved dimensions
423  unsigned int conv_w = 0;
424  unsigned int conv_h = 0;
425 
426  std::tie(conv_w, conv_h) = scaled_dimensions(input->dimension(idx_width),
427  input->dimension(idx_height),
428  kernel_width,
429  kernel_height,
430  conv_info,
431  dilation);
432 
433  // Check if GEMM3D is supported
434  bool skip_col2im = false;
436  {
437  skip_col2im = bool(validate_gemm3d(input, weights, act_info, conv_h, true));
438  // If not supported, we need to perform im2col and col2im (or reshape layer)
439  if(!skip_col2im)
440  {
441  skip_im2col = false;
442  }
443  }
444 
445  if(skip_col2im)
446  {
447  // If not supported, we need to perform im2col and col2im (or reshape layer)
448  if(!bool(validate_gemm3d(input, weights, act_info, conv_h, skip_im2col)))
449  {
450  skip_im2col = false;
451  skip_col2im = false;
452  }
453  }
454 
455  ARM_COMPUTE_RETURN_ERROR_ON(weights->dimension(idx_channel) != input->dimension(idx_channel));
456  ARM_COMPUTE_RETURN_ERROR_ON(weights->num_dimensions() > 4);
457 
458  // Validate biases
459  if(biases != nullptr)
460  {
461  if(is_quantized)
462  {
464  }
465  else
466  {
468  }
469  ARM_COMPUTE_RETURN_ERROR_ON(biases->dimension(0) != weights->dimension(idx_kernels));
471  }
472 
473  unsigned int mat_weights_cols = weights->dimension(idx_kernels);
474  unsigned int mat_weights_rows = weights->dimension(idx_width) * weights->dimension(idx_height) * weights->dimension(idx_channel);
475 
476  // Output tensor auto inizialization if not yet initialized
478  weights_reshaped_info = TensorInfo(compute_weights_reshaped_shape(*weights, append_bias), 1, data_type);
479  weights_reshaped_info.set_quantization_info(weights->quantization_info());
480  weights_to_use = &weights_reshaped_info;
481 
482  if(!skip_im2col)
483  {
484  // Create tensor info for im2col reshaped inputs
485  // For NEON the batch size is on the fourth dimension
486  // TODO (giaiod01): Auto-initialize the output shape of im2col COMPMID-1482
487  TensorShape shape_im2col = input->tensor_shape();
488  shape_im2col.set(0, mat_weights_rows);
489  shape_im2col.set(1, conv_w * conv_h);
490  shape_im2col.set(2, 1);
491 
492  im2col_reshaped_info = TensorInfo(shape_im2col, 1, data_type);
493  im2col_reshaped_info.set_quantization_info(input->quantization_info());
494 
495  ARM_COMPUTE_RETURN_ON_ERROR(NEIm2ColKernel::validate(input, &im2col_reshaped_info, Size2D(kernel_width, kernel_height), conv_info, append_bias, dilation));
496  gemm_input_to_use = &im2col_reshaped_info;
497  }
498 
499  // Create temporary GEMM output tensor in case we cannot skip col2im
500  if(!skip_col2im)
501  {
502  TensorShape shape_gemm = gemm_input_to_use->tensor_shape();
503  shape_gemm.set(0, mat_weights_cols);
504  shape_gemm.set(1, conv_w * conv_h);
505  info_gemm = TensorInfo(shape_gemm, 1, data_type);
506  }
507  else
508  {
509  info_gemm = TensorInfo(output->tensor_shape(), 1, data_type);
510  }
511  info_gemm.set_quantization_info(output->quantization_info()).set_data_layout(input->data_layout());
512  gemm_output_to_use = &info_gemm;
513  ARM_COMPUTE_RETURN_ON_ERROR(validate_mm(gemm_input_to_use, weights_to_use, biases, gemm_output_to_use, act_info, skip_col2im ? conv_h : 0, skip_im2col));
514 
515  // Validate Col2Im/ReshapeLayer
516  if(!skip_col2im && (data_layout == DataLayout::NCHW))
517  {
518  ARM_COMPUTE_RETURN_ON_ERROR(NECol2ImKernel::validate(gemm_output_to_use, output, Size2D(conv_w, conv_h)));
519  }
520 
521  return Status{};
522 }
523 
525 {
526  prepare();
527 
528  MemoryGroupResourceScope scope_mg(_memory_group);
529 
530  if(!_skip_im2col)
531  {
532  // Run input reshaping
533  unsigned int y_dim = get_data_layout_dimension_index(_data_layout, DataLayoutDimension::HEIGHT);
534  NEScheduler::get().schedule(&_im2col_kernel, y_dim);
535  }
536 
537  // Runs NEGEMM or NEGEMMLowpMatrixMultiplyCore functions
538  if(_is_quantized)
539  {
540  // Run gemmlowp
541  _mm_gemmlowp.run();
542  }
543  else
544  {
545  // Run gemm
546  _mm_gemm.run();
547  }
548 
549  // Reshape output matrix
550  if(!_skip_col2im)
551  {
552  if(_data_layout == DataLayout::NCHW)
553  {
554  NEScheduler::get().schedule(&_col2im_kernel, Window::DimY);
555  }
556  else
557  {
558  _reshape_layer.run();
559  }
560  }
561 }
562 
564 {
565  if(!_is_prepared)
566  {
567  if(_weights_manager && _weights_manager->are_weights_managed(_original_weights))
568  {
569  _weights_manager->run(_original_weights, &_reshape_weights_managed);
570  }
571  else
572  {
573  // Run weights reshaping and mark original weights tensor as unused
574  _weights_reshaped.allocator()->allocate();
575  _reshape_weights.run();
576  _original_weights->mark_as_unused();
577  }
578 
579  // Prepare GEMM
580  _is_quantized ? _mm_gemmlowp.prepare() : _mm_gemm.prepare();
581  if(!_weights_reshaped.is_used())
582  {
583  _weights_reshaped.allocator()->free();
584  }
585 
586  _is_prepared = true;
587  }
588 }
589 } // namespace arm_compute
void configure(const ITensor *input, const ITensor *bias, ITensor *output)
Set the input and output of the kernel.
virtual size_t num_dimensions() const =0
The number of dimensions of the tensor (rank)
void prepare() override
Prepare the function for executing.
Shape of a tensor.
Definition: TensorShape.h:39
const DataLayout data_layout
Definition: Im2Col.cpp:146
Quantize using a fixed point multiplication.
void run() override final
Run the kernels contained in the function.
TensorInfo * info() const override
Interface to be implemented by the child class to return the tensor's metadata.
Definition: CLTensor.cpp:41
void init(const TensorAllocator &allocator, const Coordinates &coords, TensorInfo &sub_info)
Shares the same backing memory with another tensor allocator, while the tensor info might be differen...
virtual size_t dimension(size_t index) const =0
Return the size of the requested dimension.
#define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_LAYOUT(...)
Definition: Validate.h:494
#define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(...)
Definition: Validate.h:545
#define ARM_COMPUTE_RETURN_ON_ERROR(status)
Checks if a status contains an error and returns it.
Definition: Error.h:204
size_t dimension(size_t index) const override
Return the size of the requested dimension.
Definition: TensorInfo.h:232
bool is_used() const
Flags if the tensor is used or not.
Definition: ITensor.cpp:162
QuantizationInfo quantization_info() const override
Get the quantization settings (scale and offset) of the tensor.
Definition: TensorInfo.h:311
#define ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(t, c,...)
Definition: Validate.h:792
1 channel, 1 F32 per channel
Store the tensor's metadata.
Definition: ITensorInfo.h:40
#define ARM_COMPUTE_ERROR_THROW_ON(status)
Definition: Error.h:455
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
Activation Layer Information class.
Definition: Types.h:1615
Interface for NEON tensor.
Definition: ITensor.h:36
static Status validate(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output, const PadStrideInfo &conv_info, const WeightsInfo &weights_info=WeightsInfo(), const Size2D &dilation=Size2D(1U, 1U), const ActivationLayerInfo &act_info=ActivationLayerInfo(), unsigned int num_groups=1)
Static function to check if given info will lead to a valid configuration of NEGEMMConvolutionLayer.
Copyright (c) 2017-2020 ARM Limited.
void configure(const ITensor *input, ITensor *output, const Size2D &convolved_dims)
Set the input and output of the kernel.
static Status validate(const ITensorInfo *input, const ITensorInfo *biases, const ITensorInfo *output)
Static function to check if given info will lead to a valid configuration of NEWeightsReshapeKernel.
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:402
ITensorInfo & set_quantization_info(const QuantizationInfo &quantization_info) override
Set the quantization settings (scale and offset) of the tensor.
Definition: TensorInfo.cpp:372
TensorAllocator * allocator()
Return a pointer to the tensor's allocator.
Definition: Tensor.cpp:48
ITensorInfo * info() const override
Interface to be implemented by the child class to return the tensor's metadata.
Definition: Tensor.cpp:33
DataType data_type() const override
Data type used for each element of the tensor.
Definition: TensorInfo.h:265
Convolution Layer Weights Information class.
Definition: Types.h:1757
void mark_as_unused() const
Marks a tensor as unused.
Definition: ITensor.cpp:167
1 channel, 1 S32 per channel
void manage(IMemoryManageable *obj) override
Sets a object to be managed by the given memory group.
Definition: MemoryGroup.h:79
static Status validate(const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output)
Static function to check if given info will lead to a valid configuration of NEConvolutionLayerReshap...
bool are_weights_managed(const ITensor *weights)
Check if the weights are managed.
static Status validate(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, float alpha, float beta, const GEMMInfo &gemm_info=GEMMInfo())
Static function to check if given info will lead to a valid configuration of NEGEMM.
Definition: NEGEMM.cpp:172
void run() override
Run the kernels contained in the function.
Definition: NEGEMM.cpp:285
#define ARM_COMPUTE_UNUSED(...)
To avoid unused variables warnings.
Definition: Error.h:152
void configure(const ITensor *a, const ITensor *b, const ITensor *c, ITensor *output, const GEMMInfo &gemm_info=GEMMInfo())
Initialise the kernel's inputs, output.
bool is_data_type_quantized_per_channel(DataType dt)
Check if a given data type is of per channel type.
Definition: Utils.h:1194
virtual const TensorShape & tensor_shape() const =0
Size for each dimension of the tensor.
std::pair< int32_t, int32_t > get_quantized_activation_min_max(ActivationLayerInfo act_info, DataType data_type, UniformQuantizationInfo oq_info)
Returns a pair of minimum and maximum values for a quantized activation.
Definition: Utils.cpp:478
Status calculate_quantized_multipliers(const QuantizationInfo &iq_info, const QuantizationInfo &wq_info, const QuantizationInfo &oq_info, GEMMLowpOutputStageInfo &stage_info)
Calculate quantized representation of per-channel multipliers.
void run() override
Run the kernels contained in the function.
quantized, asymmetric fixed-point 8-bit number unsigned
#define ARM_COMPUTE_ERROR_ON_MSG(cond, msg)
Definition: Error.h:456
const unsigned int num_groups
Definition: Im2Col.cpp:148
void allocate() override
Allocate size specified by TensorInfo of CPU memory.
UniformQuantizationInfo uniform() const
Return per layer quantization info.
GEMMLowp output stage info.
Definition: Types.h:1944
virtual ITensorInfo * info() const =0
Interface to be implemented by the child class to return the tensor's metadata.
Padding and stride information class.
Definition: Types.h:686
virtual ITensorInfo & set_quantization_info(const QuantizationInfo &quantization_info)=0
Set the quantization settings (scale and offset) of the tensor.
void free() override
Free allocated CPU memory.
static Status validate(const ITensorInfo *input, const ITensorInfo *output, const Size2D &convolved_dims)
Static function to check if given info will lead to a valid configuration of NECol2ImKernel.
Weights manager interface to handle weights transformations.
virtual QuantizationInfo quantization_info() const =0
Get the quantization settings (scale and offset) of the tensor.
void run() override
Run the kernels contained in the function.
Num samples, channels, height, width.
src_info set_data_layout(data_layout)
bool is_data_type_quantized_asymmetric(DataType dt)
Check if a given data type is of asymmetric quantized type.
Definition: Utils.h:1139
quantized, symmetric per channel fixed-point 8-bit number
__constant DATA_TYPE16 type_min
Definition: minmaxloc.cl:46
#define ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(...)
Definition: Validate.h:163
static constexpr size_t DimY
Alias for dimension 1 also known as Y dimension.
Definition: Window.h:45
NEGEMMConvolutionLayer(const std::shared_ptr< IMemoryManager > &memory_manager=nullptr, IWeightsManager *weights_manager=nullptr)
Constructor.
void run() override
Run the kernels contained in the function.
#define ARM_COMPUTE_ERROR_ON_NULLPTR(...)
Definition: Validate.h:161
Memory group resources scope handling class.
Definition: IMemoryGroup.h:82
virtual size_t total_size() const =0
Returns the total size of the tensor in bytes.
virtual void schedule(ICPPKernel *kernel, const Hints &hints)=0
Runs the kernel in the same thread as the caller synchronously.
void configure(const ITensor *input, const ITensor *weights, const ITensor *biases, ITensor *output, const PadStrideInfo &conv_info, const WeightsInfo &weights_info=WeightsInfo(), const Size2D &dilation=Size2D(1U, 1U), const ActivationLayerInfo &act_info=ActivationLayerInfo(), unsigned int num_groups=1)
Set the input and output tensors.
TensorShape compute_weights_reshaped_shape(const ITensorInfo &weights, bool has_bias=false, unsigned int num_groups=1)
Calculate the reshaped shape of the weights.
Class for specifying the size of an image or rectangle.
Definition: Size2D.h:34
Num samples, height, width, channels.
void configure(const ITensor *a, const ITensor *b, const ITensor *c, ITensor *d, float alpha, float beta, const GEMMInfo &gemm_info=GEMMInfo())
Initialise the kernel's inputs, output.
Definition: NEGEMM.cpp:51
void prepare() override
Prepare the function for executing.
Definition: NEGEMM.cpp:335
__constant DATA_TYPE16 type_max
Definition: minmaxloc.cl:47
void configure(const ITensor *input, ITensor *output)
Initialise the kernel's inputs and outputs.
#define ARM_COMPUTE_RETURN_ERROR_ON_MSG(cond, msg)
If the condition is true, an error is returned.
Definition: Error.h:244
void configure(const ITensor *input, ITensor *output, const Size2D &kernel_dims, const PadStrideInfo &conv_info, bool has_bias, const Size2D &dilation=Size2D(1U, 1U), unsigned int num_groups=1)
Set the input and output of the kernel.
TensorShape & set(size_t dimension, size_t value, bool apply_dim_correction=true)
Accessor to set the value of one of the dimensions.
Definition: TensorShape.h:78
Store the tensor's metadata.
Definition: TensorInfo.h:45
static Status validate(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *output, const GEMMInfo &gemm_info=GEMMInfo())
Static function to check if given info will lead to a valid configuration of NEGEMMLowpMatrixMultiply...
GEMM information class.
Definition: Types.h:1983
ITensor * run(const ITensor *weights, ITransformWeights *weights_transform)
Run the reshape function.
quantized, asymmetric fixed-point 8-bit number signed
void prepare() override
Prepare the function for executing.
size_t get_data_layout_dimension_index(const DataLayout data_layout, const DataLayoutDimension data_layout_dimension)
Get the index of the given dimension.
Definition: Helpers.inl:327
void configure(const ITensor *weights, const ITensor *biases, ITensor *output)
Set the input and output tensors.
DataType
Available data types.
Definition: Types.h:75
DataLayout
[DataLayout enum definition]
Definition: Types.h:117
static Status validate(const ITensorInfo *input, const ITensorInfo *output, const Size2D &kernel_dims, const PadStrideInfo &conv_info, bool has_bias, const Size2D &dilation=Size2D(1U, 1U), unsigned int num_groups=1)
Static function to check if given info will lead to a valid configuration of NEIm2ColKernel.
std::tuple< PixelValue, PixelValue > get_min_max(DataType dt)
Compute the mininum and maximum values a data type can take.
Definition: Utils.h:558
ITensor * acquire(const ITensor *weights, ITransformWeights *weights_transform)
Acquire the requested reshape tensor of the selected weights.
static IScheduler & get()
Access the scheduler singleton.
Definition: Scheduler.cpp:95