Compute Library
 19.08
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 &&)=default
 Default move constructor. More...
 
NEFFTConvolutionLayeroperator= (const NEFFTConvolutionLayer &)=delete
 Prevent instances of this class from being copied (As this class contains pointers) More...
 
NEFFTConvolutionLayeroperator= (NEFFTConvolutionLayer &&)=default
 Default move assignment operator. 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 55 of file NEFFTConvolutionLayer.cpp.

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

◆ NEFFTConvolutionLayer() [2/3]

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

◆ NEFFTConvolutionLayer() [3/3]

Default move constructor.

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 97 of file NEFFTConvolutionLayer.cpp.

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

References arm_compute::test::validation::act_info, TensorAllocator::allocate(), Tensor::allocator(), arm_compute::auto_init_if_empty(), Tensor::buffer(), ICloneable< T >::clone(), NEArithmeticAddition::configure(), NEReverse::configure(), NEPermute::configure(), NESlice::configure(), NEActivationLayer::configure(), NEFFT2D::configure(), NEReductionOperation::configure(), NEPadLayer::configure(), NEComplexPixelWiseMultiplication::configure(), arm_compute::test::validation::conv_info, ITensorInfo::data_layout(), FFT2DInfo::direction, arm_compute::get_data_layout_dimension_index(), arm_compute::HEIGHT, ITensor::info(), Tensor::info(), CLTensor::info(), TensorAllocator::init(), arm_compute::Inverse, MemoryGroupBase< TensorType >::manage(), arm_compute::NCHW, arm_compute::NHWC, TensorShape::remove_dimension(), ITensorInfo::set_data_layout(), arm_compute::SUM, ITensorInfo::tensor_shape(), TensorInfo::tensor_shape(), arm_compute::U, arm_compute::U32, arm_compute::test::validation::weights, 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 &&  )
default

Default move assignment operator.

◆ 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 337 of file NEFFTConvolutionLayer.cpp.

338 {
339  if(!_is_prepared)
340  {
341  // Permute bias to NCHW
342  if(_original_bias != nullptr)
343  {
344  _permuted_bias.allocator()->allocate();
345  _permute_bias_func.run();
346  _original_bias->mark_as_unused();
347  }
348 
349  const ITensor *cur_weights = _original_weights;
350 
351  // Permute weights
352  if(_needs_permute)
353  {
354  ARM_COMPUTE_ERROR_ON(!cur_weights->is_used());
355 
356  _permuted_weights.allocator()->allocate();
357  _permute_weights_func.run();
358  cur_weights->mark_as_unused();
359  cur_weights = &_permuted_weights;
360  }
361 
362  // Flip weights
363  _flipped_weights.allocator()->allocate();
364  _flip_weights_func.run();
365  cur_weights->mark_as_unused();
366 
367  // Pad weights
368  _padded_weights.allocator()->allocate();
369  _pad_weights_func.run();
370  _flipped_weights.mark_as_unused();
371  _flipped_weights.allocator()->free();
372 
373  // Transform weights to frequency domain
374  _transformed_weights.allocator()->allocate();
375  _transform_weights_func->run();
376  _transform_weights_func.reset();
377 
378  _padded_weights.mark_as_unused();
379  _padded_weights.allocator()->free();
380 
381  _is_prepared = true;
382  }
383 }
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:337
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:167
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:288

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 296 of file NEFFTConvolutionLayer.cpp.

297 {
298  prepare();
299 
300  MemoryGroupResourceScope scope_mg(_memory_group);
301 
302  // Transform input
303  if(_needs_permute)
304  {
305  _permute_input_func.run();
306  }
307  _pad_input_func.run();
308  _transform_input_func.run();
309 
310  // Perform operations to frequency domain
311  _prod_func.run();
312 
313  _reduce_func.run();
314 
315  // Transform output
316  _itransform_output_func.run();
317  _reshaped_output.allocator()->import_memory(_itransformed_output.buffer());
318  _extract_output_func.run();
319 
320  // Add bias
321  if(_has_bias)
322  {
323  _bias_add_func.run();
324  }
325  if(_needs_permute)
326  {
327  _permute_output_func.run();
328  }
329 
330  // Run activation layer
331  if(_is_activationlayer_enabled)
332  {
333  _activation_layer_func.run();
334  }
335 }
void prepare() override
Prepare the function for executing.
void run() override final
Run the kernels contained in the function.
void run() override
Run the kernels contained in the function.
void run() override final
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.
Definition: NEPadLayer.cpp:288
void run() override
Run the kernels contained in the function.
Definition: NEFFT2D.cpp:86
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.

References Tensor::allocator(), Tensor::buffer(), TensorAllocator::import_memory(), NEFFTConvolutionLayer::prepare(), INESimpleFunctionNoBorder::run(), INESimpleFunction::run(), NEFFT2D::run(), NEReductionOperation::run(), and NEPadLayer::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 252 of file NEFFTConvolutionLayer.cpp.

254 {
257 
258  // Get indices for the width and height
259  const size_t idx_width = get_data_layout_dimension_index(input->data_layout(), DataLayoutDimension::WIDTH);
260  const size_t idx_height = get_data_layout_dimension_index(input->data_layout(), DataLayoutDimension::HEIGHT);
261 
262  // Input shape, kernel size and output tile
263  const Size2D kernel_size = Size2D(weights->tensor_shape()[idx_width], weights->tensor_shape()[idx_height]);
264 
265  // Strides
266  const auto strides = conv_info.stride();
267  ARM_COMPUTE_RETURN_ERROR_ON(strides.first != strides.second && strides.first != 1);
268  ARM_COMPUTE_RETURN_ERROR_ON(kernel_size.x() != kernel_size.y());
269  ARM_COMPUTE_RETURN_ERROR_ON(conv_info.pad_left() != (kernel_size.x() / 2) || conv_info.pad_right() != (kernel_size.x() / 2));
270  ARM_COMPUTE_RETURN_ERROR_ON(conv_info.pad_top() != (kernel_size.y() / 2) || conv_info.pad_bottom() != (kernel_size.y() / 2));
271 
272  // Validate biases
273  if(biases != nullptr)
274  {
275  const size_t idx_channels = get_data_layout_dimension_index(input->data_layout(), DataLayoutDimension::CHANNEL);
277  ARM_COMPUTE_RETURN_ERROR_ON(input->tensor_shape()[idx_channels] != biases->tensor_shape().x());
278  }
279 
280  // Checks performed when output is configured
281  if((output != nullptr) && (output->total_size() != 0))
282  {
284  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]));
285 
286  // Validate Activation Layer
287  if(act_info.enabled())
288  {
290  }
291  }
292 
293  return Status{};
294 }
#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:193
static Status validate(const ITensorInfo *input, const ITensorInfo *output, const ActivationLayerInfo &act_info)
Static function to check if given info will lead to a valid configuration of NEActivationLayer.
#define ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(t, c,...)
Definition: Validate.h:791
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:244
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:326

References arm_compute::test::validation::act_info, 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, ITensorInfo::data_layout(), arm_compute::F32, arm_compute::get_data_layout_dimension_index(), arm_compute::HEIGHT, ITensorInfo::tensor_shape(), ITensorInfo::total_size(), NEActivationLayer::validate(), arm_compute::test::validation::weights, 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: