| 450 | } |
| 451 | |
| 452 | TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { |
| 453 | const auto* op_data = reinterpret_cast<OpData*>(node->user_data); |
| 454 | TF_LITE_ENSURE_MSG( |
| 455 | context, op_data->eager_context != nullptr, |
| 456 | "Failed to initialize eager context. This often happens when a CPU " |
| 457 | "device has not been registered, presumably because some symbols from " |
| 458 | "tensorflow/core:core_cpu_impl were not linked into the binary."); |
| 459 | |
| 460 | // We will keep track of the number of references to each tensor in the |
| 461 | // graph, so we can make them "forwardable" if there is only one reference. |
| 462 | std::map<int, int> tensor_ref_count; |
| 463 | |
| 464 | // Whenever we find a constant tensor, insert it in the buffer map. |
| 465 | BufferMap* buffer_map = op_data->buffer_map; |
| 466 | for (auto tensor_index : op_data->subgraph_inputs) { |
| 467 | TfLiteTensor* tensor = &context->tensors[tensor_index]; |
| 468 | if (IsConstantTensor(tensor)) { |
| 469 | if (!buffer_map->HasTensor(tensor_index)) { |
| 470 | buffer_map->SetFromTfLite(tensor_index, tensor); |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | // Input tensors should never be forwarded so we increment their ref counts |
| 475 | // twice: once for this graph and another for the possibility of them being |
| 476 | // used by another subgraph, or being an output of the full graph. |
| 477 | tensor_ref_count[tensor_index] += 2; |
| 478 | } |
| 479 | |
| 480 | // All output tensors are allocated by TensorFlow/Eager, so we |
| 481 | // mark them as kTfLiteDynamic. |
| 482 | for (auto tensor_index : op_data->subgraph_outputs) { |
| 483 | SetTensorToDynamic(&context->tensors[tensor_index]); |
| 484 | ++tensor_ref_count[tensor_index]; |
| 485 | } |
| 486 | |
| 487 | for (const auto& node_data : op_data->nodes) { |
| 488 | if (node_data->nodedef().op().empty()) { |
| 489 | context->ReportError(context, "Invalid NodeDef in Flex op '%s'", |
| 490 | node_data->name().c_str()); |
| 491 | return kTfLiteError; |
| 492 | } |
| 493 | TF_LITE_ENSURE(context, node_data->op()); |
| 494 | |
| 495 | for (int i = 0; i < node_data->inputs().Size(); ++i) { |
| 496 | ++tensor_ref_count[node_data->inputs().TfLiteIndex(i)]; |
| 497 | } |
| 498 | } |
| 499 | |
| 500 | // All tensors that are referenced exactly once are marked as "forwardable", |
| 501 | // meaning that we will allow TensorFlow to reuse its buffer as the output of |
| 502 | // an op. |
| 503 | for (auto& node_data : op_data->nodes) { |
| 504 | for (int i = 0; i < node_data->inputs().Size(); ++i) { |
| 505 | bool f = (tensor_ref_count[node_data->inputs().TfLiteIndex(i)] == 1); |
| 506 | node_data->mutable_inputs()->SetForwardable(i, f); |
| 507 | } |
| 508 | } |
| 509 |
nothing calls this directly
no test coverage detected