| 231 | } |
| 232 | |
| 233 | void CpuFullyConnected::configure(const ITensorInfo *src, |
| 234 | const ITensorInfo *weights, |
| 235 | const ITensorInfo *biases, |
| 236 | ITensorInfo *dst, |
| 237 | FullyConnectedLayerInfo fc_info, |
| 238 | const WeightsInfo &weights_info) |
| 239 | { |
| 240 | ARM_COMPUTE_TRACE_EVENT(ARM_COMPUTE_PROF_CAT_CPU, ARM_COMPUTE_PROF_LVL_CPU, "CpuFullyConnected::configure"); |
| 241 | // Perform validate step |
| 242 | ARM_COMPUTE_ERROR_ON_NULLPTR(src, weights, dst); |
| 243 | ARM_COMPUTE_ERROR_THROW_ON( |
| 244 | CpuFullyConnected::validate(src, weights, biases != nullptr ? biases : nullptr, dst, fc_info, weights_info)); |
| 245 | ARM_COMPUTE_LOG_PARAMS(src, weights, biases, dst, fc_info); |
| 246 | |
| 247 | _needs_weights_conversion = false; |
| 248 | _needs_weights_reshape = fc_info.transpose_weights ? !fc_info.are_weights_reshaped : false; |
| 249 | _needs_weights_reshape = _needs_weights_reshape && !fc_info.retain_internal_weights; |
| 250 | _is_fc_after_conv = true; |
| 251 | _is_quantized_asymmetric = is_data_type_quantized_asymmetric(src->data_type()); |
| 252 | _is_prepared = false; |
| 253 | _trans_weights_idx = AuxTensorIdx::Count; |
| 254 | _enable_fast_math = fc_info.enable_fast_math; |
| 255 | _fixed_format = weights_info.weight_format() != WeightFormat::UNSPECIFIED; |
| 256 | _weight_format = weights_info.weight_format(); |
| 257 | _dynamic_weights = !weights->are_values_constant() && _needs_weights_reshape; |
| 258 | |
| 259 | // With the Fully Connected layer we can have 4 different cases: |
| 260 | // 1) Convolution layer -> Fully Connected layer without batches |
| 261 | // 2) Fully Connected layer -> Fully Connected layer without batches |
| 262 | // 3) Convolution layer -> Fully Connected layer with batches |
| 263 | // 4) Fully Connected layer -> Fully Connected layer with batches |
| 264 | |
| 265 | const ITensorInfo *weights_to_use = weights; |
| 266 | |
| 267 | // Check if we have a fully connected layer with batches |
| 268 | const bool is_batched_fc_layer = dst->dimension(1) > 1; |
| 269 | if (is_batched_fc_layer) |
| 270 | { |
| 271 | _is_fc_after_conv = (TensorShape::num_max_dimensions >= 4) && |
| 272 | (std::equal(src->tensor_shape().cbegin() + 3, src->tensor_shape().cend(), |
| 273 | dst->tensor_shape().cbegin() + 1)); |
| 274 | } |
| 275 | else |
| 276 | { |
| 277 | _is_fc_after_conv = src->num_dimensions() > 1; |
| 278 | } |
| 279 | |
| 280 | // Reshape weights if needed |
| 281 | if (_needs_weights_reshape) |
| 282 | { |
| 283 | // Reshape the weights |
| 284 | _transpose_weights = std::make_unique<kernels::CpuTransposeKernel>(); |
| 285 | _transpose_weights->configure(weights, &_reshaped_weights); |
| 286 | _reshaped_weights.set_are_values_constant(weights->are_values_constant()); |
| 287 | |
| 288 | weights_to_use = &_reshaped_weights; |
| 289 | _trans_weights_idx = AuxTensorIdx::TransposedWeights; |
| 290 | } |
no test coverage detected