| 219 | } |
| 220 | |
| 221 | TfLiteStatus Prepare(KernelType kernel_type, TfLiteContext* context, |
| 222 | TfLiteNode* node) { |
| 223 | auto* params = reinterpret_cast<TfLiteConvParams*>(node->builtin_data); |
| 224 | OpData* data = reinterpret_cast<OpData*>(node->user_data); |
| 225 | |
| 226 | bool has_bias = node->inputs->size == 3; |
| 227 | // Check number of inputs/outputs |
| 228 | TF_LITE_ENSURE(context, has_bias || node->inputs->size == 2); |
| 229 | TF_LITE_ENSURE_EQ(context, node->outputs->size, 1); |
| 230 | TfLiteTensor* output = &context->tensors[node->outputs->data[0]]; |
| 231 | TfLiteTensor* input = &context->tensors[node->inputs->data[0]]; |
| 232 | TfLiteTensor* filter = &context->tensors[node->inputs->data[1]]; |
| 233 | |
| 234 | // Check dimensionality of input, filter |
| 235 | TF_LITE_ENSURE_EQ(context, input->dims->size, 4); |
| 236 | TF_LITE_ENSURE_EQ(context, filter->dims->size, 4); |
| 237 | // Check input channels matching filter |
| 238 | TF_LITE_ENSURE_EQ(context, input->dims->data[3], filter->dims->data[3]); |
| 239 | |
| 240 | // Check types. (We assume that UINT8 refers to quantized tensors) |
| 241 | TfLiteType input_type = input->type; |
| 242 | TF_LITE_ENSURE(context, input_type == kTfLiteFloat32 || |
| 243 | input_type == kTfLiteUInt8 || |
| 244 | input_type == kTfLiteInt8); |
| 245 | TF_LITE_ENSURE_EQ(context, output->type, input_type); |
| 246 | |
| 247 | TfLiteTensor* bias = nullptr; |
| 248 | |
| 249 | // TODO(ahentz): At this point the optimized versions require 'bias'. We can |
| 250 | // either change that or document that convolution requires it. |
| 251 | TF_LITE_ENSURE(context, has_bias); |
| 252 | |
| 253 | if (has_bias) { |
| 254 | bias = &context->tensors[node->inputs->data[2]]; |
| 255 | if (input_type == kTfLiteUInt8 || input_type == kTfLiteInt8) { |
| 256 | TF_LITE_ENSURE_EQ(context, bias->type, kTfLiteInt32); |
| 257 | TF_LITE_ENSURE_EQ(context, bias->params.zero_point, 0); |
| 258 | } else { |
| 259 | TF_LITE_ENSURE_EQ(context, bias->type, input_type); |
| 260 | } |
| 261 | TF_LITE_ENSURE_EQ(context, NumElements(bias), SizeOfDimension(filter, 0)); |
| 262 | } |
| 263 | |
| 264 | const bool is_hybrid = |
| 265 | (input->type == kTfLiteFloat32 && |
| 266 | (filter->type == kTfLiteUInt8 || filter->type == kTfLiteInt8)); |
| 267 | |
| 268 | // The multi-threaded kernel supports neither dilation nor hybrid kernels. |
| 269 | data->supports_multithreaded_kernel = |
| 270 | (kernel_type == kMultithreadOptimized) && |
| 271 | (context->recommended_num_threads != 1) && !is_hybrid && |
| 272 | (params->dilation_width_factor == 1) && |
| 273 | (params->dilation_height_factor == 1); |
| 274 | |
| 275 | TF_LITE_ENSURE_STATUS( |
| 276 | AllocateTemporaryTensorsIfRequired(context, node, is_hybrid)); |
| 277 | |
| 278 | int channels_in = filter->dims->data[3]; |
nothing calls this directly
no test coverage detected