| 1048 | } |
| 1049 | |
| 1050 | inline void Conv(const ConvParams& params, const RuntimeShape& input_shape, |
| 1051 | const float* input_data, const RuntimeShape& filter_shape, |
| 1052 | const float* filter_data, const RuntimeShape& bias_shape, |
| 1053 | const float* bias_data, const RuntimeShape& output_shape, |
| 1054 | float* output_data, const RuntimeShape& im2col_shape, |
| 1055 | float* im2col_data, CpuBackendContext* cpu_backend_context) { |
| 1056 | const int stride_width = params.stride_width; |
| 1057 | const int stride_height = params.stride_height; |
| 1058 | const int dilation_width_factor = params.dilation_width_factor; |
| 1059 | const int dilation_height_factor = params.dilation_height_factor; |
| 1060 | const float output_activation_min = params.float_activation_min; |
| 1061 | const float output_activation_max = params.float_activation_max; |
| 1062 | TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); |
| 1063 | TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); |
| 1064 | TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); |
| 1065 | |
| 1066 | (void)im2col_data; |
| 1067 | (void)im2col_shape; |
| 1068 | gemmlowp::ScopedProfilingLabel label("Conv"); |
| 1069 | |
| 1070 | // NB: the float 0.0f value is represented by all zero bytes. |
| 1071 | const uint8 float_zero_byte = 0x00; |
| 1072 | const float* gemm_input_data = nullptr; |
| 1073 | const RuntimeShape* gemm_input_shape = nullptr; |
| 1074 | const int filter_width = filter_shape.Dims(2); |
| 1075 | const int filter_height = filter_shape.Dims(1); |
| 1076 | const bool need_dilated_im2col = |
| 1077 | dilation_width_factor != 1 || dilation_height_factor != 1; |
| 1078 | const bool need_im2col = stride_width != 1 || stride_height != 1 || |
| 1079 | filter_width != 1 || filter_height != 1; |
| 1080 | if (need_dilated_im2col) { |
| 1081 | DilatedIm2col(params, float_zero_byte, input_shape, input_data, |
| 1082 | filter_shape, output_shape, im2col_data); |
| 1083 | gemm_input_data = im2col_data; |
| 1084 | gemm_input_shape = &im2col_shape; |
| 1085 | } else if (need_im2col) { |
| 1086 | TFLITE_DCHECK(im2col_data); |
| 1087 | Im2col(params, filter_height, filter_width, float_zero_byte, input_shape, |
| 1088 | input_data, im2col_shape, im2col_data); |
| 1089 | gemm_input_data = im2col_data; |
| 1090 | gemm_input_shape = &im2col_shape; |
| 1091 | } else { |
| 1092 | // TODO(aselle): We need to make sure to not send im2col if it is not |
| 1093 | // needed. |
| 1094 | TFLITE_DCHECK(!im2col_data); |
| 1095 | gemm_input_data = input_data; |
| 1096 | gemm_input_shape = &input_shape; |
| 1097 | } |
| 1098 | |
| 1099 | const int gemm_input_dims = gemm_input_shape->DimensionsCount(); |
| 1100 | int m = FlatSizeSkipDim(*gemm_input_shape, gemm_input_dims - 1); |
| 1101 | int n = output_shape.Dims(3); |
| 1102 | int k = gemm_input_shape->Dims(gemm_input_dims - 1); |
| 1103 | |
| 1104 | #if defined(TF_LITE_USE_CBLAS) && defined(__APPLE__) |
| 1105 | // The following code computes matrix multiplication c = a * transponse(b) |
| 1106 | // with CBLAS, where: |
| 1107 | // * `a` is a matrix with dimensions (m, k). |
nothing calls this directly
no test coverage detected