| 328 | } |
| 329 | |
| 330 | void ClFullyConnected::configure(const CLCompileContext &compile_context, |
| 331 | ITensorInfo *src, |
| 332 | ITensorInfo *weights, |
| 333 | ITensorInfo *biases, |
| 334 | ITensorInfo *dst, |
| 335 | FullyConnectedLayerInfo fc_info) |
| 336 | { |
| 337 | ARM_COMPUTE_ERROR_ON_NULLPTR(src, weights, dst); |
| 338 | const GPUTarget gpu_target = get_arch_from_target(CLScheduler::get().target()); |
| 339 | |
| 340 | // Perform validate step |
| 341 | ARM_COMPUTE_ERROR_THROW_ON(ClFullyConnected::validate(src, weights, biases, dst, fc_info)); |
| 342 | ARM_COMPUTE_LOG_PARAMS(src, weights, biases, dst, fc_info); |
| 343 | |
| 344 | _transpose_weights = fc_info.transpose_weights ? !fc_info.are_weights_reshaped : false; |
| 345 | _is_fc_after_conv = true; |
| 346 | _is_quantized = is_data_type_quantized_asymmetric(src->data_type()); |
| 347 | _is_prepared = fc_info.retain_internal_weights; |
| 348 | _weights_to_use = TensorInfo(*weights); |
| 349 | _weights_to_use_idx = ACL_SRC_1; |
| 350 | |
| 351 | // When using dynamic weights - use matmul kernels. |
| 352 | // Note: MatMul is not used in the following cases (Gemm is used as fallback) : |
| 353 | // 1. When the weights tensor is not dynamic |
| 354 | // 2. MatMul does not support broadcasting batch dimension, and therefore is disabled if fc is batched. |
| 355 | // 3. When FC is after convolution and src tensor data layout does not match weights trained data layout (weights conversion kernel is required) |
| 356 | const bool is_batched_fc_layer = dst->dimension(1) > 1; |
| 357 | _use_matmul = gpu_target != GPUTarget::MIDGARD && !weights->are_values_constant() && !is_batched_fc_layer && |
| 358 | !(src->num_dimensions() > 1 && (src->data_layout() != fc_info.weights_trained_layout)); |
| 359 | _dynamic_gemm = !weights->are_values_constant() && _transpose_weights && !_use_matmul; |
| 360 | |
| 361 | // With the Fully Connected layer we can have 4 different cases: |
| 362 | // 1) Convolution layer -> Fully Connected layer without batches |
| 363 | // 2) Fully Connected layer -> Fully Connected layer without batches |
| 364 | // 3) Convolution layer -> Fully Connected layer with batches |
| 365 | // 4) Fully Connected layer -> Fully Connected layer with batches |
| 366 | |
| 367 | // Check if we have a fully connected layer with batches |
| 368 | if (is_batched_fc_layer) |
| 369 | { |
| 370 | _is_fc_after_conv = (TensorShape::num_max_dimensions >= 4) && |
| 371 | (std::equal(src->tensor_shape().cbegin() + 3, src->tensor_shape().cend(), |
| 372 | dst->tensor_shape().cbegin() + 1)); |
| 373 | } |
| 374 | else |
| 375 | { |
| 376 | _is_fc_after_conv = src->num_dimensions() > 1; |
| 377 | } |
| 378 | |
| 379 | ITensorInfo *weights_used = weights; |
| 380 | |
| 381 | // Reshape weights if needed - Not needed when matmul is in use as matmul fuses transpose op. |
| 382 | if (_transpose_weights && !_use_matmul) |
| 383 | { |
| 384 | // Reshape the weights |
| 385 | _reshape_weights = std::make_unique<ClTranspose>(); |
| 386 | _reshape_weights->configure(compile_context, weights, &_reshaped_weights); |
| 387 | weights_used = &_reshaped_weights; |
no test coverage detected