| 522 | |
| 523 | template <KernelType kernel_type> |
| 524 | void EvalFloat(TfLiteContext* context, TfLiteNode* node, |
| 525 | TfLiteConvParams* params, OpData* data, TfLiteTensor* input, |
| 526 | TfLiteTensor* filter, TfLiteTensor* bias, TfLiteTensor* im2col, |
| 527 | TfLiteTensor* hwcn_weights, TfLiteTensor* output) { |
| 528 | float output_activation_min, output_activation_max; |
| 529 | CalculateActivationRange(params->activation, &output_activation_min, |
| 530 | &output_activation_max); |
| 531 | KernelType effective_kernel_type = kernel_type; |
| 532 | // Fall back to the optimized path if multi-threaded conv is unsupported. |
| 533 | if ((kernel_type == kMultithreadOptimized) && |
| 534 | !data->supports_multithreaded_kernel) { |
| 535 | effective_kernel_type = kGenericOptimized; |
| 536 | } |
| 537 | ConvParams op_params; |
| 538 | op_params.padding_type = RuntimePaddingType(params->padding); |
| 539 | op_params.padding_values.width = data->padding.width; |
| 540 | op_params.padding_values.height = data->padding.height; |
| 541 | op_params.stride_width = params->stride_width; |
| 542 | op_params.stride_height = params->stride_height; |
| 543 | op_params.dilation_width_factor = params->dilation_width_factor; |
| 544 | op_params.dilation_height_factor = params->dilation_height_factor; |
| 545 | op_params.float_activation_min = output_activation_min; |
| 546 | op_params.float_activation_max = output_activation_max; |
| 547 | switch (effective_kernel_type) { |
| 548 | case kReference: { |
| 549 | reference_ops::Conv(op_params, GetTensorShape(input), |
| 550 | GetTensorData<float>(input), GetTensorShape(filter), |
| 551 | GetTensorData<float>(filter), GetTensorShape(bias), |
| 552 | GetTensorData<float>(bias), GetTensorShape(output), |
| 553 | GetTensorData<float>(output), GetTensorShape(im2col), |
| 554 | GetTensorData<float>(im2col)); |
| 555 | break; |
| 556 | } |
| 557 | case kCblasOptimized: |
| 558 | case kGenericOptimized: { |
| 559 | optimized_ops::Conv(op_params, GetTensorShape(input), |
| 560 | GetTensorData<float>(input), GetTensorShape(filter), |
| 561 | GetTensorData<float>(filter), GetTensorShape(bias), |
| 562 | GetTensorData<float>(bias), GetTensorShape(output), |
| 563 | GetTensorData<float>(output), GetTensorShape(im2col), |
| 564 | GetTensorData<float>(im2col), |
| 565 | CpuBackendContext::GetFromContext(context)); |
| 566 | break; |
| 567 | } |
| 568 | case kMultithreadOptimized: { |
| 569 | #ifdef TFLITE_WITH_RUY |
| 570 | // See Register_CONV_2D: we should never be here when tflite_with_ruy |
| 571 | // was enabled. We #if out this code in order to get the corresponding |
| 572 | // binary size benefits. |
| 573 | TFLITE_DCHECK(false); |
| 574 | #else |
| 575 | const float* filter_data; |
| 576 | if (data->need_hwcn_weights) { |
| 577 | filter_data = GetTensorData<float>(hwcn_weights); |
| 578 | } else { |
| 579 | filter_data = GetTensorData<float>(filter); |
| 580 | } |
| 581 | multithreaded_ops::Conv( |
no test coverage detected