1 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 #ifndef TENSORFLOW_LITE_CORE_SUBGRAPH_H_ 16 #define TENSORFLOW_LITE_CORE_SUBGRAPH_H_ 17 18 #include <stdarg.h> 19 #include <stddef.h> 20 21 #include <cstdint> 22 #include <cstdlib> 23 #include <map> 24 #include <memory> 25 #include <utility> 26 #include <vector> 27 28 #include "tensorflow/lite/allocation.h" 29 #include "tensorflow/lite/c/common.h" 30 #include "tensorflow/lite/core/api/error_reporter.h" 31 #include "tensorflow/lite/core/api/profiler.h" 32 #include "tensorflow/lite/core/macros.h" 33 #include "tensorflow/lite/experimental/resource/resource_base.h" 34 #include "tensorflow/lite/memory_planner.h" 35 #include "tensorflow/lite/util.h" 36 37 namespace tflite { 38 namespace delegates { 39 namespace test_utils { 40 class TestDelegate; // Class for friend declarations. 41 } // namespace test_utils 42 } // namespace delegates 43 44 class Subgraph { 45 public: 46 friend class Interpreter; 47 48 Subgraph(ErrorReporter* error_reporter, 49 TfLiteExternalContext** external_contexts, 50 std::vector<std::unique_ptr<Subgraph>>* subgraphs, 51 resource::ResourceMap* resources); 52 53 Subgraph(const Subgraph&) = delete; 54 55 // Subgraphs should be movable but not copyable. 56 Subgraph(Subgraph&&) = default; 57 Subgraph& operator=(const Subgraph&) = delete; 58 virtual ~Subgraph(); 59 60 // Provide a list of tensor indexes that are inputs to the model. 61 // Each index is bound check and this modifies the consistent_ flag of the 62 // interpreter. 63 TfLiteStatus SetInputs(std::vector<int> inputs); 64 65 // Provide a list of tensor indexes that are outputs to the model 66 // Each index is bound check and this modifies the consistent_ flag of the 67 // interpreter. 68 TfLiteStatus SetOutputs(std::vector<int> outputs); 69 70 // Provide a list of tensor indexes that are variable tensors. 71 // Each index is bound check and this modifies the consistent_ flag of the 72 // interpreter. 73 TfLiteStatus SetVariables(std::vector<int> variables); 74 75 // Ensure the internal node storage memory allocates at least `count` 76 // spots for node. NOTE, this doesn't actually add operators. This is an 77 // efficiency optimization that is subject to change. 78 void ReserveNodes(int count); 79 80 // Adds a node with the given parameters and returns the index of the new 81 // node in `node_index` (optionally). Interpreter will take ownership of 82 // `builtin_data` and destroy it with `free`. Ownership of 'init_data' 83 // remains with the caller. 84 TfLiteStatus AddNodeWithParameters(const std::vector<int>& inputs, 85 const std::vector<int>& outputs, 86 const std::vector<int>& intermediates, 87 const char* init_data, 88 size_t init_data_size, void* builtin_data, 89 const TfLiteRegistration* registration, 90 int* node_index = nullptr); 91 92 // Adds `tensors_to_add` tensors, preserving pre-existing Tensor entries. 93 // The value pointed to by `first_new_tensor_index` will be set to the 94 // index of the first new tensor if `first_new_tensor_index` is non-null. 95 TfLiteStatus AddTensors(int tensors_to_add, 96 int* first_new_tensor_index = nullptr); 97 98 // Set description of inputs/outputs/data/fptrs for node `node_index`. 99 // This variant assumes an external buffer has been allocated of size 100 // bytes. The lifetime of buffer must be ensured to be greater or equal 101 // to Interpreter. `quantization` ownership is passed to the subgraph. 102 inline TfLiteStatus SetTensorParametersReadOnly( 103 int tensor_index, TfLiteType type, const char* name, 104 const std::vector<int>& dims, TfLiteQuantization quantization, 105 const char* buffer, size_t bytes, const Allocation* allocation = nullptr, 106 TfLiteSparsity* sparsity = nullptr) { 107 return SetTensorParametersReadOnly(tensor_index, type, name, dims.size(), 108 dims.data(), quantization, buffer, bytes, 109 allocation, sparsity); 110 } 111 TfLiteStatus SetTensorParametersReadOnly( 112 int tensor_index, TfLiteType type, const char* name, const size_t rank, 113 const int* dims, TfLiteQuantization quantization, const char* buffer, 114 size_t bytes, const Allocation* allocation = nullptr, 115 TfLiteSparsity* sparsity = nullptr); 116 117 // Set description of inputs/outputs/data/fptrs for node `node_index`. 118 // This variant assumes an external buffer has been allocated of size 119 // bytes. The lifetime of buffer must be ensured to be greater or equal 120 // to Interpreter. `quantization` ownership is passed to the subgraph. 121 inline TfLiteStatus SetTensorParametersReadWrite( 122 int tensor_index, TfLiteType type, const char* name, 123 const std::vector<int>& dims, TfLiteQuantization quantization, 124 bool is_variable = false, const std::vector<int>& dims_signature = {}) { 125 if (dims_signature.empty()) { 126 return SetTensorParametersReadWrite(tensor_index, type, name, dims.size(), 127 dims.data(), quantization, 128 is_variable); 129 } 130 return SetTensorParametersReadWrite( 131 tensor_index, type, name, dims.size(), dims.data(), quantization, 132 is_variable, dims_signature.size(), dims_signature.data()); 133 } 134 TfLiteStatus SetTensorParametersReadWrite( 135 int tensor_index, TfLiteType type, const char* name, const size_t rank, 136 const int* dims, TfLiteQuantization quantization, 137 bool is_variable = false, const size_t rank_dims_signature = 0, 138 const int* dims_signature = nullptr); 139 140 // WARNING: Experimental interface, subject to change 141 // Overrides execution plan. This bounds checks indices sent in. 142 TfLiteStatus SetExecutionPlan(const std::vector<int>& new_plan); 143 144 // Get a mutable tensor data structure. 145 // TODO(aselle): Create a safe ArrayHandle interface to avoid exposing this 146 // read/write access to structure tensor(int tensor_index)147 TfLiteTensor* tensor(int tensor_index) { 148 if (tensor_index < 0 || 149 static_cast<size_t>(tensor_index) >= context_.tensors_size) { 150 return nullptr; 151 } 152 return &context_.tensors[tensor_index]; 153 } 154 155 // Get an immutable tensor data structure. tensor(int tensor_index)156 const TfLiteTensor* tensor(int tensor_index) const { 157 if (tensor_index < 0 || 158 static_cast<size_t>(tensor_index) >= context_.tensors_size) { 159 return nullptr; 160 } 161 return &context_.tensors[tensor_index]; 162 } 163 164 // Read only access to list of inputs. inputs()165 std::vector<int>& inputs() { return inputs_; } 166 167 // Read only access to list of inputs. inputs()168 const std::vector<int>& inputs() const { return inputs_; } 169 170 // Read only access to list of outputs. outputs()171 std::vector<int>& outputs() { return outputs_; } 172 173 // Read only access to list of outputs. outputs()174 const std::vector<int>& outputs() const { return outputs_; } 175 176 // Read only access to list of variable tensors. variables()177 std::vector<int>& variables() { return variables_; } 178 179 // Read only access to list of variable tensors. variables()180 const std::vector<int>& variables() const { return variables_; } 181 182 // WARNING: Experimental interface, subject to change. 183 // TODO(ycling): Move this function to an external context interface. resources()184 resource::ResourceMap& resources() { return *resources_; } 185 tensors_size()186 size_t tensors_size() const { return tensors_.size(); } 187 188 // Return the number of ops in the model. nodes_size()189 size_t nodes_size() const { return nodes_and_registration_.size(); } 190 191 // Return vector of node indices in the order of execution. execution_plan()192 std::vector<int>& execution_plan() { return execution_plan_; } 193 194 // Return read-only vector of node indices in the order of execution. execution_plan()195 const std::vector<int>& execution_plan() const { return execution_plan_; } 196 197 const std::vector<std::pair<TfLiteNode, TfLiteRegistration>>& nodes_and_registration()198 nodes_and_registration() const { 199 return nodes_and_registration_; 200 } 201 202 // Get a pointer to an operation and registration data structure if in bounds. node_and_registration(int node_index)203 const std::pair<TfLiteNode, TfLiteRegistration>* node_and_registration( 204 int node_index) const { 205 if (node_index < 0 || static_cast<size_t>(node_index) >= nodes_size()) 206 return nullptr; 207 return &nodes_and_registration_[node_index]; 208 } 209 210 // Change the dimensionality of a given tensor. Note, this is only acceptable 211 // for tensor indices that are inputs. 212 // Returns status of failure or success. 213 // TODO(aselle): Consider implementing ArraySlice equivalent to make this 214 // more adept at accepting data without an extra copy. Use absl::ArraySlice 215 // if our partners determine that dependency is acceptable. 216 TfLiteStatus ResizeInputTensor(int tensor_index, 217 const std::vector<int>& dims); 218 219 // WARNING: Experimental interface, subject to change 220 // Change the dimensionality of a given tensor. This is only acceptable for 221 // tensor indices that are inputs or variables. Only unknown dimensions can be 222 // resized with this function. Unknown dimensions are indicated as `-1` in the 223 // `dims_signature` attribute of a `TfLiteTensor`. Returns status of failure 224 // or success. 225 TfLiteStatus ResizeInputTensorStrict(int tensor_index, 226 const std::vector<int>& dims); 227 228 // This releases memory held by non-persistent tensors. It does NOT re-perform 229 // memory planning. 230 // AllocateTensors needs to be called before next invocation. 231 TfLiteStatus ReleaseNonPersistentMemory(); 232 233 // Update allocations for all tensors. This will redim dependent tensors using 234 // the input tensor dimensionality as given. This is relatively expensive. 235 // If you know that your sizes are not changing, you need not call this. 236 // Returns status of success or failure. 237 TfLiteStatus AllocateTensors(); 238 239 // Invoke the subgraph (run the whole graph in dependency order). 240 // 241 // NOTE: It is possible that the interpreter is not in a ready state 242 // to evaluate (i.e. if a ResizeTensor() has been performed without an 243 // AllocateTensors(). 244 // Returns status of success or failure. 245 TfLiteStatus Invoke(); 246 247 // Entry point for C node plugin API to report an error. 248 void ReportError(const char* format, ...); 249 250 // Return the subgraph specific context. context()251 TfLiteContext* context() { return &context_; } 252 253 // Set the value of an external context. 254 void SetExternalContext(TfLiteExternalContextType type, 255 TfLiteExternalContext* ctx); 256 // Get the half precision flag. 257 // WARNING: This is an experimental API and subject to change. GetAllowFp16PrecisionForFp32()258 bool GetAllowFp16PrecisionForFp32() const { 259 return context_.allow_fp32_relax_to_fp16; 260 } 261 262 // Sets the cancellation function pointer in order to cancel a request in the 263 // middle of a call to Invoke(). The interpreter queries this function during 264 // inference, between op invocations; when it returns true, the interpreter 265 // will abort execution and return `kTfLiteError`. The `data` parameter 266 // contains any data used by the cancellation function, and if non-null, 267 // remains owned by the caller. 268 // WARNING: This is an experimental API and subject to change. 269 void SetCancellationFunction(void* data, bool (*check_cancelled_func)(void*)); 270 271 // Ensure the data in `tensor.data` is readable. In case delegate is used, 272 // it might require to copy the data from delegate buffer to raw memory. 273 // WARNING: This is an experimental API and subject to change. 274 // TODO(b/119495520): make this private when refactoring complete. EnsureTensorDataIsReadable(int tensor_index)275 TfLiteStatus EnsureTensorDataIsReadable(int tensor_index) { 276 TfLiteTensor* t = &tensors_[tensor_index]; 277 TF_LITE_ENSURE(&context_, t != nullptr); 278 if (t->data_is_stale) { 279 TF_LITE_ENSURE(&context_, t->delegate != nullptr); 280 TF_LITE_ENSURE(&context_, t->buffer_handle != kTfLiteNullBufferHandle); 281 TF_LITE_ENSURE(&context_, t->delegate->CopyFromBufferHandle != nullptr); 282 // TODO(b/120420546): we must add a test that exercise this code. 283 TF_LITE_ENSURE_STATUS(t->delegate->CopyFromBufferHandle( 284 &context_, t->delegate, t->buffer_handle, t)); 285 t->data_is_stale = false; 286 } 287 return kTfLiteOk; 288 } 289 290 // The default capacity of `tensors_` vector. 291 static constexpr int kTensorsReservedCapacity = 128; 292 // The capacity headroom of `tensors_` vector before calling ops' 293 // `prepare` and `invoke` function. In these functions, it's guaranteed 294 // allocating up to `kTensorsCapacityHeadroom` more tensors won't invalidate 295 // pointers to existing tensors. 296 static constexpr int kTensorsCapacityHeadroom = 16; 297 298 // Reset all variable tensors to the default value. 299 // If a variable tensor doesn't have a buffer, reset it to zero. 300 // TODO(b/115961645): Implement - If a variable tensor has a buffer, reset it 301 // to the value of the buffer. 302 // WARNING: This is an experimental API and subject to change. 303 TfLiteStatus ResetVariableTensors(); 304 SetProfiler(Profiler * profiler,int associated_subgraph_idx)305 void SetProfiler(Profiler* profiler, int associated_subgraph_idx) { 306 if (!profiler) { 307 profiler_.reset(nullptr); 308 context_.profiler = nullptr; 309 } else { 310 profiler_.reset( 311 new SubgraphAwareProfiler(profiler, associated_subgraph_idx)); 312 context_.profiler = profiler_.get(); 313 } 314 } 315 GetProfiler()316 Profiler* GetProfiler() { return profiler_.get(); } 317 318 // Returns a pointer to vector of subgraphs. 319 // WARNING: This is an experimental API and subject to change. GetSubgraphs()320 std::vector<std::unique_ptr<Subgraph>>* GetSubgraphs() { return subgraphs_; } 321 322 // True if all tensors in the graph has static size after calling 323 // `AllocateTensors` function. 324 // Before `AllocateTensors` is called, this will always return true; HasDynamicTensors()325 bool HasDynamicTensors() { return has_dynamic_tensors_; } 326 327 // Assigns (or reassigns) a custom memory allocation for the given tensor. 328 // If AllocateTensors() is called after this, the runtime does not consider 329 // the tensor during internal memory planning and will continue using the 330 // provided allocation for the tensor (assuming it satisfies the expected 331 // tensor byte length). 332 // The runtime does NOT take ownership of the underlying memory. 333 // Note that while this function can be called again to set a new allocation 334 // for the tensor, it can no longer be reset to the TFLite arena memory. 335 // 336 // Parameters should satisfy the following conditions: 337 // 1. tensor->allocation_type == kTfLiteArenaRw or kTfLiteArenaRwPersistent 338 // In general, this is true for I/O tensors & variable tensors. 339 // 2. allocation->data has the appropriate permissions for runtime access 340 // (Read-only for inputs, Read-Write for others), and outlives Interpreter. 341 // 3. allocation->bytes >= tensor->bytes. 342 // This condition is checked again if any tensors are resized. 343 // 4. allocation->data should be aligned to kDefaultTensorAlignment 344 // defined in lite/util.h. (Currently 64 bytes) 345 // 346 // WARNING: This is an experimental interface that is subject to change. 347 TfLiteStatus SetCustomAllocationForTensor( 348 int tensor_index, const TfLiteCustomAllocation& allocation); 349 350 void SetName(const char* name); 351 const std::string& GetName() const; 352 353 private: 354 friend class TestDelegate; 355 // SubgraphAwareProfiler wraps an actual TFLite profiler, such as a 356 // BufferedProfiler instance, and takes care of event profiling/tracing in a 357 // certain subgraph. 358 class SubgraphAwareProfiler : public Profiler { 359 public: 360 // Constructor should be called with the non-nullptr profiler argument. SubgraphAwareProfiler(Profiler * profiler,int64_t subgraph_index)361 SubgraphAwareProfiler(Profiler* profiler, int64_t subgraph_index) 362 : profiler_(profiler), subgraph_index_(subgraph_index) {} ~SubgraphAwareProfiler()363 ~SubgraphAwareProfiler() override {} 364 BeginEvent(const char * tag,EventType event_type,int64_t event_metadata1,int64_t event_metadata2)365 uint32_t BeginEvent(const char* tag, EventType event_type, 366 int64_t event_metadata1, 367 int64_t event_metadata2) override { 368 if (!profiler_) return 0; 369 return profiler_->BeginEvent(tag, event_type, event_metadata1, 370 subgraph_index_); 371 } 372 EndEvent(uint32_t event_handle)373 void EndEvent(uint32_t event_handle) override { 374 if (!profiler_) return; 375 profiler_->EndEvent(event_handle); 376 } 377 EndEvent(uint32_t event_handle,int64_t event_metadata1,int64_t event_metadata2)378 void EndEvent(uint32_t event_handle, int64_t event_metadata1, 379 int64_t event_metadata2) override { 380 if (!profiler_) return; 381 profiler_->EndEvent(event_handle, event_metadata1, event_metadata2); 382 } 383 AddEvent(const char * tag,EventType event_type,uint64_t start,uint64_t end,int64_t event_metadata1,int64_t event_metadata2)384 void AddEvent(const char* tag, EventType event_type, uint64_t start, 385 uint64_t end, int64_t event_metadata1, 386 int64_t event_metadata2) override { 387 if (!profiler_) return; 388 profiler_->AddEvent(tag, event_type, start, end, event_metadata1, 389 subgraph_index_); 390 } 391 392 private: 393 // Not own the memory. 394 Profiler* const profiler_; 395 const int64_t subgraph_index_; 396 }; 397 398 // Prevent 'context_' from accessing functions that are only available to 399 // delegated kernels. 400 void SwitchToKernelContext(); 401 402 // Add delegate-only functions to 'context_'. 403 void SwitchToDelegateContext(); 404 405 // Give 'op_reg' a chance to initialize itself using the contents of 406 // 'buffer'. OpInit(const TfLiteRegistration & op_reg,const char * buffer,size_t length)407 void* OpInit(const TfLiteRegistration& op_reg, const char* buffer, 408 size_t length) { 409 if (op_reg.init == nullptr) return nullptr; 410 return op_reg.init(&context_, buffer, length); 411 } 412 413 // Let 'op_reg' release any memory it might have allocated via 'OpInit'. OpFree(const TfLiteRegistration & op_reg,void * buffer)414 void OpFree(const TfLiteRegistration& op_reg, void* buffer) { 415 if (op_reg.free == nullptr) return; 416 if (buffer) { 417 op_reg.free(&context_, buffer); 418 } 419 } 420 421 // Prepare the given 'node' for execution. 422 TfLiteStatus OpPrepare(const TfLiteRegistration& op_reg, TfLiteNode* node); 423 424 // Invoke the operator represented by 'node'. OpInvoke(const TfLiteRegistration & op_reg,TfLiteNode * node)425 TfLiteStatus OpInvoke(const TfLiteRegistration& op_reg, TfLiteNode* node) { 426 if (op_reg.invoke == nullptr) return kTfLiteError; 427 return op_reg.invoke(&context_, node); 428 } 429 430 // Call OpPrepare() for as many ops as possible, allocating memory for their 431 // tensors. If an op containing dynamic tensors is found, preparation will be 432 // postponed until this function is called again. This allows the interpreter 433 // to wait until Invoke() to resolve the sizes of dynamic tensors. 434 TfLiteStatus PrepareOpsAndTensors(); 435 436 // Call OpPrepare() for all ops starting at 'first_node'. Stop when a 437 // dynamic tensors is found or all ops have been prepared. Fill 438 // 'last_node_prepared' with the id of the op containing dynamic tensors, or 439 // the last in the graph. 440 TfLiteStatus PrepareOpsStartingAt(int first_execution_plan_index, 441 const std::vector<int>& execution_plan, 442 int* last_execution_plan_index_prepared); 443 444 // Tensors needed by the interpreter. Use `AddTensors` to add more blank 445 // tensor entries. Note, `tensors_.data()` needs to be synchronized to the 446 // `context_` whenever this std::vector is reallocated. Currently this 447 // only happens in `AddTensors()`. 448 std::vector<TfLiteTensor> tensors_; 449 450 // Check if an array of tensor indices are valid with respect to the Tensor 451 // array. 452 // NOTE: this changes consistent_ to be false if indices are out of bounds. 453 TfLiteStatus CheckTensorIndices(const char* label, const int* indices, 454 int length); 455 456 // Check that the input indices and the output indices don't overlap. 457 // This is needed because same tensor must not be used both as input and 458 // output for an operator. 459 // NOTE: this changes consistent_ to be false if indices are out of bounds. 460 TfLiteStatus CheckInputAndOutputForOverlap(const int* input_indices, 461 int num_inputs, 462 const int* output_indices, 463 int num_outputs); 464 465 // Compute the number of bytes required to represent a tensor with dimensions 466 // specified by the array dims (of length dims_size). Returns the status code 467 // and bytes. 468 TfLiteStatus BytesRequired(TfLiteType type, const int* dims, size_t dims_size, 469 size_t* bytes); 470 471 // Request an tensor be resized implementation. If the given tensor is of 472 // type kTfLiteDynamic it will also be allocated new memory. 473 TfLiteStatus ResizeTensorImpl(TfLiteTensor* tensor, TfLiteIntArray* new_size); 474 475 // Report a detailed error string (will be printed to stderr). 476 // TODO(aselle): allow user of class to provide alternative destinations. 477 void ReportErrorImpl(const char* format, va_list args); 478 479 // Entry point for C node plugin API to request an tensor be resized. 480 static TfLiteStatus ResizeTensor(TfLiteContext* context, TfLiteTensor* tensor, 481 TfLiteIntArray* new_size); 482 // Entry point for C node plugin API to report an error. 483 static void ReportErrorC(TfLiteContext* context, const char* format, ...); 484 485 // Entry point for C node plugin API to add new tensors. 486 static TfLiteStatus AddTensors(TfLiteContext* context, int tensors_to_add, 487 int* first_new_tensor_index); 488 489 // WARNING: This is an experimental API and subject to change. 490 // Entry point for C API ReplaceNodeSubsetsWithDelegateKernels 491 static TfLiteStatus ReplaceNodeSubsetsWithDelegateKernels( 492 TfLiteContext* context, TfLiteRegistration registration, 493 const TfLiteIntArray* nodes_to_replace, TfLiteDelegate* delegate); 494 495 // Update the execution graph to replace some of the nodes with stub 496 // nodes. Specifically any node index that has `nodes[index]==1` will be 497 // slated for replacement with a delegate kernel specified by registration. 498 // Ownership of 'nodes_to_replace' and 'delegate' remains with the caller. 499 // WARNING: This is an experimental interface that is subject to change. 500 TfLiteStatus ReplaceNodeSubsetsWithDelegateKernels( 501 TfLiteRegistration registration, const TfLiteIntArray* nodes_to_replace, 502 TfLiteDelegate* delegate); 503 504 // WARNING: This is an experimental interface that is subject to change. 505 // Gets the internal pointer to a TensorFlow lite node by node_index. 506 TfLiteStatus GetNodeAndRegistration(int node_index, TfLiteNode** node, 507 TfLiteRegistration** registration); 508 509 // WARNING: This is an experimental interface that is subject to change. 510 // Entry point for C node plugin API to get a node by index. 511 static TfLiteStatus GetNodeAndRegistration(struct TfLiteContext*, 512 int node_index, TfLiteNode** node, 513 TfLiteRegistration** registration); 514 515 // WARNING: This is an experimental interface that is subject to change. 516 // Gets an TfLiteIntArray* representing the execution plan. The interpreter 517 // owns this memory and it is only guaranteed to exist during the invocation 518 // of the delegate prepare. 519 TfLiteStatus GetExecutionPlan(TfLiteIntArray** execution_plan); 520 521 // WARNING: This is an experimental interface that is subject to change. 522 // Entry point for C node plugin API to get the execution plan. 523 static TfLiteStatus GetExecutionPlan(struct TfLiteContext* context, 524 TfLiteIntArray** execution_plan); 525 526 // WARNING: This is an experimental interface that is subject to change. 527 // Provides a preview of post-delegation partitioning. Each 528 // TfLiteDelegateParams in the referenced array corresponds to one instance of 529 // the delegate kernel. 530 // nodes_to_replace should point to a valid array. partition_params_array & 531 // num_partitions should be non-null. 532 // Memory allocated by this method is automatically released with another call 533 // to PreviewDelegateParitioning, or after TfLiteDelegate::Prepare is done. 534 TfLiteStatus PreviewDelegatePartitioning( 535 const TfLiteIntArray* nodes_to_replace, 536 TfLiteDelegateParams** partition_params_array, int* num_partitions); 537 538 // WARNING: This is an experimental interface that is subject to change. 539 // Entry point for C node plugin API to preview delegation partitioning. 540 static TfLiteStatus PreviewDelegatePartitioning( 541 struct TfLiteContext* context, const TfLiteIntArray* nodes_to_replace, 542 TfLiteDelegateParams** partition_params_array, int* num_partitions); 543 544 // Used to clear partitioning_preview_cache_, in case 545 // PreviewDelegatePartitioning was called. 546 void FreeDelegatePartitioningData(); 547 548 // Retrieve an existing external context by type. 549 TfLiteExternalContext* GetExternalContext(TfLiteExternalContextType type); 550 static TfLiteExternalContext* GetExternalContext( 551 struct TfLiteContext* context, TfLiteExternalContextType type); 552 553 // Set the value of an external context. 554 static void SetExternalContext(struct TfLiteContext* context, 555 TfLiteExternalContextType type, 556 TfLiteExternalContext* ctx); 557 558 // WARNING: This is an experimental API and subject to change. 559 // Allow a delegate to look at the graph and modify the graph to handle 560 // parts of the graph themselves. After this is called, the graph may 561 // contain new nodes that replace 1 more nodes. 562 // NOTE: If tensors were allocated prior to delegate application, they will 563 // be reallocated if the graph was modified (i.e., the caller does *not* need 564 // to explicitly call |AllocateTensors()| again). If tensors were unallocated, 565 // they will remain unallocated after delegate application. 566 // Returns one of the following status codes: 567 // 1. kTfLiteOk: Delegation succeeded 568 // 2. kTfLiteDelegateError: Delegation failed due to an error *in the 569 // delegate*, or the delegate parameter was null. The Subgraph has been 570 // restored to its pre-delegation state. 571 // NOTE: This reverts all delegates previously applied to the Subgraph. 572 // 3. kTfLiteApplicationError : Delegation failed to be applied due to the 573 // incompatibility with the TfLite runtime, e.g., the model graph is already 574 // immutable when applying the delegate. However, the Subgraph is still in a 575 // invokable state. 576 // 4. kTfLiteError: Unexpected/runtime failure. 577 TfLiteStatus ModifyGraphWithDelegate(TfLiteDelegate* delegate); 578 579 // This un-applies all delegates that have been applied till now, but retains 580 // pointers to them. 581 // The old execution plan and nodes are restored. 582 TfLiteStatus UndoAllDelegates(); 583 584 // This re-applies all delegates that were undone. 585 // Does nothing if UndoAllDelegates wasn't previously called. 586 TfLiteStatus RedoAllDelegates(); 587 588 // This removes all delegates. 589 // The old execution plan and nodes are restored. The graph is invokable 590 // afterwards. 591 TfLiteStatus RemoveAllDelegates(); 592 593 // Returns true if the subgraph has delegates applied. 594 bool HasDelegates(); 595 596 // Cleanups up data reserved for the given node. Does not remove the {node, 597 // registration} pair from nodes_and_registrations_. 598 void CleanupNode(int node_index); 599 600 // Ensures that `tensors_` has at least `kTensorsCapacityHeadroom` extra 601 // capacity. Calling this function may invalidate existing pointers to 602 // tensors. After calling this function, adding `kTensorsCapacityHeadroom` 603 // more tensors won't invalidate the pointer to existing tensors. 604 void EnsureTensorsVectorCapacity(); 605 606 // Ensures the memory required is planned and allocated. 607 TfLiteStatus EnsureMemoryAllocations(); 608 609 // Returns true if cancellation function returns true. 610 bool IsCancelled(); 611 612 // The state of the Interpreter. 613 enum State { 614 // The interpreter isn't ready to be invoked. 615 // `AllocateTensor` need to be called to enter an invokable state. 616 kStateUninvokable = 0, 617 // The interpreter is ready to be invoked. 618 kStateInvokable, 619 // The interpreter is ready to be invoked, and graph can't be further 620 // modified. The interpreter will enter this state when calling 621 // `ModifyGraphWithDelegate` and the delegate doesn't support dynamic 622 // tensors. 623 kStateInvokableAndImmutable, 624 }; 625 State state_ = kStateUninvokable; 626 627 // A pure C data structure used to communicate with the pure C plugin 628 // interface. To avoid copying tensor metadata, this is also the definitive 629 // structure to store tensors. 630 TfLiteContext context_ = {}; 631 632 // A pointer to the external contexts (kTfLiteMaxExternalContexts) array that 633 // sits inside the associated TFLite interpreter instance. 634 TfLiteExternalContext** external_contexts_; 635 636 // Node inputs/outputs are stored in TfLiteNode and TfLiteRegistration stores 637 // function pointers to actual implementation. 638 // Nodes should appear in the order in which they are instantiated at runtime. 639 // Delegated nodes are appended after all the original ones. 640 std::vector<std::pair<TfLiteNode, TfLiteRegistration>> 641 nodes_and_registration_; 642 643 // Whether the model is consistent. That is to say if the inputs and outputs 644 // of every node and the global inputs and outputs are valid indexes into 645 // the tensor array. 646 bool consistent_ = true; 647 648 // Array of indices representing the tensors that are inputs to the 649 // interpreter. 650 std::vector<int> inputs_; 651 652 // Array of indices representing the tensors that are outputs to the 653 // interpreter. 654 std::vector<int> outputs_; 655 656 // Array of indices representing the tensors that are variable tensors. 657 std::vector<int> variables_; 658 659 // The error reporter delegate that tflite will forward queries errors to. 660 ErrorReporter* error_reporter_; 661 662 // Index of the next node to prepare. 663 // During Invoke(), Interpreter will allocate input tensors first, which are 664 // known to be fixed size. Then it will allocate outputs from nodes as many 665 // as possible. When there is a node that produces dynamic sized tensor. 666 // Interpreter will stop allocating tensors, set the value of next allocate 667 // node id, and execute the node to generate the output tensor before continue 668 // to allocate successors. This process repeats until all nodes are executed. 669 // NOTE: this relies on the order of nodes that is in topological order. 670 int next_execution_plan_index_to_prepare_; 671 672 // Only used in cases where a delegate supporting dynamic tensors is applied. 673 // This helps prepare the original execution before the post-delegation one, 674 // so that tensor shapes propagate. 675 int next_original_execution_plan_index_to_prepare_; 676 677 // This is similar to `next_execution_plan_index_to_prepare_`, but it tracks 678 // which nodes' allocation is planned with the arena planner. 679 // 680 // This is a workaround for b/127354079. It shouldn't be necessary if 681 // ArenaPlanner can "rewind" to a specific point. 682 // TODO(b/127354079): Improve ArenaPlanner and remove this mechanism. 683 int next_execution_plan_index_to_plan_allocation_; 684 685 // WARNING: This is an experimental interface that is subject to change. 686 // This is a list of node indices (to index into nodes_and_registration). 687 // This represents a valid topological sort (dependency ordered) execution 688 // plan. In particular, it is valid for this ordering to contain only a 689 // subset of the node indices. 690 std::vector<int> execution_plan_; 691 692 // This is a copy of the first execution_plan_ before any delegates were 693 // applied. It is empty if no delegates were applied to this Subgraph. 694 std::vector<int> pre_delegation_execution_plan_; 695 696 // Contains a list of delegates applied by the user so far, in order. 697 std::vector<TfLiteDelegate*> delegates_applied_; 698 699 // Set to true if UndoAllDelegates was called, and to false during 700 // RedoAllDelegates. 701 bool delegates_undone_ = false; 702 703 // In the future, we'd like a TfLiteIntArray compatible representation. 704 // TODO(aselle): replace execution_plan_ with this. 705 std::unique_ptr<TfLiteIntArray, TfLiteIntArrayDeleter> plan_cache_; 706 707 // Used by PreviewDelegateParitioning. 708 std::vector<TfLiteDelegateParams> partitioning_preview_cache_; 709 710 std::unique_ptr<MemoryPlanner> memory_planner_; 711 712 // Contains <tensor idx, custom allocation> pairs for all applicable tensors. 713 std::vector<std::pair<int, TfLiteCustomAllocation>> custom_allocations_; 714 715 // Tracking bit for whether a tensor was resized in the course of an op 716 // invocation. This is a useful hint to ensure that dynamic tensor outputs 717 // trigger downstream reallocation after op invocation. 718 bool tensor_resized_since_op_invoke_ = false; 719 720 // Profiler for this interpreter instance. 721 std::unique_ptr<SubgraphAwareProfiler> profiler_; 722 723 // A pointer to vector of subgraphs. The vector is owned by the interpreter. 724 std::vector<std::unique_ptr<Subgraph>>* subgraphs_ = nullptr; 725 726 // True if all tensors in the graph has static size after calling 727 // `PrepareOpsStartingAt` function (which is called by the `AllocateTensors` 728 // public function). 729 // The value is invalid before `PrepareOpStartingAt` is called. 730 bool has_dynamic_tensors_ = true; 731 732 // Reference to cancellation function that can cancel a request in the middle 733 // of a call to Invoke(). When this function returns True, a kTfLiteError is 734 // thrown by Invoke(). 735 bool (*check_cancelled_func_)(void*) = nullptr; 736 737 // Reference to data used by the cancellation function in 738 // `check_cancelled_func_`. 739 void* cancellation_data_ = nullptr; 740 741 // A map of resources. Owned by interpreter and shared by multiple subgraphs. 742 resource::ResourceMap* resources_ = nullptr; 743 744 std::string name_; 745 }; 746 747 } // namespace tflite 748 #endif // TENSORFLOW_LITE_CORE_SUBGRAPH_H_ 749