Compute Library
 20.11
NEFFTConvolutionLayer Class Reference

Basic function to execute FFT-based convolution on NEON. More...

#include <NEFFTConvolutionLayer.h>

Collaboration diagram for NEFFTConvolutionLayer:
[legend]

Public Member Functions

 NEFFTConvolutionLayer (std::shared_ptr< IMemoryManager > memory_manager=nullptr)
 Default constructor. More...
 
 NEFFTConvolutionLayer (const NEFFTConvolutionLayer &)=delete
 Prevent instances of this class from being copied (As this class contains pointers) More...
 
 NEFFTConvolutionLayer (NEFFTConvolutionLayer &&)=delete
 Prevent instances of this class from being moved (As this class contains non movable objects) More...
 
NEFFTConvolutionLayeroperator= (const NEFFTConvolutionLayer &)=delete
 Prevent instances of this class from being copied (As this class contains pointers) More...
 
NEFFTConvolutionLayeroperator= (NEFFTConvolutionLayer &&)=delete
 Prevent instances of this class from being moved (As this class contains non movable objects) More...
 
 ~NEFFTConvolutionLayer ()
 Default destructor. More...
 
void configure (ITensor *input, const ITensor *weights, const ITensor *biases, ITensor *output, const PadStrideInfo &conv_info, const ActivationLayerInfo &act_info=ActivationLayerInfo())
 Set the input and output tensors. More...
 
void run () override
 Run the kernels contained in the function. More...
 
void prepare () override
 Prepare the function for executing. More...
 
- Public Member Functions inherited from IFunction
virtual ~IFunction ()=default
 Destructor. More...
 

Static Public Member Functions

static Status validate (const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output, const PadStrideInfo &conv_info, const ActivationLayerInfo &act_info=ActivationLayerInfo())
 Static function to check if given info will lead to a valid configuration of NEFFTConvolutionLayer. More...
 

Detailed Description

Basic function to execute FFT-based convolution on NEON.

This function calls the following NEON functions/kernels:

  1. NEPermute Permute input if NHWC(only NCHW is supported).
  2. NEPadLayer Pad input.
  3. NEFFT2D Forward transform to the frequency domain.
  4. NEComplexPixelWiseMultiplication Complex element-wise product of input and the weights.
  5. NEReductionOperation Reduction across channels.
  6. NEFFT2D Inverse transform back to the time domain.
  7. NEStridedSlice Extract valid output.
  8. NEArithmeticAddition Add bias.
  9. NEActivationLayer Perform activation.
  10. NEPermute Permute output if NHWC(only NCHW is supported).

Definition at line 59 of file NEFFTConvolutionLayer.h.

Constructor & Destructor Documentation

◆ NEFFTConvolutionLayer() [1/3]

NEFFTConvolutionLayer ( std::shared_ptr< IMemoryManager memory_manager = nullptr)

Default constructor.

Definition at line 64 of file NEFFTConvolutionLayer.cpp.

65  : _memory_group(memory_manager),
66  _flip_weights_func(),
67  _permute_input_func(),
68  _permute_output_func(),
69  _permute_weights_func(),
70  _permute_bias_func(),
71  _pad_input_func(),
72  _pad_weights_func(),
73  _transform_input_func(memory_manager),
74  _transform_weights_func(),
75  _itransform_output_func(memory_manager),
76  _prod_func(),
77  _reduce_func(),
78  _extract_output_func(),
79  _bias_add_func(),
80  _activation_layer_func(),
81  _permuted_input(),
82  _permuted_weights(),
83  _permuted_bias(),
84  _permuted_output(),
85  _padded_input(),
86  _padded_weights(),
87  _flip_axis(),
88  _flipped_weights(),
89  _transformed_input(),
90  _transformed_weights(),
91  _input_weights_product(),
92  _output_product(),
93  _output_reduced(),
94  _itransformed_output(),
95  _reshaped_output(),
96  _bias_output(),
97  _original_weights(nullptr),
98  _original_bias(nullptr),
99  _is_activationlayer_enabled(false),
100  _needs_permute(false),
101  _has_bias(false),
102  _is_prepared(false)
103 {
104 }

◆ NEFFTConvolutionLayer() [2/3]

Prevent instances of this class from being copied (As this class contains pointers)

◆ NEFFTConvolutionLayer() [3/3]

Prevent instances of this class from being moved (As this class contains non movable objects)

◆ ~NEFFTConvolutionLayer()

~NEFFTConvolutionLayer ( )
default

Default destructor.

Member Function Documentation

◆ configure()

void configure ( ITensor input,
const ITensor weights,
const ITensor biases,
ITensor output,
const PadStrideInfo conv_info,
const ActivationLayerInfo act_info = ActivationLayerInfo() 
)

Set the input and output tensors.

Note
: This function only works with any square kernel size and unit strides for both NCHW and NHWC data layout
Parameters
[in]inputSource tensor. 3 lower dimensions represent a single input [width, height, IFM], while every optional dimension from 4 and above represent a batch of inputs. Data types supported: F32.
[in]weightsWeights tensor. Weights are 4D tensor with dimensions [kernel_x, kernel_y, IFM, OFM]. Data type supported:Same as input.
[in]biasesBiases tensor. Shared biases supported. Biases are 1D tensor with dimensions [OFM].Data type supported: Same as input
[out]outputDestination tensor. 3 lower dimensions represent a single output [width, height, OFM], while the rest represent batch of outputs. Data types supported: Same as input.
[in]conv_infoContains padding and stride information described in PadStrideInfo.
[in]act_info(Optional) Activation layer information in case of a fused activation.

Definition at line 107 of file NEFFTConvolutionLayer.cpp.

109 {
110  _original_weights = weights;
111  _original_bias = biases;
112 
113  // Flat if bias addition is required
114  _has_bias = biases != nullptr;
115 
116  // Get indices for the width and height
117  const size_t idx_width = get_data_layout_dimension_index(input->info()->data_layout(), DataLayoutDimension::WIDTH);
118  const size_t idx_height = get_data_layout_dimension_index(input->info()->data_layout(), DataLayoutDimension::HEIGHT);
119 
120  // Input shape, kernel size and output tile
121  const Size2D input_dims = Size2D(input->info()->tensor_shape()[idx_width], input->info()->tensor_shape()[idx_height]);
122  const Size2D kernel_size = Size2D(weights->info()->tensor_shape()[idx_width], weights->info()->tensor_shape()[idx_height]);
123  const Size2D pad_valid = Size2D(pad_decomposable(input_dims.x() + kernel_size.x() - 1),
124  pad_decomposable(input_dims.y() + kernel_size.y() - 1));
125  // Tensors to use
126  ITensor *input_to_use = input;
127  const ITensor *weights_to_use = weights;
128  ITensor *output_to_use = _has_bias ? &_bias_output : output;
129 
130  // Permute bias
131  if(biases != nullptr)
132  {
133  _permute_bias_func.configure(biases, &_permuted_bias, PermutationVector(1U, 2U, 0U));
134  _permuted_bias.info()->set_data_layout(DataLayout::NCHW);
135  }
136 
137  // Permute input if needed
138  _needs_permute = input->info()->data_layout() == DataLayout::NHWC;
139  if(_needs_permute)
140  {
141  _memory_group.manage(&_permuted_input);
142  // Configure the function to transform the input tensor from NHWC -> NCHW
143  _permute_input_func.configure(input, &_permuted_input, PermutationVector(1U, 2U, 0U));
144  _permuted_input.info()->set_data_layout(DataLayout::NCHW);
145 
146  // Configure the function to transform the weights tensor from HWI -> IHW
147  _permute_weights_func.configure(weights, &_permuted_weights, PermutationVector(1U, 2U, 0U));
148  _permuted_weights.info()->set_data_layout(DataLayout::NCHW);
149 
150  input_to_use = &_permuted_input;
151  weights_to_use = &_permuted_weights;
152  }
153 
154  // Flip weights
155  _flipped_weights.allocator()->init(weights_to_use->info()->clone()->set_is_resizable(true).reset_padding());
156  _flip_axis.allocator()->init(TensorInfo(TensorShape(2U), 1, DataType::U32));
157  _flip_weights_func.configure(weights_to_use, &_flipped_weights, &_flip_axis);
158 
159  // Pad weights
160  const PaddingList padding_w = { { 0, input_dims.x() + pad_valid.x() - 1 }, { 0, input_dims.y() + pad_valid.y() - 1 } };
161  _pad_weights_func.configure(&_flipped_weights, &_padded_weights, padding_w);
162 
163  // Transform weights
164  _transform_weights_func = support::cpp14::make_unique<NEFFT2D>();
165  _transform_weights_func->configure(&_padded_weights, &_transformed_weights, FFT2DInfo());
166 
167  // Pad input
168  const PaddingList padding_in = { { 0, kernel_size.x() + pad_valid.x() - 1 }, { 0, kernel_size.y() + pad_valid.y() - 1 } };
169  _memory_group.manage(&_padded_input);
170  _pad_input_func.configure(input_to_use, &_padded_input, padding_in);
171  if(_needs_permute)
172  {
173  _permuted_input.allocator()->allocate();
174  }
175 
176  // Transform input
177  _memory_group.manage(&_transformed_input);
178  _transform_input_func.configure(&_padded_input, &_transformed_input, FFT2DInfo());
179  _padded_input.allocator()->allocate();
180 
181  // Perform product
182  _memory_group.manage(&_output_product);
183  _prod_func.configure(&_transformed_input, &_transformed_weights, &_output_product);
184  _transformed_input.allocator()->allocate();
185 
186  // Perform reduction
187  _memory_group.manage(&_output_reduced);
188  _reduce_func.configure(&_output_product, &_output_reduced, 2, ReductionOperation::SUM);
189  _output_product.allocator()->allocate();
190 
191  // Transform output
192  _memory_group.manage(&_itransformed_output);
193  FFT2DInfo itranform_info;
194  itranform_info.direction = FFTDirection::Inverse;
195  _itransformed_output.allocator()->init(_output_reduced.info()->clone()->set_is_resizable(true).set_num_channels(1).reset_padding());
196  _itransform_output_func.configure(&_output_reduced, &_itransformed_output, itranform_info);
197  _output_reduced.allocator()->allocate();
198 
199  // Reshape output
200  TensorShape reshaped_shape = _itransformed_output.info()->tensor_shape();
201  reshaped_shape.remove_dimension(2);
202  _reshaped_output.allocator()->init(_itransformed_output.info()->clone()->set_tensor_shape(reshaped_shape));
203 
204  // Extract correct region
205  const int start_left = kernel_size.x() - conv_info.pad_left() - 1;
206  const int start_top = kernel_size.y() - conv_info.pad_top() - 1;
207  const int end_right = _reshaped_output.info()->tensor_shape().x() - (kernel_size.x() - conv_info.pad_right() - 1) - pad_valid.x();
208  const int end_botton = _reshaped_output.info()->tensor_shape().y() - (kernel_size.y() - conv_info.pad_bottom() - 1) - pad_valid.y();
209  if(_has_bias)
210  {
211  _memory_group.manage(&_bias_output);
212  }
213  else if(_needs_permute)
214  {
215  output_to_use = &_permuted_output;
216  _memory_group.manage(&_permuted_output);
217  }
218  _extract_output_func.configure(&_reshaped_output, output_to_use, Coordinates(start_left, start_top), Coordinates(end_right, end_botton));
219  _reshaped_output.allocator()->allocate();
220  _itransformed_output.allocator()->allocate();
221 
222  // Add bias
223  if(biases != nullptr)
224  {
225  output_to_use = output;
226  if(_needs_permute)
227  {
228  output_to_use = &_permuted_output;
229  _memory_group.manage(&_permuted_output);
230  }
231  auto_init_if_empty(*output_to_use->info(), *_bias_output.info());
232  _bias_add_func.configure(&_bias_output, &_permuted_bias, output_to_use, ConvertPolicy::WRAP);
233  _bias_output.allocator()->allocate();
234  }
235 
236  // Permute output
237  if(_needs_permute)
238  {
239  // Configure the function to transform the convoluted output to ACL's native ordering format NCHW
240  _permuted_output.info()->set_data_layout(DataLayout::NCHW);
241  _permute_output_func.configure(&_permuted_output, output, PermutationVector(2U, 0U, 1U));
242 
243  // Allocate tensors
244  _permuted_output.allocator()->allocate();
245  }
246 
247  // Configure Activation Layer
248  _is_activationlayer_enabled = act_info.enabled();
249  if(_is_activationlayer_enabled)
250  {
251  _activation_layer_func.configure(output, nullptr, act_info);
252  }
253 
254  // Setup flip axis data
255  _flip_axis.allocator()->allocate();
256 
257  auto axis_data = reinterpret_cast<uint32_t *>(_flip_axis.buffer());
258  axis_data[0] = 0;
259  axis_data[1] = 1;
260 }
void remove_dimension(size_t n)
Accessor to remove the dimension n from the tensor shape.
Definition: TensorShape.h:110
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...
std::vector< PaddingInfo > PaddingList
List of padding information.
Definition: Types.h:481
Strides PermutationVector
Permutation vector.
Definition: Types.h:49
void configure(const ITensor *input1, const ITensor *input2, ITensor *output, ConvertPolicy policy, const ActivationLayerInfo &act_info=ActivationLayerInfo())
Initialise the kernel's inputs, output and conversion policy.
void configure(const ITensor *input, ITensor *output, const ITensor *axis)
Initialize the function.
Definition: NEReverse.cpp:31
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
void manage(IMemoryManageable *obj) override
Sets a object to be managed by the given memory group.
Definition: MemoryGroup.h:79
T x() const
Alias to access the size of the first dimension.
Definition: Dimensions.h:81
void configure(const ITensor *input, ITensor *output, const Coordinates &starts, const Coordinates &ends)
Configure kernel.
Definition: NESlice.cpp:87
1 channel, 1 U32 per channel
virtual const TensorShape & tensor_shape() const =0
Size for each dimension of the tensor.
virtual ITensorInfo & set_data_layout(const DataLayout &data_layout)=0
Set the data layout of the tensor.
void allocate() override
Allocate size specified by TensorInfo of CPU memory.
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.
Num samples, channels, height, width.
Num samples, height, width, channels.
void configure(ITensor *input, ITensor *output, ActivationLayerInfo activation_info)
[NEActivationLayer snippet]
uint8_t * buffer() const override
Interface to be implemented by the child class to return a pointer to CPU memory.
Definition: Tensor.cpp:43
void configure(ITensor *input, ITensor *output, const PaddingList &padding, const PixelValue constant_value=PixelValue(), const PaddingMode mode=PaddingMode::CONSTANT)
Initialize the function.
Definition: NEPadLayer.cpp:169
T y() const
Alias to access the size of the second dimension.
Definition: Dimensions.h:86
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:193
void configure(const ITensor *input, ITensor *output, const PermutationVector &perm)
Configure the permute NEON kernel.
Definition: NEPermute.cpp:31
void configure(const ITensor *input, ITensor *output, const FFT2DInfo &config)
Initialise the function's source and destinations.
Definition: NEFFT2D.cpp:42
void configure(ITensor *input1, ITensor *input2, ITensor *output, const ActivationLayerInfo &act_info=ActivationLayerInfo())
Initialise the kernel's inputs, output.
void configure(ITensor *input, ITensor *output, unsigned int axis, ReductionOperation op, bool keep_dims=true)
Set the input and output tensors.

References TensorAllocator::allocate(), Tensor::allocator(), arm_compute::auto_init_if_empty(), Tensor::buffer(), ICloneable< T >::clone(), NEReverse::configure(), NEPermute::configure(), NEFFT2D::configure(), NEReductionOperation::configure(), NEActivationLayer::configure(), NEPadLayer::configure(), NESlice::configure(), NEArithmeticAddition::configure(), NEComplexPixelWiseMultiplication::configure(), arm_compute::test::validation::conv_info, FFT2DInfo::direction, ActivationLayerInfo::enabled(), arm_compute::get_data_layout_dimension_index(), arm_compute::HEIGHT, arm_compute::test::validation::idx_height, arm_compute::test::validation::idx_width, ITensor::info(), Tensor::info(), TensorAllocator::init(), arm_compute::test::validation::input, arm_compute::Inverse, MemoryGroup::manage(), arm_compute::NCHW, arm_compute::NHWC, TensorShape::remove_dimension(), ITensorInfo::set_data_layout(), arm_compute::SUM, ITensorInfo::tensor_shape(), arm_compute::U, arm_compute::U32, arm_compute::WIDTH, arm_compute::WRAP, Dimensions< T >::x(), and Dimensions< T >::y().

◆ operator=() [1/2]

NEFFTConvolutionLayer& operator= ( const NEFFTConvolutionLayer )
delete

Prevent instances of this class from being copied (As this class contains pointers)

◆ operator=() [2/2]

NEFFTConvolutionLayer& operator= ( NEFFTConvolutionLayer &&  )
delete

Prevent instances of this class from being moved (As this class contains non movable objects)

◆ prepare()

void prepare ( )
overridevirtual

Prepare the function for executing.

Any one off pre-processing step required by the function is handled here

Note
Prepare stage might not need all the function's buffers' backing memory to be available in order to execute

Reimplemented from IFunction.

Definition at line 347 of file NEFFTConvolutionLayer.cpp.

348 {
349  if(!_is_prepared)
350  {
351  // Permute bias to NCHW
352  if(_original_bias != nullptr)
353  {
354  _permuted_bias.allocator()->allocate();
355  _permute_bias_func.run();
356  _original_bias->mark_as_unused();
357  }
358 
359  const ITensor *cur_weights = _original_weights;
360 
361  // Permute weights
362  if(_needs_permute)
363  {
364  ARM_COMPUTE_ERROR_ON(!cur_weights->is_used());
365 
366  _permuted_weights.allocator()->allocate();
367  _permute_weights_func.run();
368  cur_weights->mark_as_unused();
369  cur_weights = &_permuted_weights;
370  }
371 
372  // Flip weights
373  _flipped_weights.allocator()->allocate();
374  _flip_weights_func.run();
375  cur_weights->mark_as_unused();
376 
377  // Pad weights
378  _padded_weights.allocator()->allocate();
379  _pad_weights_func.run();
380  _flipped_weights.mark_as_unused();
381  _flipped_weights.allocator()->free();
382 
383  // Transform weights to frequency domain
384  _transformed_weights.allocator()->allocate();
385  _transform_weights_func->run();
386  _transform_weights_func.reset();
387 
388  _padded_weights.mark_as_unused();
389  _padded_weights.allocator()->free();
390 
391  _is_prepared = true;
392  }
393 }
void run() override final
Run the kernels contained in the function.
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
TensorAllocator * allocator()
Return a pointer to the tensor's allocator.
Definition: Tensor.cpp:48
void mark_as_unused() const
Marks a tensor as unused.
Definition: ITensor.cpp:168
void allocate() override
Allocate size specified by TensorInfo of CPU memory.
void free() override
Free allocated CPU memory.
void run() override
Run the kernels contained in the function.
Definition: NEPadLayer.cpp:253

References TensorAllocator::allocate(), Tensor::allocator(), ARM_COMPUTE_ERROR_ON, TensorAllocator::free(), ITensor::is_used(), ITensor::mark_as_unused(), INESimpleFunctionNoBorder::run(), and NEPadLayer::run().

Referenced by NEFFTConvolutionLayer::run().

◆ run()

void run ( )
overridevirtual

Run the kernels contained in the function.

For NEON kernels:

  • Multi-threading is used for the kernels which are parallelisable.
  • By default std::thread::hardware_concurrency() threads are used.
Note
CPPScheduler::set_num_threads() can be used to manually set the number of threads

For OpenCL kernels:

  • All the kernels are enqueued on the queue associated with CLScheduler.
  • The queue is then flushed.
Note
The function will not block until the kernels are executed. It is the user's responsibility to wait.
Will call prepare() on first run if hasn't been done

Implements IFunction.

Definition at line 306 of file NEFFTConvolutionLayer.cpp.

307 {
308  prepare();
309 
310  MemoryGroupResourceScope scope_mg(_memory_group);
311 
312  // Transform input
313  if(_needs_permute)
314  {
315  _permute_input_func.run();
316  }
317  _pad_input_func.run();
318  _transform_input_func.run();
319 
320  // Perform operations to frequency domain
321  _prod_func.run();
322 
323  _reduce_func.run();
324 
325  // Transform output
326  _itransform_output_func.run();
327  _reshaped_output.allocator()->import_memory(_itransformed_output.buffer());
328  _extract_output_func.run();
329 
330  // Add bias
331  if(_has_bias)
332  {
333  _bias_add_func.run();
334  }
335  if(_needs_permute)
336  {
337  _permute_output_func.run();
338  }
339 
340  // Run activation layer
341  if(_is_activationlayer_enabled)
342  {
343  _activation_layer_func.run();
344  }
345 }
void prepare() override
Prepare the function for executing.
void run() override
Run the kernels contained in the function.
void run() override final
Run the kernels contained in the function.
void run() override
Run the kernels contained in the function.
void run() override
Run the kernels contained in the function.
TensorAllocator * allocator()
Return a pointer to the tensor's allocator.
Definition: Tensor.cpp:48
void run() override
Run the kernels contained in the function.
void run() override
Run the kernels contained in the function.
Definition: NEPadLayer.cpp:253
void run() override
Run the kernels contained in the function.
Definition: NEFFT2D.cpp:91
uint8_t * buffer() const override
Interface to be implemented by the child class to return a pointer to CPU memory.
Definition: Tensor.cpp:43
Status import_memory(void *memory)
Import an existing memory as a tensor's backing memory.
void run() override
Run the kernels contained in the function.
Definition: NESlice.cpp:95

References Tensor::allocator(), Tensor::buffer(), TensorAllocator::import_memory(), NEFFTConvolutionLayer::prepare(), INESimpleFunctionNoBorder::run(), NEFFT2D::run(), NEReductionOperation::run(), NEActivationLayer::run(), NEPadLayer::run(), NESlice::run(), NEArithmeticAddition::run(), and NEComplexPixelWiseMultiplication::run().

◆ validate()

Status validate ( const ITensorInfo input,
const ITensorInfo weights,
const ITensorInfo biases,
const ITensorInfo output,
const PadStrideInfo conv_info,
const ActivationLayerInfo act_info = ActivationLayerInfo() 
)
static

Static function to check if given info will lead to a valid configuration of NEFFTConvolutionLayer.

Note
: This function only works with any square kernel size and unit strides for both NCHW and NHWC data layout
Parameters
[in]inputSource tensor. 3 lower dimensions represent a single input [width, height, IFM], while every optional dimension from 4 and above represent a batch of inputs. Data types supported: F32.
[in]weightsWeights tensor. Weights are 4D tensor with dimensions [kernel_x, kernel_y, IFM, OFM]. Data type supported:Same as input.
[in]biasesBiases tensor. Shared biases supported. Biases are 1D tensor with dimensions [OFM].Data type supported: Same as input
[in]outputDestination tensor. 3 lower dimensions represent a single output [width, height, OFM], while the rest represent batch of outputs. Data types supported: Same as input.
[in]conv_infoContains padding and stride information described in PadStrideInfo.
[in]act_info(Optional) Activation layer information in case of a fused activation.
Returns
a status

Definition at line 262 of file NEFFTConvolutionLayer.cpp.

264 {
267 
268  // Get indices for the width and height
271 
272  // Input shape, kernel size and output tile
273  const Size2D kernel_size = Size2D(weights->tensor_shape()[idx_width], weights->tensor_shape()[idx_height]);
274 
275  // Strides
276  const auto strides = conv_info.stride();
277  ARM_COMPUTE_RETURN_ERROR_ON(strides.first != strides.second && strides.first != 1);
278  ARM_COMPUTE_RETURN_ERROR_ON(kernel_size.x() != kernel_size.y());
279  ARM_COMPUTE_RETURN_ERROR_ON(conv_info.pad_left() != (kernel_size.x() / 2) || conv_info.pad_right() != (kernel_size.x() / 2));
280  ARM_COMPUTE_RETURN_ERROR_ON(conv_info.pad_top() != (kernel_size.y() / 2) || conv_info.pad_bottom() != (kernel_size.y() / 2));
281 
282  // Validate biases
283  if(biases != nullptr)
284  {
285  const size_t idx_channels = get_data_layout_dimension_index(input->data_layout(), DataLayoutDimension::CHANNEL);
287  ARM_COMPUTE_RETURN_ERROR_ON(input->tensor_shape()[idx_channels] != biases->tensor_shape().x());
288  }
289 
290  // Checks performed when output is configured
291  if((output != nullptr) && (output->total_size() != 0))
292  {
294  ARM_COMPUTE_RETURN_ERROR_ON((input->tensor_shape()[idx_height] != output->tensor_shape()[idx_height]) || (input->tensor_shape()[idx_width] != output->tensor_shape()[idx_width]));
295 
296  // Validate Activation Layer
297  if(act_info.enabled())
298  {
299  ARM_COMPUTE_RETURN_ON_ERROR(NEActivationLayer::validate(output, nullptr, act_info));
300  }
301  }
302 
303  return Status{};
304 }
#define ARM_COMPUTE_RETURN_ON_ERROR(status)
Checks if a status contains an error and returns it.
Definition: Error.h:204
static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ActivationLayerInfo &act_info)
[NEActivationLayer snippet]
1 channel, 1 F32 per channel
#define ARM_COMPUTE_RETURN_ERROR_ON(cond)
If the condition is true, an error is returned.
Definition: Error.h:296
#define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(...)
Definition: Validate.h:545
#define ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(t, c,...)
Definition: Validate.h:792
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:193

References ARM_COMPUTE_RETURN_ERROR_ON, ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN, ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES, ARM_COMPUTE_RETURN_ON_ERROR, arm_compute::CHANNEL, arm_compute::test::validation::conv_info, ActivationLayerInfo::enabled(), arm_compute::F32, arm_compute::get_data_layout_dimension_index(), arm_compute::HEIGHT, arm_compute::test::validation::idx_height, arm_compute::test::validation::idx_width, arm_compute::test::validation::input, ITensorInfo::tensor_shape(), ITensorInfo::total_size(), NEActivationLayer::validate(), arm_compute::WIDTH, and Dimensions< T >::x().

Referenced by NEConvolutionLayer::get_convolution_method(), and NEConvolutionLayer::validate().


The documentation for this class was generated from the following files: