ONE - On-device Neural Engine
Loading...
Searching...
No Matches
arm_compute::CLFullyConnectedLayerEx Class Reference

#include <CLFullyConnectedLayerEx.h>

Collaboration diagram for arm_compute::CLFullyConnectedLayerEx:

Public Member Functions

 CLFullyConnectedLayerEx (std::shared_ptr< IMemoryManager > memory_manager=nullptr, IWeightsManager *weights_manager=nullptr)
 
 CLFullyConnectedLayerEx (const CLFullyConnectedLayerEx &)=delete
 
 CLFullyConnectedLayerEx (CLFullyConnectedLayerEx &&)=default
 
CLFullyConnectedLayerExoperator= (const CLFullyConnectedLayerEx &)=delete
 
CLFullyConnectedLayerExoperator= (CLFullyConnectedLayerEx &&)=default
 
void configure (const ICLTensor *input, const ICLTensor *weights, const ICLTensor *biases, ICLTensor *output, FullyConnectedLayerInfo fc_info=FullyConnectedLayerInfo())
 
void run () override
 
void prepare () override
 

Static Public Member Functions

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

Detailed Description

Basic function to compute a Fully Connected layer on OpenCL. This function calls the following OpenCL kernels:

  1. CLIm2ColKernel (called when the input comes from a convolutional layer)
  2. CLFullyConnectedLayerReshapeWeightsEx (if are_weights_reshaped is set to false and transpose_weights is set to true ) (called once)
  3. CLGEMMMatrixMultiplyKernel or CLGEMMLowpMatrixMultiplyCore (if quantized asymmetric)
Note
The fully connected layer accepts "weights" tensors only with 2 dimensions.

Definition at line 106 of file CLFullyConnectedLayerEx.h.

Constructor & Destructor Documentation

◆ CLFullyConnectedLayerEx() [1/3]

arm_compute::CLFullyConnectedLayerEx::CLFullyConnectedLayerEx ( std::shared_ptr< IMemoryManager >  memory_manager = nullptr,
IWeightsManager *  weights_manager = nullptr 
)

Constructor

Definition at line 148 of file CLFullyConnectedLayerEx.cpp.

150 : _memory_group(memory_manager), _weights_manager(weights_manager), _convert_weights(),
151 _convert_weights_managed(), _reshape_weights_managed_function(), _flatten_layer(),
152 _reshape_weights_function(), _mm_gemm(memory_manager, weights_manager),
153 _mm_gemmlowp(memory_manager), _flatten_output(), _converted_weights_output(),
154 _reshape_weights_output(), _are_weights_converted(true), _are_weights_reshaped(true),
155 _is_fc_after_conv(true), _is_quantized(false), _is_prepared(false), _original_weights(nullptr)
156{
157}

◆ CLFullyConnectedLayerEx() [2/3]

arm_compute::CLFullyConnectedLayerEx::CLFullyConnectedLayerEx ( const CLFullyConnectedLayerEx )
delete

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

◆ CLFullyConnectedLayerEx() [3/3]

arm_compute::CLFullyConnectedLayerEx::CLFullyConnectedLayerEx ( CLFullyConnectedLayerEx &&  )
default

Default move constructor

Member Function Documentation

◆ configure()

void arm_compute::CLFullyConnectedLayerEx::configure ( const ICLTensor *  input,
const ICLTensor *  weights,
const ICLTensor *  biases,
ICLTensor *  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 251 of file CLFullyConnectedLayerEx.cpp.

254{
255 ARM_COMPUTE_ERROR_ON_NULLPTR(input, weights, output);
256
257 // Perform validate step
258 ARM_COMPUTE_ERROR_THROW_ON(CLFullyConnectedLayerEx::validate(
259 input->info(), weights->info(), biases != nullptr ? biases->info() : nullptr, output->info(),
260 fc_info));
261
262 _are_weights_converted = true;
263 _are_weights_reshaped = fc_info.transpose_weights ? fc_info.are_weights_reshaped : true;
264 _is_fc_after_conv = true;
265 _is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
266 _is_prepared = fc_info.retain_internal_weights;
267 _original_weights = weights;
268
269 if (_weights_manager)
270 {
271 _weights_manager->manage(weights);
272 }
273
274 const ICLTensor *weights_to_use = weights;
275
276 // With the Fully Connected layer we can have 4 different cases:
277 // 1) Convolution layer -> Fully Connected layer without batches
278 // 2) Fully Connected layer -> Fully Connected layer without batches
279 // 3) Convolution layer -> Fully Connected layer with batches
280 // 4) Fully Connected layer -> Fully Connected layer with batches
281
282 // Check if we have a fully connected layer with batches
283 const bool is_batched_fc_layer = output->info()->dimension(1) > 1;
284 if (is_batched_fc_layer)
285 {
286 _is_fc_after_conv =
287 (TensorShape::num_max_dimensions >= 4) &&
288 (std::equal(input->info()->tensor_shape().cbegin() + 3, input->info()->tensor_shape().cend(),
289 output->info()->tensor_shape().cbegin() + 1));
290 }
291 else
292 {
293 _is_fc_after_conv = input->info()->num_dimensions() > 1;
294 }
295
296 // Reshape weights if needed
297 if (!_are_weights_reshaped)
298 {
299 if (_weights_manager && _weights_manager->are_weights_managed(weights))
300 {
301 _reshape_weights_managed_function.configure(weights);
302 weights_to_use = utils::cast::polymorphic_downcast<ICLTensor *>(
303 _weights_manager->acquire(weights, &_reshape_weights_managed_function));
304 }
305 else
306 {
307 // Reshape the weights
308 _reshape_weights_function.configure(weights, &_reshape_weights_output);
309 weights_to_use = &_reshape_weights_output;
310 }
311 }
312
313 // Convert weights if needed
314 if (_is_fc_after_conv && (input->info()->data_layout() != fc_info.weights_trained_layout))
315 {
316 if (_weights_manager && _weights_manager->are_weights_managed(weights_to_use))
317 {
318 _convert_weights_managed.configure(weights_to_use, input->info()->tensor_shape(),
319 fc_info.weights_trained_layout);
320 weights_to_use = utils::cast::polymorphic_downcast<ICLTensor *>(
321 _weights_manager->acquire(weights, &_convert_weights_managed));
322 }
323 else
324 {
325 // Convert weights
326 _convert_weights.configure(weights_to_use, &_converted_weights_output,
327 input->info()->tensor_shape(), fc_info.weights_trained_layout);
328
329 weights_to_use = &_converted_weights_output;
330 }
331 _are_weights_converted = false;
332 }
333
334 if (_is_fc_after_conv)
335 {
336 // Fully Connected layer after a Convolution Layer without batches
337 configure_conv_fc(input, weights_to_use, biases, output, fc_info);
338 }
339 else
340 {
341 // Fully Connected layer after a Fully Connected Layer without batches
342 configure_fc_fc(input, weights_to_use, biases, output, fc_info);
343 }
344}
static Status validate(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output, FullyConnectedLayerInfo fc_info=FullyConnectedLayerInfo())
volatile const char info[]

References arm_compute::weights_transformations::CLFullyConnectedLayerReshapeWeightsExManaged::configure(), and validate().

◆ operator=() [1/2]

CLFullyConnectedLayerEx & arm_compute::CLFullyConnectedLayerEx::operator= ( CLFullyConnectedLayerEx &&  )
default

Default move assignment operator

References validate().

◆ operator=() [2/2]

CLFullyConnectedLayerEx & arm_compute::CLFullyConnectedLayerEx::operator= ( const CLFullyConnectedLayerEx )
delete

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

◆ prepare()

void arm_compute::CLFullyConnectedLayerEx::prepare ( )
override

Definition at line 503 of file CLFullyConnectedLayerEx.cpp.

504{
505 // DO NOTHING
506}

◆ run()

void arm_compute::CLFullyConnectedLayerEx::run ( )
override

Definition at line 430 of file CLFullyConnectedLayerEx.cpp.

431{
432 if (!_is_prepared)
433 {
434 if (!_are_weights_reshaped)
435 _reshape_weights_output.allocator()->allocate();
436 if (!_are_weights_converted)
437 _converted_weights_output.allocator()->allocate();
438 _is_prepared = true;
439 }
440
441 {
442 if (!_weights_manager)
443 {
444 ARM_COMPUTE_ERROR_ON(!_original_weights->is_used());
445 }
446
447 // Pointer to current weights
448 const ICLTensor *cur_weights = _original_weights;
449 // Reshape of the weights
450 if (!_are_weights_reshaped)
451 {
452 if (_weights_manager && _weights_manager->are_weights_managed(cur_weights))
453 {
454 _original_weights = utils::cast::polymorphic_downcast<ICLTensor *>(
455 _weights_manager->run(cur_weights, &_reshape_weights_managed_function));
456 }
457 else
458 {
459 _reshape_weights_function.run();
460 cur_weights = &_reshape_weights_output;
461 }
462 }
463
464 // Convert weights if needed
465 if (!_are_weights_converted)
466 {
467 if (_weights_manager && _weights_manager->are_weights_managed(cur_weights))
468 {
469 _weights_manager->run(cur_weights, &_convert_weights_managed);
470 }
471 else
472 {
473 _convert_weights.run();
474 }
475 }
476
477 // Prepare GEMM prepare
478 if (!_is_quantized)
479 {
480 _mm_gemm.prepare();
481 }
482 }
483
484 MemoryGroupResourceScope scope_mg(_memory_group);
485
486 // Linearize input if it comes from a convolutional layer
487 if (_is_fc_after_conv)
488 {
489 _flatten_layer.run();
490 }
491
492 // Run matrix multiply
493 if (_is_quantized)
494 {
495 _mm_gemmlowp.run();
496 }
497 else
498 {
499 _mm_gemm.run();
500 }
501}

Referenced by package.infer.session::inference().

◆ validate()

Status arm_compute::CLFullyConnectedLayerEx::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 CLFullyConnectedLayer

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 346 of file CLFullyConnectedLayerEx.cpp.

349{
350 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, weights, output);
351 ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::QASYMM8, DataType::F16,
352 DataType::F32);
353 ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, weights, output);
354 ARM_COMPUTE_RETURN_ERROR_ON(weights->num_dimensions() > 2);
355
356 bool weights_reshaped = fc_info.transpose_weights ? fc_info.are_weights_reshaped : true;
357 bool is_fc_after_conv = true;
358
359 const ITensorInfo &flatten_input =
360 TensorInfo(input->clone()->set_is_resizable(true).reset_padding().set_tensor_shape(
361 compute_flatten_shape(input)));
362 const ITensorInfo &reshaped_weights =
363 TensorInfo(weights->clone()->set_is_resizable(true).reset_padding().set_tensor_shape(
364 compute_transposed_shape(*weights)));
365 const ITensorInfo &converted_weights =
366 weights_reshaped ? TensorInfo(weights->clone()->set_is_resizable(true).reset_padding())
367 : TensorInfo(*reshaped_weights.clone());
368
369 // With the Fully Connected layer we can have 4 different cases:
370 // 1) Convolution layer -> Fully Connected layer without batches
371 // 2) Fully Connected layer -> Fully Connected layer without batches
372 // 3) Convolution layer -> Fully Connected layer with batches
373 // 4) Fully Connected layer -> Fully Connected layer with batches
374
375 const ITensorInfo *input_to_use = input;
376 const ITensorInfo *weights_to_use = weights;
377
378 // Check if we have a fully connected layer with batches
379 const bool is_batched_fc_layer = output->dimension(1) > 1;
380 if (is_batched_fc_layer)
381 {
382 is_fc_after_conv = (TensorShape::num_max_dimensions >= 4) &&
383 (std::equal(input->tensor_shape().cbegin() + 3, input->tensor_shape().cend(),
384 output->tensor_shape().cbegin() + 1));
385 }
386 else
387 {
388 is_fc_after_conv = input->num_dimensions() > 1;
389 }
390
391 if (!weights_reshaped)
392 {
393 // Validate reshape weights kernel
394 ARM_COMPUTE_RETURN_ON_ERROR(CLTranspose::validate(weights, &reshaped_weights));
395 weights_to_use = &reshaped_weights;
396 }
397
398 if (is_fc_after_conv && (input->data_layout() != fc_info.weights_trained_layout))
399 {
400 // Validate convert weights kernel
401 ARM_COMPUTE_RETURN_ON_ERROR(CLConvertFullyConnectedWeights::validate(
402 weights_to_use, &converted_weights, input->tensor_shape(), fc_info.weights_trained_layout));
403 weights_to_use = &converted_weights;
404 }
405
406 if (is_fc_after_conv)
407 {
408 // Fully Connected layer after a Convolution Layer without batches
409 ARM_COMPUTE_RETURN_ERROR_ON(
410 (weights_to_use->dimension(1) !=
411 (input->dimension(0) * input->dimension(1) * input->dimension(2))));
412
413 // Validate flatten kernel
414 ARM_COMPUTE_RETURN_ON_ERROR(CLFlattenLayer::validate(input, &flatten_input));
415 input_to_use = &flatten_input;
416 }
417 else
418 {
419 // Fully Connected layer after a Fully Connected Layer without batches
420 ARM_COMPUTE_RETURN_ERROR_ON(input->dimension(0) != weights_to_use->dimension(1));
421 }
422
423 // Validate matrix multiply kernel
424 ARM_COMPUTE_RETURN_ON_ERROR(
425 validate_mm(*input_to_use, *weights_to_use, biases, *output, fc_info));
426
427 return Status{};
428}
luci::CircleConst * clone(luci::CircleConst *node)
Return cloned object of CircleConst node.

Referenced by configure(), and operator=().


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