| 1147 | } |
| 1148 | |
| 1149 | inline void HybridConv(const ConvParams& params, float* scaling_factors_ptr, |
| 1150 | const RuntimeShape& input_shape, |
| 1151 | const int8_t* input_data, |
| 1152 | const RuntimeShape& filter_shape, |
| 1153 | const int8_t* filter_data, |
| 1154 | const RuntimeShape& bias_shape, const float* bias_data, |
| 1155 | const RuntimeShape& output_shape, float* output_data, |
| 1156 | const RuntimeShape& im2col_shape, int8_t* im2col_data) { |
| 1157 | const int stride_width = params.stride_width; |
| 1158 | const int stride_height = params.stride_height; |
| 1159 | const float output_activation_min = params.float_activation_min; |
| 1160 | const float output_activation_max = params.float_activation_max; |
| 1161 | TFLITE_DCHECK_EQ(input_shape.DimensionsCount(), 4); |
| 1162 | TFLITE_DCHECK_EQ(filter_shape.DimensionsCount(), 4); |
| 1163 | TFLITE_DCHECK_EQ(output_shape.DimensionsCount(), 4); |
| 1164 | |
| 1165 | const int batch_size = input_shape.Dims(0); |
| 1166 | const int filter_width = filter_shape.Dims(2); |
| 1167 | const int filter_height = filter_shape.Dims(1); |
| 1168 | |
| 1169 | const int8_t* gemm_input_data = nullptr; |
| 1170 | int num_input; |
| 1171 | const bool need_im2col = stride_width != 1 || stride_height != 1 || |
| 1172 | filter_width != 1 || filter_height != 1; |
| 1173 | |
| 1174 | if (need_im2col) { |
| 1175 | TFLITE_DCHECK(im2col_data); |
| 1176 | // symmetric quantization assumes zero point of 0. |
| 1177 | const int input_zero_point = 0; |
| 1178 | |
| 1179 | Im2col(params, filter_height, filter_width, input_zero_point, input_shape, |
| 1180 | input_data, im2col_shape, im2col_data); |
| 1181 | gemm_input_data = im2col_data; |
| 1182 | num_input = im2col_shape.FlatSize(); |
| 1183 | } else { |
| 1184 | TFLITE_DCHECK(!im2col_data); |
| 1185 | gemm_input_data = input_data; |
| 1186 | num_input = input_shape.FlatSize(); |
| 1187 | } |
| 1188 | |
| 1189 | // Flatten 4D matrices into 2D matrices for matrix multiplication. |
| 1190 | |
| 1191 | // Flatten so that each filter has its own row. |
| 1192 | const int filter_rows = filter_shape.Dims(0); |
| 1193 | const int filter_cols = FlatSizeSkipDim(filter_shape, 0); |
| 1194 | |
| 1195 | // In MatrixBatchVectorMultiplyAccumulate, each output value is the |
| 1196 | // dot product of one row of the first matrix with one row of the second |
| 1197 | // matrix. Therefore, the number of cols in each matrix are equivalent. |
| 1198 | // |
| 1199 | // After Im2Col, each input patch becomes a row. |
| 1200 | const int gemm_input_cols = filter_cols; |
| 1201 | const int gemm_input_rows = num_input / gemm_input_cols; |
| 1202 | |
| 1203 | const int output_cols = output_shape.Dims(3); |
| 1204 | const int output_rows = FlatSizeSkipDim(output_shape, 3); |
| 1205 | TFLITE_DCHECK_EQ(output_cols, filter_rows); |
| 1206 | TFLITE_DCHECK_EQ(output_rows, gemm_input_rows); |
no test coverage detected