Compute Library
 19.11
NEFullyConnectedLayer Class Reference

Basic function to compute a Fully Connected layer on NEON. More...

#include <NEFullyConnectedLayer.h>

Collaboration diagram for NEFullyConnectedLayer:
[legend]

Public Member Functions

 NEFullyConnectedLayer (std::shared_ptr< IMemoryManager > memory_manager=nullptr, IWeightsManager *weights_manager=nullptr)
 Constructor. More...
 
 NEFullyConnectedLayer (const NEFullyConnectedLayer &)=delete
 Prevent instances of this class from being copied (As this class contains pointers) More...
 
 NEFullyConnectedLayer (NEFullyConnectedLayer &&)=default
 Default move constructor. More...
 
NEFullyConnectedLayeroperator= (const NEFullyConnectedLayer &)=delete
 Prevent instances of this class from being copied (As this class contains pointers) More...
 
NEFullyConnectedLayeroperator= (NEFullyConnectedLayer &&)=default
 Default move assignment operator. More...
 
void configure (const ITensor *input, const ITensor *weights, const ITensor *biases, ITensor *output, FullyConnectedLayerInfo fc_info=FullyConnectedLayerInfo())
 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, FullyConnectedLayerInfo fc_info=FullyConnectedLayerInfo())
 Static function to check if given info will lead to a valid configuration of NEFullyConnectedLayer. More...
 

Detailed Description

Basic function to compute a Fully Connected layer on NEON.

This function calls the following NEON kernels:

  1. NEIm2ColKernel (called when the input comes from a convolutional layer)
  2. NEFullyConnectedLayerReshapeWeights (if are_weights_reshaped is set to false and transpose_weights is set to true ) (called once)
  3. NEGEMMMatrixMultiplyKernel or NEGEMMLowpMatrixMultiplyCore (if quantized asymmetric)
  4. NEGEMMMatrixAccumulateBiasesKernel or NEGEMMLowpQuantizeDownInt32ToUint8ScaleByFixedPoint (if quantized asymmetric) (if biases is not equal to nullptr)
Note
The fully connected layer accepts "weights" tensors only with 2 dimensions.

Definition at line 114 of file NEFullyConnectedLayer.h.

Constructor & Destructor Documentation

◆ NEFullyConnectedLayer() [1/3]

NEFullyConnectedLayer ( std::shared_ptr< IMemoryManager memory_manager = nullptr,
IWeightsManager weights_manager = nullptr 
)

Constructor.

Definition at line 77 of file NEFullyConnectedLayer.cpp.

78  : _memory_group(std::move(memory_manager)), _weights_manager(weights_manager), _flatten_kernel(), _convert_weights(), _convert_weights_managed(), _reshape_weights_function(),
79  _reshape_weights_managed_function(), _mm_gemm(nullptr, weights_manager), _mm_gemmlowp(), _gemmlowp_output_stage(), _accumulate_biases_kernel(), _flatten_output(), _gemmlowp_output(),
80  _converted_weights_output(), _reshape_weights_output(), _original_weights(nullptr), _are_weights_converted(true), _are_weights_reshaped(false), _is_fc_after_conv(false), _accumulate_biases(false),
81  _is_quantized(false), _is_prepared(false)
82 {
83 }

◆ NEFullyConnectedLayer() [2/3]

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

◆ NEFullyConnectedLayer() [3/3]

Default move constructor.

Member Function Documentation

◆ configure()

void configure ( const ITensor input,
const ITensor weights,
const ITensor biases,
ITensor output,
FullyConnectedLayerInfo  fc_info = FullyConnectedLayerInfo() 
)

Set the input and output tensors.

Parameters
[in]inputSource tensor. Data type supported: QASYMM8/F16/F32.
[in]weightsWeights tensor. The weights must be 2 dimensional. If this function is called after a Convolution Layer, the (transposed) weights will have as many rows as the product of the first 3 input's dimensions. If it is called after another FullyConnected Layer, the (transposed) weights will have as many rows as the input's first dimension. Data type supported: Same as input.
[in]biasesBias tensor. Can be nullptr. Data type supported:Same as input.
[out]outputDestination tensor. Its shape should be equal to the output of a matrix multiplication between:
  • The output of im2col on the input and the (transposed) 2D weights, if the function is called after a Convolution Layer
  • The input tensor and the (transposed) 2D weights, if the function is called after another FullyConnected Layer. Data type supported: Same as input.
[in]fc_info(Optional) Fully connected layer additional info

Definition at line 140 of file NEFullyConnectedLayer.cpp.

142 {
144 
145  // Perform validate step
147  weights->info(),
148  biases != nullptr ? biases->info() : nullptr,
149  output->info(),
150  fc_info));
151 
152  _are_weights_converted = true;
153  _are_weights_reshaped = fc_info.transpose_weights ? fc_info.are_weights_reshaped : true;
154  _is_fc_after_conv = true;
155  _accumulate_biases = false;
156  _is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
157  _original_weights = weights;
158 
159  if(_weights_manager)
160  {
161  _weights_manager->manage(weights);
162  }
163 
164  // Configure gemmlowp output
165  if(_is_quantized)
166  {
167  _gemmlowp_output.allocator()->init(output->info()->clone()->set_is_resizable(true).reset_padding().set_data_type(DataType::S32));
168  }
169 
170  // Configure accumulate biases kernel for non quantized asymmetric types
171  if(biases != nullptr && !_is_quantized)
172  {
173  _accumulate_biases = true;
174 
175  // Configure accumulate biases kernel
176  _accumulate_biases_kernel.configure(output, biases);
177  }
178 
179  // With the Fully Connected layer we can have 4 different cases:
180  // 1) Convolution layer -> Fully Connected layer without batches
181  // 2) Fully Connected layer -> Fully Connected layer without batches
182  // 3) Convolution layer -> Fully Connected layer with batches
183  // 4) Fully Connected layer -> Fully Connected layer with batches
184 
185  const ITensor *weights_to_use = weights;
186 
187  // Check if we have a fully connected layer with batches
188  const bool is_batched_fc_layer = output->info()->dimension(1) > 1;
189  if(is_batched_fc_layer)
190  {
191  _is_fc_after_conv = (TensorShape::num_max_dimensions >= 4) && (std::equal(input->info()->tensor_shape().cbegin() + 3,
192  input->info()->tensor_shape().cend(),
193  output->info()->tensor_shape().cbegin() + 1));
194  }
195  else
196  {
197  _is_fc_after_conv = input->info()->num_dimensions() > 1;
198  }
199 
200  // Reshape weights if needed
201  if(!_are_weights_reshaped)
202  {
203  if(_weights_manager && _weights_manager->are_weights_managed(weights))
204  {
205  _reshape_weights_managed_function.configure(weights);
206  weights_to_use = _weights_manager->acquire(weights, &_reshape_weights_managed_function);
207  }
208  else
209  {
210  // Reshape the weights
211  _reshape_weights_function.configure(weights, &_reshape_weights_output);
212  weights_to_use = &_reshape_weights_output;
213  }
214  }
215 
216  // Convert weights if needed
217  if(_is_fc_after_conv && (input->info()->data_layout() != fc_info.weights_trained_layout))
218  {
219  if(_weights_manager && _weights_manager->are_weights_managed(weights_to_use))
220  {
221  _convert_weights_managed.configure(weights_to_use,
222  input->info()->tensor_shape(),
223  fc_info.weights_trained_layout);
224  weights_to_use = _weights_manager->acquire(weights, &_convert_weights_managed);
225  }
226  else
227  {
228  // Convert weights
229  _convert_weights.configure(weights_to_use,
230  &_converted_weights_output,
231  input->info()->tensor_shape(),
232  fc_info.weights_trained_layout);
233 
234  weights_to_use = &_converted_weights_output;
235  }
236  _are_weights_converted = false;
237  }
238 
239  ITensor *tmp_output = (_is_quantized) ? &_gemmlowp_output : output;
240  if(_is_fc_after_conv)
241  {
242  // Fully Connected layer after a Convolution Layer without batches
243  configure_conv_fc(input, weights_to_use, tmp_output);
244  }
245  else
246  {
247  // Fully Connected layer after a Fully Connected Layer without batches
248  configure_fc_fc(input, weights_to_use, tmp_output);
249  }
250 
251  // Configure output stage for asymmetric quantized types
252  if(_is_quantized)
253  {
254  const UniformQuantizationInfo iq_info = input->info()->quantization_info().uniform();
256  const UniformQuantizationInfo oq_info = output->info()->quantization_info().uniform();
257 
258  float multiplier = (iq_info.scale * wq_info.scale) / oq_info.scale;
259  int output_multiplier;
260  int output_shift;
261  quantization::calculate_quantized_multiplier_less_than_one(multiplier, &output_multiplier, &output_shift);
262  _gemmlowp_output_stage.configure(&_gemmlowp_output, biases, output, output_multiplier, output_shift, oq_info.offset);
263  _gemmlowp_output.allocator()->allocate();
264  }
265 
266  _are_weights_reshaped = _are_weights_reshaped || fc_info.retain_internal_weights;
267 }
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.
bool retain_internal_weights
Retain internal reshaped weights.
Definition: Types.h:807
void configure(const ITensor *input, const ITensor *bias, ITensor *output, int result_fixedpoint_multiplier, int result_shift, int result_offset_after_shift, int min=0, int max=0)
Initialise the kernel's inputs, output.
QuantizationInfo quantization_info() const override
Get the quantization settings (scale and offset) of the tensor.
Definition: TensorInfo.h:311
#define ARM_COMPUTE_ERROR_THROW_ON(status)
Definition: Error.h:455
Quantization info when assuming per layer quantization.
void manage(const ITensor *weights, ITransformWeights *parent=nullptr)
Start managing a weights tensor.
Interface for NEON tensor.
Definition: ITensor.h:36
TensorAllocator * allocator()
Return a pointer to the tensor's allocator.
Definition: Tensor.cpp:48
1 channel, 1 S32 per channel
bool are_weights_managed(const ITensor *weights)
Check if the weights are managed.
virtual const TensorShape & tensor_shape() const =0
Size for each dimension of the tensor.
bool are_weights_reshaped
Reshape the weights tensor if false.
Definition: Types.h:806
void allocate() override
Allocate size specified by TensorInfo of CPU memory.
UniformQuantizationInfo uniform() const
Return per layer quantization info.
virtual std::unique_ptr< T > clone() const =0
Provide a clone of the current object of class T.
virtual ITensorInfo * info() const =0
Interface to be implemented by the child class to return the tensor's metadata.
void configure(const ITensor *input, const TensorShape &original_input_shape, DataLayout data_layout)
virtual QuantizationInfo quantization_info() const =0
Get the quantization settings (scale and offset) of the tensor.
void configure(const ITensor *input, ITensor *output, const TensorShape &original_input_shape, DataLayout data_layout)
Initialize the function.
bool is_data_type_quantized_asymmetric(DataType dt)
Check if a given data type is of asymmetric quantized type.
Definition: Utils.h:1044
std::array< T, num_max_dimensions >::const_iterator cbegin() const
Returns a read-only (constant) iterator that points to the first element in the dimension array.
Definition: Dimensions.h:210
#define ARM_COMPUTE_ERROR_ON_NULLPTR(...)
Definition: Validate.h:161
static Status validate(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output, FullyConnectedLayerInfo fc_info=FullyConnectedLayerInfo())
Static function to check if given info will lead to a valid configuration of NEFullyConnectedLayer.
DataLayout weights_trained_layout
Layout that the weights have been trained with.
Definition: Types.h:804
bool transpose_weights
Transpose weights if true.
Definition: Types.h:805
void configure(const ITensor *input, ITensor *output)
Set the input and output tensors.
Status calculate_quantized_multiplier_less_than_one(float multiplier, int *quant_multiplier, int *right_shift)
Calculate quantized representation of multiplier with value less than one.
static constexpr size_t num_max_dimensions
Number of dimensions the tensor has.
Definition: Dimensions.h:45
void configure(ITensor *accum, const ITensor *biases)
Set the accumulate buffer and the biases of the kernel.
ITensor * acquire(const ITensor *weights, ITransformWeights *weights_transform)
Acquire the requested reshape tensor of the selected weights.

References IWeightsManager::acquire(), TensorAllocator::allocate(), Tensor::allocator(), IWeightsManager::are_weights_managed(), FullyConnectedLayerInfo::are_weights_reshaped, ARM_COMPUTE_ERROR_ON_NULLPTR, ARM_COMPUTE_ERROR_THROW_ON, arm_compute::quantization::calculate_quantized_multiplier_less_than_one(), Dimensions< T >::cbegin(), ICloneable< T >::clone(), NEConvertFullyConnectedWeights::configure(), NEFullyConnectedLayerReshapeWeights::configure(), NEGEMMMatrixAccumulateBiasesKernel::configure(), NEFullyConnectedLayerReshapeWeightsManaged::configure(), NEConvertFullyConnectedWeightsManaged::configure(), NEGEMMLowpQuantizeDownInt32ToUint8ScaleByFixedPoint::configure(), ITensorInfo::dimension(), ITensor::info(), CLTensor::info(), TensorAllocator::init(), arm_compute::test::validation::input, arm_compute::is_data_type_quantized_asymmetric(), IWeightsManager::manage(), Dimensions< uint32_t >::num_max_dimensions, UniformQuantizationInfo::offset, ITensorInfo::quantization_info(), TensorInfo::quantization_info(), FullyConnectedLayerInfo::retain_internal_weights, arm_compute::S32, UniformQuantizationInfo::scale, ITensorInfo::tensor_shape(), FullyConnectedLayerInfo::transpose_weights, QuantizationInfo::uniform(), NEFullyConnectedLayer::validate(), arm_compute::test::validation::weights, and FullyConnectedLayerInfo::weights_trained_layout.

Referenced by NERNNLayer::configure(), and NELSTMLayer::configure().

◆ operator=() [1/2]

NEFullyConnectedLayer& operator= ( const NEFullyConnectedLayer )
delete

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

◆ operator=() [2/2]

NEFullyConnectedLayer& operator= ( NEFullyConnectedLayer &&  )
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 404 of file NEFullyConnectedLayer.cpp.

405 {
406  if(!_is_prepared)
407  {
408  if(!_weights_manager)
409  {
410  ARM_COMPUTE_ERROR_ON(!_original_weights->is_used());
411  }
412 
413  auto release_unused = [](Tensor * w)
414  {
415  if(!w->is_used())
416  {
417  w->allocator()->free();
418  }
419  };
420 
421  // Pointer to current weights
422  const ITensor *cur_weights = _original_weights;
423 
424  // Reshape of the weights (happens only once)
425  if(!_are_weights_reshaped)
426  {
427  if(_weights_manager && _weights_manager->are_weights_managed(_original_weights))
428  {
429  cur_weights = _weights_manager->run(cur_weights, &_reshape_weights_managed_function);
430  }
431  else
432  {
433  // Reshape of the weights (happens only once)
434  if(!_are_weights_reshaped)
435  {
436  // Run reshape weights kernel and mark weights as unused
437  _reshape_weights_output.allocator()->allocate();
438  _reshape_weights_function.run();
439  }
440  cur_weights->mark_as_unused();
441  cur_weights = &_reshape_weights_output;
442  }
443  _are_weights_reshaped = true;
444  }
445 
446  // Convert weights if needed (happens only once)
447  if(!_are_weights_converted)
448  {
449  if(_weights_manager && _weights_manager->are_weights_managed(cur_weights))
450  {
451  _weights_manager->run(cur_weights, &_convert_weights_managed);
452  }
453  else
454  {
455  _converted_weights_output.allocator()->allocate();
456  _convert_weights.run();
457  cur_weights->mark_as_unused();
458  }
459 
460  _are_weights_converted = true;
461  }
462 
463  // Release reshaped weights if unused
464  release_unused(&_reshape_weights_output);
465 
466  // Prepare GEMM prepare and release unused weights
467  if(!_is_quantized)
468  {
469  _mm_gemm.prepare();
470  }
471 
472  // Release converted weights if unused
473  release_unused(&_reshape_weights_output);
474  release_unused(&_converted_weights_output);
475 
476  _is_prepared = true;
477  }
478 }
SimpleTensor< float > w
Definition: DFT.cpp:156
void run() override final
Run the kernels contained in the function.
bool is_used() const
Flags if the tensor is used or not.
Definition: ITensor.cpp:162
#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
Interface for NEON tensor.
Definition: ITensor.h:36
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
bool are_weights_managed(const ITensor *weights)
Check if the weights are managed.
void allocate() override
Allocate size specified by TensorInfo of CPU memory.
Basic implementation of the tensor interface.
Definition: Tensor.h:37
void prepare() override
Prepare the function for executing.
Definition: NEGEMM.cpp:335
ITensor * run(const ITensor *weights, ITransformWeights *weights_transform)
Run the reshape function.
void run() override
Run the kernels contained in the function.

References TensorAllocator::allocate(), Tensor::allocator(), IWeightsManager::are_weights_managed(), ARM_COMPUTE_ERROR_ON, ITensor::is_used(), ITensor::mark_as_unused(), NEGEMM::prepare(), INESimpleFunctionNoBorder::run(), NEConvertFullyConnectedWeights::run(), IWeightsManager::run(), and arm_compute::test::validation::w.

Referenced by NERNNLayer::prepare(), and NEFullyConnectedLayer::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 368 of file NEFullyConnectedLayer.cpp.

369 {
370  prepare();
371 
372  MemoryGroupResourceScope scope_mg(_memory_group);
373 
374  // Linearize input if it comes from a convolutional layer
375  if(_is_fc_after_conv)
376  {
377  NEScheduler::get().schedule(&_flatten_kernel, Window::DimY);
378  }
379 
380  // Run matrix multiply
381  if(_is_quantized)
382  {
383  _mm_gemmlowp.run();
384  }
385  else
386  {
387  _mm_gemm.run();
388  }
389 
390  // Accumulate biases if provided
391  if(_is_quantized)
392  {
393  _gemmlowp_output_stage.run();
394  }
395  else
396  {
397  if(_accumulate_biases)
398  {
399  NEScheduler::get().schedule(&_accumulate_biases_kernel, Window::DimY);
400  }
401  }
402 }
void run() override final
Run the kernels contained in the function.
void run() override
Run the kernels contained in the function.
Definition: NEGEMM.cpp:285
void run() override
Run the kernels contained in the function.
static constexpr size_t DimY
Alias for dimension 1 also known as Y dimension.
Definition: Window.h:45
Memory group resources scope handling class.
Definition: IMemoryGroup.h:82
virtual void schedule(ICPPKernel *kernel, const Hints &hints)=0
Runs the kernel in the same thread as the caller synchronously.
void prepare() override
Prepare the function for executing.
static IScheduler & get()
Access the scheduler singleton.
Definition: Scheduler.cpp:95

References Window::DimY, Scheduler::get(), NEFullyConnectedLayer::prepare(), INESimpleFunctionNoBorder::run(), NEGEMM::run(), NEGEMMLowpMatrixMultiplyCore::run(), and IScheduler::schedule().

Referenced by NERNNLayer::run(), and NELSTMLayer::run().

◆ validate()

Status validate ( const ITensorInfo input,
const ITensorInfo weights,
const ITensorInfo biases,
const ITensorInfo output,
FullyConnectedLayerInfo  fc_info = FullyConnectedLayerInfo() 
)
static

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

Parameters
[in]inputSource tensor info. Data type supported: QASYMM8/F16/F32.
[in]weightsWeights tensor info. The weights must be 2 dimensional. If this function is called after a Convolution Layer, the (transposed) weights will have as many rows as the product of the first 3 input's dimensions. If it is called after another FullyConnected Layer, the (transposed) weights will have as many rows as the input's first dimension. Data type supported: Same as input.
[in]biasesBias tensor info. Can be nullptr. Data type supported:Same as input.
[out]outputDestination tensor info. Its shape should be equal to the output of a matrix multiplication between:
  • The output of im2col on the input and the (transposed) 2D weights, if the function is called after a Convolution Layer
  • The input tensor and the (transposed) 2D weights, if the function is called after another FullyConnected Layer. Data type supported: Same as input.
[in]fc_info(Optional) Fully connected layer additional info
Returns
a status

Definition at line 269 of file NEFullyConnectedLayer.cpp.

271 {
276  ARM_COMPUTE_RETURN_ERROR_ON(weights->num_dimensions() > 2);
277 
278  bool weights_reshaped = fc_info.transpose_weights ? fc_info.are_weights_reshaped : true;
279  bool is_fc_after_conv = true;
280  bool is_quantized = is_data_type_quantized_asymmetric(input->data_type());
281 
282  const ITensorInfo &flatten_input = TensorInfo(input->clone()->set_is_resizable(true).reset_padding().set_tensor_shape(compute_flatten_shape(input)));
283  const ITensorInfo &reshaped_weights = TensorInfo(weights->clone()->set_is_resizable(true).reset_padding().set_tensor_shape(compute_transposed_shape(*weights)));
284  const ITensorInfo &converted_weights = weights_reshaped ? TensorInfo(weights->clone()->set_is_resizable(true).reset_padding()) : TensorInfo(*reshaped_weights.clone());
285  const ITensorInfo &gemmlowp_output = TensorInfo(output->clone()->set_is_resizable(true).reset_padding().set_data_type(DataType::S32));
286 
287  // Configure accumulate biases kernel for non quantized asymmetric types
288  if(biases != nullptr && !is_quantized)
289  {
292  }
293 
294  // With the Fully Connected layer we can have 4 different cases:
295  // 1) Convolution layer -> Fully Connected layer without batches
296  // 2) Fully Connected layer -> Fully Connected layer without batches
297  // 3) Convolution layer -> Fully Connected layer with batches
298  // 4) Fully Connected layer -> Fully Connected layer with batches
299 
300  const ITensorInfo *input_to_use = input;
301  const ITensorInfo *weights_to_use = weights;
302  const ITensorInfo *tmp_output = (is_quantized) ? &gemmlowp_output : output;
303 
304  // Check if we have a fully connected layer with batches
305  const bool is_batched_fc_layer = output->dimension(1) > 1;
306 
307  if(is_batched_fc_layer)
308  {
309  is_fc_after_conv = (TensorShape::num_max_dimensions >= 4) && (std::equal(input->tensor_shape().cbegin() + 3,
310  input->tensor_shape().cend(),
311  output->tensor_shape().cbegin() + 1));
312  }
313  else
314  {
315  is_fc_after_conv = input->num_dimensions() > 1;
316  }
317 
318  if(!weights_reshaped)
319  {
320  // Validate reshape weights kernel
322  weights_to_use = &reshaped_weights;
323  }
324 
325  if(is_fc_after_conv && (input->data_layout() != fc_info.weights_trained_layout))
326  {
327  // Validate convert weights kernel
329  &converted_weights,
330  input->tensor_shape(),
331  fc_info.weights_trained_layout));
332  weights_to_use = &converted_weights;
333  }
334 
335  if(is_fc_after_conv)
336  {
337  // Fully Connected layer after a Convolution Layer without batches
338  ARM_COMPUTE_RETURN_ERROR_ON((weights_to_use->dimension(1) != (input->dimension(0) * input->dimension(1) * input->dimension(2))));
339 
340  // Validate flatten kernel
342  input_to_use = &flatten_input;
343  }
344  else
345  {
346  // Fully Connected layer after a Fully Connected Layer without batches
347  ARM_COMPUTE_RETURN_ERROR_ON(input->dimension(0) != weights_to_use->dimension(1));
348  }
349  // Validate matrix multiply kernel
350  ARM_COMPUTE_RETURN_ON_ERROR(validate_mm(*input_to_use, *weights_to_use, *tmp_output));
351 
352  // Validate output stage for asymmetric quantized types
353  if(is_quantized)
354  {
355  const UniformQuantizationInfo iq_info = input->quantization_info().uniform();
356  const UniformQuantizationInfo wq_info = weights->quantization_info().uniform();
357  const UniformQuantizationInfo oq_info = output->quantization_info().uniform();
358  const float multiplier = iq_info.scale * wq_info.scale / oq_info.scale;
359 
360  ARM_COMPUTE_UNUSED(multiplier);
361  ARM_COMPUTE_RETURN_ERROR_ON(multiplier > 1.0f);
363  }
364 
365  return Status{};
366 }
virtual size_t dimension(size_t index) const =0
Return the size of the requested dimension.
bool retain_internal_weights
Retain internal reshaped weights.
Definition: Types.h:807
#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
#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
Quantization info when assuming per layer quantization.
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
1 channel, 1 F16 per channel
TensorShape compute_transposed_shape(const ITensorInfo &input)
Calculate the transposed shape of a tensor.
static Status validate(const ITensorInfo *input, const ITensorInfo *output)
Static function to check if given info will lead to a valid configuration of NEFullyConnectedLayerRes...
1 channel, 1 S32 per channel
TensorShape compute_flatten_shape(const ITensorInfo *input)
Calculate the flattened output shape of a tensor.
#define ARM_COMPUTE_UNUSED(...)
To avoid unused variables warnings.
Definition: Error.h:152
virtual const TensorShape & tensor_shape() const =0
Size for each dimension of the tensor.
quantized, asymmetric fixed-point 8-bit number unsigned
bool are_weights_reshaped
Reshape the weights tensor if false.
Definition: Types.h:806
UniformQuantizationInfo uniform() const
Return per layer quantization info.
virtual std::unique_ptr< T > clone() const =0
Provide a clone of the current object of class T.
virtual QuantizationInfo quantization_info() const =0
Get the quantization settings (scale and offset) of the tensor.
bool is_data_type_quantized_asymmetric(DataType dt)
Check if a given data type is of asymmetric quantized type.
Definition: Utils.h:1044
#define ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(...)
Definition: Validate.h:163
std::array< T, num_max_dimensions >::const_iterator cbegin() const
Returns a read-only (constant) iterator that points to the first element in the dimension array.
Definition: Dimensions.h:210
DataLayout weights_trained_layout
Layout that the weights have been trained with.
Definition: Types.h:804
static Status validate(const ITensorInfo *input, const ITensorInfo *output, const TensorShape &original_input_shape, DataLayout data_layout)
Static function to check if given info will lead to a valid configuration of NEConvertFullyConnectedW...
static Status validate(const ITensorInfo *accum, const ITensorInfo *biases)
Static function to check if given info will lead to a valid configuration of NEGEMMMatrixAccumulateBi...
bool transpose_weights
Transpose weights if true.
Definition: Types.h:805
Store the tensor's metadata.
Definition: TensorInfo.h:45
static Status validate(const ITensorInfo *input, const ITensorInfo *output)
Static function to check if given info will lead to a valid configuration of NEFlattenLayerKernel.
static constexpr size_t num_max_dimensions
Number of dimensions the tensor has.
Definition: Dimensions.h:45
static Status validate(const ITensorInfo *input, const ITensorInfo *bias, const ITensorInfo *output, int min=0, int max=0)
Static function to check if given info will lead to a valid configuration of NEGEMMLowpQuantizeDownIn...

References FullyConnectedLayerInfo::are_weights_reshaped, 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_ERROR_ON_NULLPTR, ARM_COMPUTE_RETURN_ON_ERROR, ARM_COMPUTE_UNUSED, Dimensions< T >::cbegin(), ICloneable< T >::clone(), arm_compute::misc::shape_calculator::compute_flatten_shape(), arm_compute::misc::shape_calculator::compute_transposed_shape(), ITensorInfo::dimension(), arm_compute::F16, arm_compute::F32, arm_compute::test::validation::input, arm_compute::is_data_type_quantized_asymmetric(), Dimensions< uint32_t >::num_max_dimensions, arm_compute::QASYMM8, ITensorInfo::quantization_info(), FullyConnectedLayerInfo::retain_internal_weights, arm_compute::S32, UniformQuantizationInfo::scale, ITensorInfo::tensor_shape(), FullyConnectedLayerInfo::transpose_weights, QuantizationInfo::uniform(), NEConvertFullyConnectedWeights::validate(), NEFullyConnectedLayerReshapeWeights::validate(), NEGEMMMatrixAccumulateBiasesKernel::validate(), NEFlattenLayerKernel::validate(), NEGEMMLowpQuantizeDownInt32ToUint8ScaleByFixedPoint::validate(), arm_compute::test::validation::weights, and FullyConnectedLayerInfo::weights_trained_layout.

Referenced by NEFullyConnectedLayer::configure(), NERNNLayer::validate(), and NELSTMLayer::validate().


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