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 <set> 26 #include <string> 27 #include <utility> 28 #include <vector> 29 30 #include "tensorflow/lite/allocation.h" 31 #include "tensorflow/lite/c/common.h" 32 #include "tensorflow/lite/core/api/error_reporter.h" 33 #include "tensorflow/lite/core/api/profiler.h" 34 #include "tensorflow/lite/core/macros.h" 35 #include "tensorflow/lite/experimental/resource/initialization_status.h" 36 #include "tensorflow/lite/experimental/resource/resource_base.h" 37 #include "tensorflow/lite/graph_info.h" 38 #include "tensorflow/lite/interpreter_options.h" 39 #include "tensorflow/lite/memory_planner.h" 40 #include "tensorflow/lite/util.h" 41 42 namespace tflite { 43 44 class SingleOpModel; // Class for friend declarations. 45 46 namespace delegates { 47 namespace test_utils { 48 class TestDelegate; // Class for friend declarations. 49 } // namespace test_utils 50 } // namespace delegates 51 52 class Subgraph { 53 public: 54 friend class Interpreter; 55 friend class SingleOpModel; 56 57 Subgraph(ErrorReporter* error_reporter, 58 TfLiteExternalContext** external_contexts, 59 std::vector<std::unique_ptr<Subgraph>>* subgraphs, 60 resource::ResourceMap* resources, 61 resource::ResourceIDMap* resource_ids, 62 resource::InitializationStatusMap* initialization_status_map, 63 int subgraph_index = kInvalidSubgraphIndex); 64 65 Subgraph(const Subgraph&) = delete; 66 67 // Subgraphs should be movable but not copyable. 68 Subgraph(Subgraph&&) = default; 69 Subgraph& operator=(const Subgraph&) = delete; 70 virtual ~Subgraph(); 71 72 // Provide a list of tensor indexes that are inputs to the model. 73 // Each index is bound check and this modifies the consistent_ flag of the 74 // interpreter. 75 TfLiteStatus SetInputs(std::vector<int> inputs); 76 77 // Provide a list of tensor indexes that are outputs to the model 78 // Each index is bound check and this modifies the consistent_ flag of the 79 // interpreter. 80 TfLiteStatus SetOutputs(std::vector<int> outputs); 81 82 // Provide a list of tensor indexes that are variable tensors. 83 // Each index is bound check and this modifies the consistent_ flag of the 84 // interpreter. 85 TfLiteStatus SetVariables(std::vector<int> variables); 86 87 // Adds a node with the given parameters and returns the index of the new 88 // node in `node_index` (optionally). Interpreter will take ownership of 89 // `builtin_data` and destroy it with `free`. Ownership of 'init_data' 90 // remains with the caller. 91 TfLiteStatus AddNodeWithParameters(const std::vector<int>& inputs, 92 const std::vector<int>& outputs, 93 const std::vector<int>& intermediates, 94 const char* init_data, 95 size_t init_data_size, void* builtin_data, 96 const TfLiteRegistration* registration, 97 int* node_index = nullptr); 98 99 // Adds `tensors_to_add` tensors, preserving pre-existing Tensor entries. 100 // The value pointed to by `first_new_tensor_index` will be set to the 101 // index of the first new tensor if `first_new_tensor_index` is non-null. 102 TfLiteStatus AddTensors(int tensors_to_add, 103 int* first_new_tensor_index = nullptr); 104 105 // Set description of inputs/outputs/data/fptrs for node `node_index`. 106 // This variant assumes an external buffer has been allocated of size 107 // bytes. The lifetime of buffer must be ensured to be greater or equal 108 // to Interpreter. `quantization` ownership is passed to the subgraph. 109 inline TfLiteStatus SetTensorParametersReadOnly( 110 int tensor_index, TfLiteType type, const char* name, 111 const std::vector<int>& dims, TfLiteQuantization quantization, 112 const char* buffer, size_t bytes, const Allocation* allocation = nullptr, 113 TfLiteSparsity* sparsity = nullptr) { 114 return SetTensorParametersReadOnly(tensor_index, type, name, dims.size(), 115 dims.data(), quantization, buffer, bytes, 116 allocation, sparsity); 117 } 118 TfLiteStatus SetTensorParametersReadOnly( 119 int tensor_index, TfLiteType type, const char* name, const size_t ndims, 120 const int* dims, TfLiteQuantization quantization, const char* buffer, 121 size_t bytes, const Allocation* allocation = nullptr, 122 TfLiteSparsity* sparsity = nullptr); 123 124 // Set description of inputs/outputs/data/fptrs for node `node_index`. 125 // This variant assumes an external buffer has been allocated of size 126 // bytes. The lifetime of buffer must be ensured to be greater or equal 127 // to Interpreter. `quantization` ownership is passed to the subgraph. 128 inline TfLiteStatus SetTensorParametersReadWrite( 129 int tensor_index, TfLiteType type, const char* name, 130 const std::vector<int>& dims, TfLiteQuantization quantization, 131 bool is_variable = false, const std::vector<int>& dims_signature = {}) { 132 if (dims_signature.empty()) { 133 return SetTensorParametersReadWrite(tensor_index, type, name, dims.size(), 134 dims.data(), quantization, 135 is_variable); 136 } 137 return SetTensorParametersReadWrite( 138 tensor_index, type, name, dims.size(), dims.data(), quantization, 139 is_variable, dims_signature.size(), dims_signature.data()); 140 } 141 TfLiteStatus SetTensorParametersReadWrite( 142 int tensor_index, TfLiteType type, const char* name, const size_t ndims, 143 const int* dims, TfLiteQuantization quantization, 144 bool is_variable = false, const size_t ndims_signature = 0, 145 const int* dims_signature = nullptr); 146 147 // Get a mutable tensor data structure. tensor(int tensor_index)148 TfLiteTensor* tensor(int tensor_index) { 149 if (tensor_index < 0 || 150 static_cast<size_t>(tensor_index) >= context_.tensors_size) { 151 return nullptr; 152 } 153 return &context_.tensors[tensor_index]; 154 } 155 156 // Get an immutable tensor data structure. tensor(int tensor_index)157 const TfLiteTensor* tensor(int tensor_index) const { 158 if (tensor_index < 0 || 159 static_cast<size_t>(tensor_index) >= context_.tensors_size) { 160 return nullptr; 161 } 162 return &context_.tensors[tensor_index]; 163 } 164 165 // Read only access to list of inputs. inputs()166 std::vector<int>& inputs() { return inputs_; } 167 168 // Read only access to list of inputs. inputs()169 const std::vector<int>& inputs() const { return inputs_; } 170 171 // Read only access to list of outputs. outputs()172 std::vector<int>& outputs() { return outputs_; } 173 174 // Read only access to list of outputs. outputs()175 const std::vector<int>& outputs() const { return outputs_; } 176 177 // Read only access to list of variable tensors. variables()178 std::vector<int>& variables() { return variables_; } 179 180 // Read only access to list of variable tensors. variables()181 const std::vector<int>& variables() const { return variables_; } 182 183 // WARNING: Experimental interface, subject to change. 184 // TODO(ycling): Move this function to an external context interface. resources()185 resource::ResourceMap& resources() { return *resources_; } 186 187 // WARNING: Experimental interface, subject to change. 188 // TODO(b/149099381): Move this function to an external context interface. resource_ids()189 resource::ResourceIDMap& resource_ids() { return *resource_ids_; } 190 191 // WARNING: Experimental interface, subject to change. 192 // TODO(b/149099381): Move this function to an external context interface. initialization_status_map()193 resource::InitializationStatusMap& initialization_status_map() { 194 return *initialization_status_map_; 195 } 196 tensors_size()197 size_t tensors_size() const { return tensors_.size(); } 198 199 // Return the number of ops in the model. nodes_size()200 size_t nodes_size() const { return nodes_and_registration_.size(); } 201 202 // Return vector of node indices in the order of execution. execution_plan()203 std::vector<int>& execution_plan() { return execution_plan_; } 204 205 // Return read-only vector of node indices in the order of execution. execution_plan()206 const std::vector<int>& execution_plan() const { return execution_plan_; } 207 208 const std::vector<std::pair<TfLiteNode, TfLiteRegistration>>& nodes_and_registration()209 nodes_and_registration() const { 210 return nodes_and_registration_; 211 } 212 213 // Get a pointer to an operation and registration data structure if in bounds. node_and_registration(int node_index)214 const std::pair<TfLiteNode, TfLiteRegistration>* node_and_registration( 215 int node_index) const { 216 if (node_index < 0 || static_cast<size_t>(node_index) >= nodes_size()) 217 return nullptr; 218 return &nodes_and_registration_[node_index]; 219 } 220 221 // Change the dimensionality of a given tensor. Note, this is only acceptable 222 // for tensor indices that are inputs. 223 // Returns status of failure or success. 224 TfLiteStatus ResizeInputTensor(int tensor_index, 225 const std::vector<int>& dims); 226 227 // WARNING: Experimental interface, subject to change 228 // Change the dimensionality of a given tensor. This is only acceptable for 229 // tensor indices that are inputs or variables. Only unknown dimensions can be 230 // resized with this function. Unknown dimensions are indicated as `-1` in the 231 // `dims_signature` attribute of a `TfLiteTensor`. Returns status of failure 232 // or success. 233 TfLiteStatus ResizeInputTensorStrict(int tensor_index, 234 const std::vector<int>& dims); 235 236 // This releases memory held by non-persistent tensors. It does NOT re-perform 237 // memory planning. 238 // AllocateTensors needs to be called before next invocation. 239 TfLiteStatus ReleaseNonPersistentMemory(); 240 241 // WARNING: Experimental interface, subject to change 242 // This API releases memory held by the given subgraph. This method is 243 // designed to release memory of control flow subgraphs. 244 // AllocateTensors needs to be called before next invocation. 245 TfLiteStatus ReleaseMemory(); 246 247 // Update allocations for all tensors. This will redim dependent tensors using 248 // the input tensor dimensionality as given. This is relatively expensive. 249 // If you know that your sizes are not changing, you need not call this. 250 // Returns status of success or failure. 251 TfLiteStatus AllocateTensors(); 252 253 // Invoke the subgraph (run the whole graph in dependency order). 254 // 255 // NOTE: It is possible that the interpreter is not in a ready state 256 // to evaluate (i.e. if a ResizeTensor() has been performed without an 257 // AllocateTensors(). 258 // Returns status of success or failure. 259 TfLiteStatus Invoke(); 260 261 // Entry point for C node plugin API to report an error. 262 void ReportError(const char* format, ...); 263 264 // Return the subgraph specific context. context()265 TfLiteContext* context() { return &context_; } context()266 const TfLiteContext* context() const { return &context_; } 267 268 // Set the value of an external context. 269 void SetExternalContext(TfLiteExternalContextType type, 270 TfLiteExternalContext* ctx); 271 // Get the half precision flag. 272 // WARNING: This is an experimental API and subject to change. GetAllowFp16PrecisionForFp32()273 bool GetAllowFp16PrecisionForFp32() const { 274 return context_.allow_fp32_relax_to_fp16; 275 } 276 277 // Sets the cancellation function pointer in order to cancel a request in the 278 // middle of a call to Invoke(). The interpreter queries this function during 279 // inference, between op invocations; when it returns true, the interpreter 280 // will abort execution and return `kTfLiteError`. The `data` parameter 281 // contains any data used by the cancellation function, and if non-null, 282 // remains owned by the caller. 283 // WARNING: This is an experimental API and subject to change. 284 void SetCancellationFunction(void* data, bool (*check_cancelled_func)(void*)); 285 286 // Ensure the data in `tensor.data` is readable. In case delegate is used, 287 // it might require to copy the data from delegate buffer to raw memory. 288 // WARNING: This is an experimental API and subject to change. EnsureTensorDataIsReadable(int tensor_index)289 TfLiteStatus EnsureTensorDataIsReadable(int tensor_index) { 290 TfLiteTensor* t = &tensors_[tensor_index]; 291 TF_LITE_ENSURE(&context_, t != nullptr); 292 if (t->data_is_stale) { 293 TF_LITE_ENSURE(&context_, t->delegate != nullptr); 294 TF_LITE_ENSURE(&context_, t->buffer_handle != kTfLiteNullBufferHandle); 295 TF_LITE_ENSURE(&context_, t->delegate->CopyFromBufferHandle != nullptr); 296 TF_LITE_ENSURE_STATUS(t->delegate->CopyFromBufferHandle( 297 &context_, t->delegate, t->buffer_handle, t)); 298 t->data_is_stale = false; 299 } 300 return kTfLiteOk; 301 } 302 303 // The default capacity of `tensors_` vector. 304 static constexpr int kTensorsReservedCapacity = 128; 305 // The capacity headroom of `tensors_` vector before calling ops' 306 // `prepare` and `invoke` function. In these functions, it's guaranteed 307 // allocating up to `kTensorsCapacityHeadroom` more tensors won't invalidate 308 // pointers to existing tensors. 309 static constexpr int kTensorsCapacityHeadroom = 16; 310 311 // Reset all variable tensors to the default value. 312 // If a variable tensor doesn't have a buffer, reset it to zero. 313 // TODO(b/115961645): Implement - If a variable tensor has a buffer, reset it 314 // to the value of the buffer. 315 // WARNING: This is an experimental API and subject to change. 316 TfLiteStatus ResetVariableTensors(); 317 SetProfiler(Profiler * profiler,int associated_subgraph_idx)318 void SetProfiler(Profiler* profiler, int associated_subgraph_idx) { 319 if (!profiler) { 320 profiler_.reset(nullptr); 321 context_.profiler = nullptr; 322 } else { 323 profiler_ = std::make_unique<SubgraphAwareProfiler>( 324 profiler, associated_subgraph_idx); 325 context_.profiler = profiler_.get(); 326 } 327 } 328 GetProfiler()329 Profiler* GetProfiler() { return profiler_.get(); } 330 331 // Returns a pointer to vector of subgraphs. 332 // WARNING: This is an experimental API and subject to change. GetSubgraphs()333 std::vector<std::unique_ptr<Subgraph>>* GetSubgraphs() { return subgraphs_; } 334 335 // Returns the location of this object within subgraphs_, or 336 // kInvalidSubgraphIndex if subgraphs_ is nullptr or *this is not 337 // represented *subgraphs_. 338 // WARNING: This is an experimental API and subject to 339 // change. 340 static constexpr int kInvalidSubgraphIndex = -1; GetSubgraphIndex()341 int GetSubgraphIndex() const { return subgraph_index_; } 342 343 // True if all tensors in the graph has static size after calling 344 // `AllocateTensors` function. 345 // Before `AllocateTensors` is called, this will always return true; HasDynamicTensors()346 bool HasDynamicTensors() { return has_dynamic_tensors_; } 347 348 // Assigns (or reassigns) a custom memory allocation for the given tensor. 349 // `flags` is a bitmask, see TfLiteCustomAllocationFlags. 350 // The runtime does NOT take ownership of the underlying memory. 351 // 352 // NOTE: User needs to call AllocateTensors() after this. 353 // Invalid/insufficient buffers will cause an error during AllocateTensors or 354 // Invoke (in case of dynamic shapes in the graph). 355 // 356 // Parameters should satisfy the following conditions: 357 // 1. tensor->allocation_type == kTfLiteArenaRw or kTfLiteArenaRwPersistent 358 // In general, this is true for I/O tensors & variable tensors. 359 // 2. allocation->data has the appropriate permissions for runtime access 360 // (Read-only for inputs, Read-Write for others), and outlives Interpreter. 361 // 3. allocation->bytes >= tensor->bytes. 362 // This condition is checked again if any tensors are resized. 363 // 4. allocation->data should be aligned to kDefaultTensorAlignment 364 // defined in lite/util.h. (Currently 64 bytes) 365 // This check is skipped if kTfLiteCustomAllocationFlagsSkipAlignCheck is 366 // set through `flags`. 367 // TODO(b/182215910): Expand on this documentation in a g3doc. 368 // 369 // WARNING: This is an experimental interface that is subject to change. 370 TfLiteStatus SetCustomAllocationForTensor( 371 int tensor_index, const TfLiteCustomAllocation& allocation, 372 int64_t flags = kTfLiteCustomAllocationFlagsNone); 373 374 void SetName(const char* name); 375 const std::string& GetName() const; 376 377 // WARNING: This is an experimental API and subject to change. 378 // Dumps debugging info by the underlying memory planner. 379 // Note: to have minimal binary increase caused by this debug info dump for 380 // the TfLite library and allow users to plug-in their own memory planner 381 // debugger, we have utilized weak symbols to meet these two requirements. By 382 // default, there is no debugging info dumped. However, if the TfLite-provided 383 // lite:simple_memory_arena_debug_dump (i.e. containing the strong defintion) 384 // is linked to the program, calling this function will output memory usage 385 // information about tenosrs and ops. 386 void DumpMemoryPlannerDebugInfo() const; 387 388 typedef struct SubgraphAllocInfo { 389 size_t arena_size; 390 size_t arena_persist_size; 391 size_t dynamic_size; 392 size_t resource_size; 393 } SubgraphAllocInfo; 394 395 // WARNING: This is an experimental API and subject to change. 396 // Returns memory allocation status. 397 void GetMemoryAllocInfo(SubgraphAllocInfo* alloc_info) const; 398 399 // WARNING: This is an experimental API and subject to change. 400 // Set the given `InterpreterOptions` object. SetOptions(InterpreterOptions * options)401 void SetOptions(InterpreterOptions* options) { options_ = options; } 402 403 // WARNING: This is an experimental API and subject to change. 404 // True if all intermediates tensors should be preserved for debugging. ShouldPreserveAllTensors()405 bool ShouldPreserveAllTensors() const { 406 return (options_ && options_->GetPreserveAllTensors()); 407 } 408 409 // WARNING: This is an experimental API and subject to change. 410 // True if all intermediate dynamic tensors should be released once they are 411 // not used by the model. ShouldReleaseDynamicTensors()412 bool ShouldReleaseDynamicTensors() const { 413 return (options_ && options_->GetEnsureDynamicTensorsAreReleased()); 414 } 415 416 /// WARNING: This is an experimental API and subject to change. 417 /// Use dynamic tensor allocation and deallocation method for large tensors 418 /// instead of static memory planner. Dynamic tensors are allocated just 419 /// before when they're needed and released when they're not needed anymore. 420 /// It improves peak memory usage but there could be some latency impact. The 421 /// parameter `large_tensors_thresholds_in_bytes` is used to determine large 422 /// tensors. This API must be called before `AllocateTensors`. 423 void OptimizeMemoryForLargeTensors(int large_tensors_thresholds_in_bytes); 424 425 // WARNING: This is an experimental API and subject to change. 426 // True if dynamic tensor allocation / deallocation method is enabled by 427 // `OptimizeMemoryForLargeTensors` API. ShouldOptimizeMemoryForLargeTensors()428 bool ShouldOptimizeMemoryForLargeTensors() { 429 return (options_ && (options_->GetDynamicAllocationForLargeTensors() > 0)); 430 } 431 432 // WARNING: This is an experimental API and subject to change. 433 // Remove unused inputs of the subgraph. It checks usage of inputs and mark it 434 // as kTfLiteOptionalTensor if the input is not used in graph execution. 435 // Currently, it's used to remove unused inputs of WHILE cond subgraphs. 436 TfLiteStatus RemoveUnusedInputs(); 437 438 private: 439 friend class InterpreterBuilder; 440 friend class TestDelegate; 441 // SubgraphAwareProfiler wraps an actual TFLite profiler, such as a 442 // BufferedProfiler instance, and takes care of event profiling/tracing in a 443 // certain subgraph. 444 class SubgraphAwareProfiler : public Profiler { 445 public: 446 // Constructor should be called with the non-nullptr profiler argument. SubgraphAwareProfiler(Profiler * profiler,int64_t subgraph_index)447 SubgraphAwareProfiler(Profiler* profiler, int64_t subgraph_index) 448 : profiler_(profiler), subgraph_index_(subgraph_index) {} ~SubgraphAwareProfiler()449 ~SubgraphAwareProfiler() override {} 450 BeginEvent(const char * tag,EventType event_type,int64_t event_metadata1,int64_t event_metadata2)451 uint32_t BeginEvent(const char* tag, EventType event_type, 452 int64_t event_metadata1, 453 int64_t event_metadata2) override { 454 if (!profiler_) return 0; 455 return profiler_->BeginEvent(tag, event_type, event_metadata1, 456 subgraph_index_); 457 } 458 EndEvent(uint32_t event_handle)459 void EndEvent(uint32_t event_handle) override { 460 if (!profiler_) return; 461 profiler_->EndEvent(event_handle); 462 } 463 EndEvent(uint32_t event_handle,int64_t event_metadata1,int64_t event_metadata2)464 void EndEvent(uint32_t event_handle, int64_t event_metadata1, 465 int64_t event_metadata2) override { 466 if (!profiler_) return; 467 profiler_->EndEvent(event_handle, event_metadata1, event_metadata2); 468 } 469 AddEvent(const char * tag,EventType event_type,uint64_t elapsed_time,int64_t event_metadata1,int64_t event_metadata2)470 void AddEvent(const char* tag, EventType event_type, uint64_t elapsed_time, 471 int64_t event_metadata1, int64_t event_metadata2) override { 472 if (!profiler_) return; 473 profiler_->AddEvent(tag, event_type, elapsed_time, event_metadata1, 474 subgraph_index_); 475 } 476 477 private: 478 // Not own the memory. 479 Profiler* const profiler_; 480 const int64_t subgraph_index_; 481 }; 482 483 // Ensure the internal node storage memory allocates at least `count` 484 // spots for node. NOTE, this doesn't actually add operators. This is an 485 // efficiency optimization that is subject to change. 486 // Note: Only used during initialization. 487 void ReserveNodes(int count); 488 489 // Overrides execution plan. This bounds checks indices sent in. 490 // Note: Only used during initialization. 491 TfLiteStatus SetExecutionPlan(const std::vector<int>& new_plan); 492 493 // Prevent 'context_' from accessing functions that are only available to 494 // delegated kernels. 495 void SwitchToKernelContext(); 496 497 // Add delegate-only functions to 'context_'. 498 void SwitchToDelegateContext(); 499 500 // Give 'op_reg' a chance to initialize itself using the contents of 501 // 'buffer'. If registration_external is valid, use the 'init' callback from 502 // that. 503 void* OpInit(const TfLiteRegistration& op_reg, const char* buffer, 504 size_t length); 505 506 // Let 'op_reg' release any memory it might have allocated via 'OpInit'. 507 // If registration_external is valid, use the 'free' callback from that. 508 void OpFree(const TfLiteRegistration& op_reg, void* buffer); 509 510 // Prepare the given 'node' for execution. 511 TfLiteStatus OpPrepare(const TfLiteRegistration& op_reg, TfLiteNode* node); 512 513 // Invoke the operator represented by 'node'. 514 TfLiteStatus OpInvoke(const TfLiteRegistration& op_reg, TfLiteNode* node); 515 516 // Call OpPrepare() for as many ops as possible, allocating memory for their 517 // tensors. If an op containing dynamic tensors is found, preparation will be 518 // postponed until this function is called again. This allows the interpreter 519 // to wait until Invoke() to resolve the sizes of dynamic tensors. 520 TfLiteStatus PrepareOpsAndTensors(); 521 522 // Call OpPrepare() for all ops starting at 'first_node'. Stop when a 523 // dynamic tensors is found or all ops have been prepared. Fill 524 // 'last_node_prepared' with the id of the op containing dynamic tensors, or 525 // the last in the graph. 526 TfLiteStatus PrepareOpsStartingAt(int first_execution_plan_index, 527 const std::vector<int>& execution_plan, 528 int* last_execution_plan_index_prepared); 529 530 // Tensors needed by the interpreter. Use `AddTensors` to add more blank 531 // tensor entries. Note, `tensors_.data()` needs to be synchronized to the 532 // `context_` whenever this std::vector is reallocated. Currently this 533 // only happens in `AddTensors()`. 534 std::vector<TfLiteTensor> tensors_; 535 536 // Check if an array of tensor indices are valid with respect to the Tensor 537 // array. 538 // NOTE: this changes consistent_ to be false if indices are out of bounds. 539 TfLiteStatus CheckTensorIndices(const char* label, const int* indices, 540 int length); 541 542 // Check that the input indices and the output indices don't overlap. 543 // This is needed because same tensor must not be used both as input and 544 // output for an operator. 545 // NOTE: this changes consistent_ to be false if indices are out of bounds. 546 TfLiteStatus CheckInputAndOutputForOverlap(const int* input_indices, 547 int num_inputs, 548 const int* output_indices, 549 int num_outputs); 550 551 // Compute the number of bytes required to represent a tensor with dimensions 552 // specified by the array dims (of length dims_size). Returns the status code 553 // and bytes. 554 TfLiteStatus BytesRequired(TfLiteType type, const int* dims, size_t dims_size, 555 size_t* bytes); 556 557 // Request an tensor be resized implementation. If the given tensor is of 558 // type kTfLiteDynamic it will also be allocated new memory. 559 TfLiteStatus ResizeTensorImpl(TfLiteTensor* tensor, TfLiteIntArray* new_size); 560 561 // Report a detailed error string (will be printed to stderr). 562 void ReportErrorImpl(const char* format, va_list args); 563 564 // Entry point for C node plugin API to request an tensor be resized. 565 static TfLiteStatus ResizeTensor(TfLiteContext* context, TfLiteTensor* tensor, 566 TfLiteIntArray* new_size); 567 // Entry point for C node plugin API to report an error. 568 static void ReportErrorC(TfLiteContext* context, const char* format, ...); 569 570 // Entry point for C node plugin API to add new tensors. 571 static TfLiteStatus AddTensors(TfLiteContext* context, int tensors_to_add, 572 int* first_new_tensor_index); 573 574 // WARNING: This is an experimental API and subject to change. 575 // Entry point for C API ReplaceNodeSubsetsWithDelegateKernels 576 static TfLiteStatus ReplaceNodeSubsetsWithDelegateKernels( 577 TfLiteContext* context, TfLiteRegistration registration, 578 const TfLiteIntArray* nodes_to_replace, TfLiteDelegate* delegate); 579 580 // Update the execution graph to replace some of the nodes with stub 581 // nodes. Specifically any node index that has `nodes[index]==1` will be 582 // slated for replacement with a delegate kernel specified by registration. 583 // Ownership of 'nodes_to_replace' and 'delegate' remains with the caller. 584 // WARNING: This is an experimental interface that is subject to change. 585 TfLiteStatus ReplaceNodeSubsetsWithDelegateKernels( 586 TfLiteRegistration registration, const TfLiteIntArray* nodes_to_replace, 587 TfLiteDelegate* delegate); 588 589 // WARNING: This is an experimental interface that is subject to change. 590 // Gets the internal pointer to a TensorFlow lite node by node_index. 591 TfLiteStatus GetNodeAndRegistration(int node_index, TfLiteNode** node, 592 TfLiteRegistration** registration); 593 594 // WARNING: This is an experimental interface that is subject to change. 595 // Entry point for C node plugin API to get a node by index. 596 static TfLiteStatus GetNodeAndRegistration(struct TfLiteContext*, 597 int node_index, TfLiteNode** node, 598 TfLiteRegistration** registration); 599 600 // WARNING: This is an experimental interface that is subject to change. 601 // Gets an TfLiteIntArray* representing the execution plan. The interpreter 602 // owns this memory and it is only guaranteed to exist during the invocation 603 // of the delegate prepare. 604 TfLiteStatus GetExecutionPlan(TfLiteIntArray** execution_plan); 605 606 // WARNING: This is an experimental interface that is subject to change. 607 // Entry point for C node plugin API to get the execution plan. 608 static TfLiteStatus GetExecutionPlan(struct TfLiteContext* context, 609 TfLiteIntArray** execution_plan); 610 611 // WARNING: This is an experimental interface that is subject to change. 612 // Provides a preview of post-delegation partitioning. Each 613 // TfLiteDelegateParams in the referenced array corresponds to one instance of 614 // the delegate kernel. 615 // nodes_to_replace should point to a valid array. partition_params_array & 616 // num_partitions should be non-null. 617 // Memory allocated by this method is automatically released with another call 618 // to PreviewDelegateParitioning, or after TfLiteDelegate::Prepare is done. 619 TfLiteStatus PreviewDelegatePartitioning( 620 const TfLiteIntArray* nodes_to_replace, 621 TfLiteDelegateParams** partition_params_array, int* num_partitions); 622 623 // WARNING: This is an experimental interface that is subject to change. 624 // Entry point for C node plugin API to preview delegation partitioning. 625 static TfLiteStatus PreviewDelegatePartitioning( 626 struct TfLiteContext* context, const TfLiteIntArray* nodes_to_replace, 627 TfLiteDelegateParams** partition_params_array, int* num_partitions); 628 629 // Retrieves named metadata from the TFLite model. Returns kTfLiteOk if 630 // metadata is successfully obtained. 631 // See the Metadata table in TFLite schema. 632 TfLiteStatus GetModelMetadata(const char* name, const char** ptr, 633 size_t* bytes); 634 635 // Entry point for C node plugin API to get model metadata based on name. 636 static TfLiteStatus GetModelMetadata(const struct TfLiteContext* context, 637 const char* name, const char** ptr, 638 size_t* bytes); 639 640 // Used to clear partitioning_preview_cache_, in case 641 // PreviewDelegatePartitioning was called. 642 void FreeDelegatePartitioningData(); 643 644 // Retrieve an existing external context by type. 645 TfLiteExternalContext* GetExternalContext(TfLiteExternalContextType type); 646 static TfLiteExternalContext* GetExternalContext( 647 struct TfLiteContext* context, TfLiteExternalContextType type); 648 649 // Set the value of an external context. 650 static void SetExternalContext(struct TfLiteContext* context, 651 TfLiteExternalContextType type, 652 TfLiteExternalContext* ctx); 653 654 // WARNING: This is an experimental API and subject to change. 655 // Allow a delegate to look at the graph and modify the graph to handle 656 // parts of the graph themselves. After this is called, the graph may 657 // contain new nodes that replace 1 more nodes. 658 // NOTE: If tensors were allocated prior to delegate application, they will 659 // be reallocated if the graph was modified (i.e., the caller does *not* need 660 // to explicitly call |AllocateTensors()| again). If tensors were unallocated, 661 // they will remain unallocated after delegate application. 662 // Returns one of the following status codes: 663 // 1. kTfLiteOk: Delegation succeeded 664 // 2. kTfLiteDelegateError: Delegation failed due to an error *in the 665 // delegate*, or the delegate parameter was null. The Subgraph has been 666 // restored to its pre-delegation state. 667 // NOTE: This reverts all delegates previously applied to the Subgraph. 668 // 3. kTfLiteApplicationError : Delegation failed to be applied due to the 669 // incompatibility with the TF Lite runtime, e.g., the model graph is already 670 // immutable when applying the delegate. However, the Subgraph is still in a 671 // invokable state. 672 // 4. kTfLiteUnresolvedOps: Delegation failed because the model has an 673 // operator that cannot be resolved. This can happen when the op is not 674 // registered or built with the TF Lite framework. 675 // 5. kTfLiteError: Unexpected/runtime failure. 676 TfLiteStatus ModifyGraphWithDelegate(TfLiteDelegate* delegate); 677 678 // This un-applies all delegates that have been applied till now, but retains 679 // pointers to them. 680 // The old execution plan and nodes are restored. 681 TfLiteStatus UndoAllDelegates(); 682 683 // This re-applies all delegates that were undone. 684 // Does nothing if UndoAllDelegates wasn't previously called. 685 TfLiteStatus RedoAllDelegates(); 686 687 // This removes all delegates. 688 // The old execution plan and nodes are restored. The graph is invokable 689 // afterwards. 690 TfLiteStatus RemoveAllDelegates(); 691 692 // Returns true if the subgraph has delegates applied. 693 bool HasDelegates(); 694 695 // Returns true if the subgraph has been fully delegated. 696 bool IsFullyDelegated() const; 697 698 // Cleanups up data reserved for the given node. Does not remove the {node, 699 // registration} pair from nodes_and_registrations_. 700 void CleanupNode(int node_index); 701 702 // Ensures that `tensors_` has at least `kTensorsCapacityHeadroom` extra 703 // capacity. Calling this function may invalidate existing pointers to 704 // tensors. After calling this function, adding `kTensorsCapacityHeadroom` 705 // more tensors won't invalidate the pointer to existing tensors. 706 void EnsureTensorsVectorCapacity(); 707 708 // Ensures the memory required is planned and allocated. 709 TfLiteStatus EnsureMemoryAllocations(); 710 711 // Returns true if cancellation function returns true. 712 bool IsCancelled(); 713 714 // Returns true if 'node' could have side effect (e.g. stateful op). 715 // Note that any node that might update other tensors beside op's output 716 // are considered to have side effect. 717 // So control flow ops like 'If' and 'While' are considered to have 718 // side effect because they can have ops that have side effect in the 719 // condition and body subgraphs. 720 bool OpMightHaveSideEffect(const TfLiteNode* node, 721 const TfLiteRegistration* registration) const; 722 723 // Returns new GraphInfo object based on the current Subgraph. 724 std::unique_ptr<GraphInfo> CreateGraphInfo(); 725 726 // Store a ptr to the model metadata owned by the Interpreter. 727 // Since the lifetime of the Interpreter exceeds the Subgraph, metadata 728 // remains valid for the latter's lifetime. 729 // Also sets relevant fields on context_ based on known metadata. 730 TfLiteStatus SetMetadata(const std::map<std::string, std::string>* metadata); 731 732 // Initializes the mapping between tensor index to the index of the 733 // last operation that uses the tensor as input. 734 void InitializeTensorReleaseMap(); 735 736 // May allocate dynamic tensor memory of node outputs. It's used when 737 // `EnsureDynamicTensorsAreReleased` or`UseDynamicAllocationForLargeTensors` 738 // API is used. 739 TfLiteStatus MayAllocateOpOutput(TfLiteNode* node); 740 741 // Checks the options for releasing dynamic tensors and release dynamic 742 // tensors if configured. 743 void MaybeReleaseDynamicTensors(const TfLiteNode& node, size_t node_index); 744 745 // The state of the Subgraph. 746 enum State { 747 // The Subgraph isn't ready to be invoked. 748 // `AllocateTensor` need to be called to enter an invokable state. 749 kStateUninvokable = 0, 750 // The Subgraph is ready to be invoked. 751 kStateInvokable, 752 // The Subgraph is ready to be invoked, and graph can't be further 753 // modified. The Subgraph will enter this state when calling 754 // `ModifyGraphWithDelegate` and the delegate doesn't support dynamic 755 // tensors. 756 kStateInvokableAndImmutable, 757 }; 758 State state_ = kStateUninvokable; 759 760 // A pure C data structure used to communicate with the pure C plugin 761 // interface. To avoid copying tensor metadata, this is also the definitive 762 // structure to store tensors. 763 TfLiteContext context_ = {}; 764 765 // A pointer to the external contexts (kTfLiteMaxExternalContexts) array that 766 // sits inside the associated TFLite interpreter instance. 767 TfLiteExternalContext** external_contexts_; 768 769 // Node inputs/outputs are stored in TfLiteNode and TfLiteRegistration stores 770 // function pointers to actual implementation. 771 // Nodes should appear in the order in which they are instantiated at runtime. 772 // Delegated nodes are appended after all the original ones. 773 std::vector<std::pair<TfLiteNode, TfLiteRegistration>> 774 nodes_and_registration_; 775 776 // Whether the model is consistent. That is to say if the inputs and outputs 777 // of every node and the global inputs and outputs are valid indexes into 778 // the tensor array. 779 bool consistent_ = true; 780 781 // Array of indices representing the tensors that are inputs to the 782 // interpreter. 783 std::vector<int> inputs_; 784 785 // Array of indices representing the tensors that are outputs to the 786 // interpreter. 787 std::vector<int> outputs_; 788 789 // Array of indices representing the tensors that are variable tensors. 790 std::vector<int> variables_; 791 792 // The error reporter delegate that tflite will forward queries errors to. 793 ErrorReporter* error_reporter_; 794 795 // Index of the next node to prepare. 796 // During Invoke(), Interpreter will allocate input tensors first, which are 797 // known to be fixed size. Then it will allocate outputs from nodes as many 798 // as possible. When there is a node that produces dynamic sized tensor. 799 // Interpreter will stop allocating tensors, set the value of next allocate 800 // node id, and execute the node to generate the output tensor before continue 801 // to allocate successors. This process repeats until all nodes are executed. 802 // NOTE: this relies on the order of nodes that is in topological order. 803 int next_execution_plan_index_to_prepare_; 804 805 // Only used in cases where a delegate supporting dynamic tensors is applied. 806 // This helps prepare the original execution before the post-delegation one, 807 // so that tensor shapes propagate. 808 int next_original_execution_plan_index_to_prepare_; 809 810 // This is similar to `next_execution_plan_index_to_prepare_`, but it tracks 811 // which nodes' allocation is planned with the arena planner. 812 // 813 // This is a workaround for b/127354079. It shouldn't be necessary if 814 // ArenaPlanner can "rewind" to a specific point. 815 // TODO(b/127354079): Improve ArenaPlanner and remove this mechanism. 816 int next_execution_plan_index_to_plan_allocation_; 817 818 // WARNING: This is an experimental interface that is subject to change. 819 // This is a list of node indices (to index into nodes_and_registration). 820 // This represents a valid topological sort (dependency ordered) execution 821 // plan. In particular, it is valid for this ordering to contain only a 822 // subset of the node indices. 823 std::vector<int> execution_plan_; 824 825 // This is a copy of the first execution_plan_ before any delegates were 826 // applied. It is empty if no delegates were applied to this Subgraph. 827 std::vector<int> pre_delegation_execution_plan_; 828 829 // Contains a list of delegates applied by the user so far, in order. 830 std::vector<TfLiteDelegate*> delegates_applied_; 831 832 // Set to true if UndoAllDelegates was called, and to false during 833 // RedoAllDelegates. 834 bool delegates_undone_ = false; 835 836 // In the future, we'd like a TfLiteIntArray compatible representation. 837 // TODO(aselle): replace execution_plan_ with this. 838 std::unique_ptr<TfLiteIntArray, TfLiteIntArrayDeleter> plan_cache_; 839 840 // Used by PreviewDelegateParitioning. 841 std::vector<TfLiteDelegateParams> partitioning_preview_cache_; 842 843 std::unique_ptr<MemoryPlanner> memory_planner_; 844 845 // Maps tensor index to custom allocation for all applicable tensors. 846 std::map<int, TfLiteCustomAllocation> custom_allocations_; 847 848 // Tracking bit for whether a tensor was resized in the course of an op 849 // invocation. This is a useful hint to ensure that dynamic tensor outputs 850 // trigger downstream reallocation after op invocation. 851 bool tensor_resized_since_op_invoke_ = false; 852 853 // Profiler for this interpreter instance. 854 std::unique_ptr<SubgraphAwareProfiler> profiler_; 855 856 // A pointer to vector of subgraphs. The vector is owned by the interpreter. 857 std::vector<std::unique_ptr<Subgraph>>* subgraphs_ = nullptr; 858 859 // Location of the pointer to *this in *subgraphs_, or kInvalidSubgraphIndex. 860 const int subgraph_index_; 861 862 // True if not all tensors in the graph has static size after calling 863 // `PrepareOpsStartingAt` function (which is called by the `AllocateTensors` 864 // public function). 865 // The value is invalid before `PrepareOpStartingAt` is called. 866 bool has_dynamic_tensors_ = true; 867 868 // WARNING: This is an experimental interface that is subject to change. 869 // This is the index of dynamic tensor which was checked at 870 // PrepareOpsStartingAt() when `has_dynamic_tensors_` is set. This information 871 // is kept only for user error message. 872 int dynamic_tensor_index_ = -1; 873 874 // Reference to cancellation function that can cancel a request in the middle 875 // of a call to Invoke(). When this function returns True, a kTfLiteError is 876 // thrown by Invoke(). 877 bool (*check_cancelled_func_)(void*) = nullptr; 878 879 // Reference to data used by the cancellation function in 880 // `check_cancelled_func_`. 881 void* cancellation_data_ = nullptr; 882 883 // A map of resources. Owned by interpreter and shared by multiple subgraphs. 884 resource::ResourceMap* resources_ = nullptr; 885 886 // A map of resources IDs. Owned by interpreter and shared by multiple 887 // subgraphs. 888 resource::ResourceIDMap* resource_ids_ = nullptr; 889 890 // A map of initialization statuses, that indicate whether the intialization 891 // subgraph invocation is done or not. 892 resource::InitializationStatusMap* initialization_status_map_; 893 894 // Name of the subgraph (analogous to function name). 895 std::string name_; 896 897 // Model-metadata owned by the Interpreter. 898 const std::map<std::string, std::string>* metadata_ = nullptr; 899 900 // Mapping between tensor index to the last index of the execution plan that 901 // uses this tensor. 902 std::map<int, int> tensor_to_last_op_index_; 903 904 // `InterpreterOptions` object which is being used and owned by Interpreter. 905 InterpreterOptions* options_; 906 }; 907 908 } // namespace tflite 909 #endif // TENSORFLOW_LITE_CORE_SUBGRAPH_H_ 910