| 213 | |
| 214 | template <KernelType kernel_type> |
| 215 | TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { |
| 216 | OpData* data = reinterpret_cast<OpData*>(node->user_data); |
| 217 | |
| 218 | // Sanity checks on op |
| 219 | TF_LITE_ENSURE_EQ(context, NumInputs(node), 3); |
| 220 | TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1); |
| 221 | |
| 222 | // Retrieve tensors |
| 223 | const TfLiteTensor* output_shape = |
| 224 | GetInput(context, node, kOutputShapeTensor); |
| 225 | const TfLiteTensor* weights = GetInput(context, node, kWeightsTensor); |
| 226 | const TfLiteTensor* input = GetInput(context, node, kDataInputTensor); |
| 227 | TfLiteTensor* output = GetOutput(context, node, kOutputTensor); |
| 228 | |
| 229 | // Tensor sanity checks |
| 230 | TF_LITE_ENSURE_EQ(context, NumDimensions(output_shape), 1); |
| 231 | TF_LITE_ENSURE_EQ(context, NumDimensions(input), 4); |
| 232 | TF_LITE_ENSURE_EQ(context, NumDimensions(weights), 4); |
| 233 | TF_LITE_ENSURE(context, |
| 234 | input->type == kTfLiteFloat32 || input->type == kTfLiteUInt8); |
| 235 | TF_LITE_ENSURE_EQ(context, weights->type, input->type); |
| 236 | TF_LITE_ENSURE_EQ(context, output->type, input->type); |
| 237 | // Ensure that weights and inputs have the same channel dimension. |
| 238 | // Note: TOCO will reorder weights in the following format: OHWI. |
| 239 | TF_LITE_ENSURE_EQ(context, SizeOfDimension(input, 3), |
| 240 | SizeOfDimension(weights, 3)); |
| 241 | |
| 242 | // Allocate col2Im, transposed_weights & scratch Tensor. |
| 243 | TF_LITE_ENSURE_STATUS(AllocateTemporaryTensorsIfRequired<kernel_type>( |
| 244 | context, input->type, weights->type, node)); |
| 245 | |
| 246 | OpData* user_data = reinterpret_cast<OpData*>(node->user_data); |
| 247 | TfLiteTensor* col2im = nullptr; |
| 248 | if (data->has_col2im) { |
| 249 | node->temporaries->data[data->col2im_index] = data->col2im_id; |
| 250 | col2im = GetTemporary(context, node, user_data->col2im_index); |
| 251 | } |
| 252 | |
| 253 | if (!IsConstantTensor(output_shape)) { |
| 254 | // Defer resizing until Eval(). |
| 255 | SetTensorToDynamic(output); |
| 256 | if (data->has_col2im) { |
| 257 | SetTensorToDynamic(col2im); |
| 258 | } |
| 259 | } else { |
| 260 | TF_LITE_ENSURE_STATUS(ResizeTensor(context, output_shape, output)); |
| 261 | if (data->has_col2im) { |
| 262 | TF_LITE_ENSURE_STATUS( |
| 263 | ResizeCol2ImTensor(context, output_shape, weights, input, col2im)); |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | if (data->weights_are_transposed) { |
| 268 | node->temporaries->data[data->transposed_weights_index] = |
| 269 | data->transposed_weights_id; |
| 270 | TfLiteTensor* transposed_weights = |
| 271 | GetTemporary(context, node, user_data->transposed_weights_index); |
| 272 | if (!IsConstantTensor(weights)) { |
nothing calls this directly
no test coverage detected