Allocate temporary tensors (`im2col`, `hwcn_weights` if necessary). Note: `context->AddTensors` might invalidate pointers to existing tensors. Therefore the logic to add tensors are isolated into this function.
| 143 | // Note: `context->AddTensors` might invalidate pointers to existing tensors. |
| 144 | // Therefore the logic to add tensors are isolated into this function. |
| 145 | static TfLiteStatus AllocateTemporaryTensorsIfRequired(TfLiteContext* context, |
| 146 | TfLiteNode* node, |
| 147 | bool is_hybrid) { |
| 148 | auto* params = reinterpret_cast<TfLiteConvParams*>(node->builtin_data); |
| 149 | OpData* data = reinterpret_cast<OpData*>(node->user_data); |
| 150 | |
| 151 | TF_LITE_ENSURE(context, node->inputs->size >= 2); |
| 152 | TfLiteTensor* input = &context->tensors[node->inputs->data[0]]; |
| 153 | TfLiteTensor* filter = &context->tensors[node->inputs->data[1]]; |
| 154 | |
| 155 | int filter_width = filter->dims->data[2]; |
| 156 | int filter_height = filter->dims->data[1]; |
| 157 | |
| 158 | // If we're using the optimized multithreaded EigenTensor implementation of |
| 159 | // convolution, it expects the filter weights to be transposed compared to |
| 160 | // the normal TF Lite buffer format. Typical TF Lite weights are |
| 161 | // [filter_count, filter_height, filter_width, input_depth], but for the float |
| 162 | // implementation we need them as [filter_height, filter_width, input_depth, |
| 163 | // filter_count]. We get to that format by transposing, and create a temporary |
| 164 | // buffer to store the results. |
| 165 | // This path is only used for float processing, so only create the buffer if |
| 166 | // we're running with that data type. |
| 167 | data->need_hwcn_weights = (input->type == kTfLiteFloat32 && |
| 168 | data->supports_multithreaded_kernel && !is_hybrid); |
| 169 | |
| 170 | // We don't always need to allocate im2col. It is only used in some versions |
| 171 | // of the optimized Conv. This test just mimics something that happens inside |
| 172 | // optimized_ops.h, in order to avoid a DCHECK(!im2col_data). |
| 173 | data->need_im2col = |
| 174 | !data->need_hwcn_weights && |
| 175 | (params->stride_width != 1 || params->stride_height != 1 || |
| 176 | params->dilation_width_factor != 1 || |
| 177 | params->dilation_height_factor != 1 || filter_width != 1 || |
| 178 | filter_height != 1); |
| 179 | |
| 180 | int temporaries_count = 0; |
| 181 | if (data->need_im2col) { |
| 182 | data->im2col_index = temporaries_count; |
| 183 | if (data->im2col_id == kTensorNotAllocated) { |
| 184 | context->AddTensors(context, 1, &data->im2col_id); |
| 185 | } |
| 186 | ++temporaries_count; |
| 187 | } |
| 188 | if (data->need_hwcn_weights) { |
| 189 | data->hwcn_weights_index = temporaries_count; |
| 190 | if (data->hwcn_weights_id == kTensorNotAllocated) { |
| 191 | context->AddTensors(context, 1, &data->hwcn_weights_id); |
| 192 | } |
| 193 | ++temporaries_count; |
| 194 | } |
| 195 | |
| 196 | if (is_hybrid) { |
| 197 | // Allocate tensor to store the on-the-fly quantized inputs. |
| 198 | data->input_quantized_index = temporaries_count; |
| 199 | if (data->input_quantized_id == kTensorNotAllocated) { |
| 200 | TF_LITE_ENSURE_OK( |
| 201 | context, context->AddTensors(context, 1, &data->input_quantized_id)); |
| 202 | } |
no test coverage detected