317{
318 ARM_COMPUTE_UNUSED(fc_info.retain_internal_weights);
319 ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, weights, output);
320 ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::QASYMM8, DataType::F16,
321 DataType::F32);
322 ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(input, weights, output);
323 ARM_COMPUTE_RETURN_ERROR_ON(weights->num_dimensions() > 2);
324
325 bool weights_reshaped = fc_info.transpose_weights ? fc_info.are_weights_reshaped : true;
326 bool is_fc_after_conv = true;
327
328 const ITensorInfo &flatten_input =
329 TensorInfo(
input->clone()->set_is_resizable(
true).reset_padding().set_tensor_shape(
330 compute_flatten_shape(input)));
331 const ITensorInfo &reshaped_weights =
332 TensorInfo(weights->clone()->set_is_resizable(true).reset_padding().set_tensor_shape(
333 compute_transposed_shape(*weights)));
334 const ITensorInfo &converted_weights =
335 weights_reshaped ? TensorInfo(weights->clone()->set_is_resizable(true).reset_padding())
336 : TensorInfo(*reshaped_weights.
clone());
337
338
339
340
341
342
343
344 const ITensorInfo *input_to_use =
input;
345 const ITensorInfo *weights_to_use = weights;
346
347
348 const bool is_batched_fc_layer =
output->dimension(1) > 1;
349
350 if (is_batched_fc_layer)
351 {
352 is_fc_after_conv = (TensorShape::num_max_dimensions >= 4) &&
353 (std::equal(
input->tensor_shape().cbegin() + 3,
input->tensor_shape().cend(),
354 output->tensor_shape().cbegin() + 1));
355 }
356 else
357 {
358 is_fc_after_conv =
input->num_dimensions() > 1;
359 }
360
361 if (!weights_reshaped)
362 {
363
364 ARM_COMPUTE_RETURN_ON_ERROR(NETranspose::validate(weights, &reshaped_weights));
365 weights_to_use = &reshaped_weights;
366 }
367
368 if (is_fc_after_conv && (
input->data_layout() != fc_info.weights_trained_layout))
369 {
370
371 ARM_COMPUTE_RETURN_ON_ERROR(NEConvertFullyConnectedWeights::validate(
372 weights_to_use, &converted_weights,
input->tensor_shape(), fc_info.weights_trained_layout));
373 weights_to_use = &converted_weights;
374 }
375
376 if (is_fc_after_conv)
377 {
378
379 ARM_COMPUTE_RETURN_ERROR_ON(
380 (weights_to_use->dimension(1) !=
382
383
384 ARM_COMPUTE_RETURN_ON_ERROR(NEFlattenLayer::validate(input, &flatten_input));
385 input_to_use = &flatten_input;
386 }
387 else
388 {
389
390 ARM_COMPUTE_RETURN_ERROR_ON(
input->dimension(0) != weights_to_use->dimension(1));
391 }
392
393 ARM_COMPUTE_RETURN_ON_ERROR(
394 validate_mm(*input_to_use, *weights_to_use, biases, *output, fc_info));
395
396 return Status{};
397}
luci::CircleConst * clone(luci::CircleConst *node)
Return cloned object of CircleConst node.