diff --git a/tensorflow/lite/c/common.h b/tensorflow/lite/c/common.h index 8917c254825..e04e1a12cd4 100644 --- a/tensorflow/lite/c/common.h +++ b/tensorflow/lite/c/common.h @@ -46,8 +46,17 @@ extern "C" { typedef enum TfLiteStatus { kTfLiteOk = 0, + + // Generally referring to an error in the runtime (i.e. interpreter) kTfLiteError = 1, + + // Generally referring to an error from a TfLiteDelegate itself. kTfLiteDelegateError = 2, + + // Generally referring to an error in applying a delegate due to + // incompatibility between runtime and delegate, e.g., this error is returned + // when trying to apply a TfLite delegate onto a model graph that's already + // immutable. kTfLiteApplicationError = 3 } TfLiteStatus; diff --git a/tensorflow/lite/core/subgraph.cc b/tensorflow/lite/core/subgraph.cc index 2b9246a1100..cece4ecba87 100644 --- a/tensorflow/lite/core/subgraph.cc +++ b/tensorflow/lite/core/subgraph.cc @@ -1526,7 +1526,7 @@ TfLiteStatus Subgraph::ModifyGraphWithDelegate(TfLiteDelegate* delegate) { ReportError( "Attempting to use a delegate that only supports static-sized " "tensors with a graph that has dynamic-sized tensors."); - return kTfLiteError; + return kTfLiteApplicationError; } } diff --git a/tensorflow/lite/core/subgraph.h b/tensorflow/lite/core/subgraph.h index b94d1a0b2bc..ed3b55ce630 100644 --- a/tensorflow/lite/core/subgraph.h +++ b/tensorflow/lite/core/subgraph.h @@ -567,7 +567,8 @@ class Subgraph { // delegate*. The Subgraph has been restored to its pre-delegation state. // NOTE: This reverts all delegates previously applied to the Subgraph. // 3. kTfLiteApplicationError : Delegation failed to be applied due to the - // state that the TfLite runtime is in. However, the Subgraph is still in a + // incompatibility with the TfLite runtime, e.g., the model graph is already + // immutable when applying the delegate. However, the Subgraph is still in a // invokable state. // 4. kTfLiteError: Unexpected/runtime failure. TfLiteStatus ModifyGraphWithDelegate(TfLiteDelegate* delegate); diff --git a/tensorflow/lite/interpreter.h b/tensorflow/lite/interpreter.h index 6a77c5a5f11..ef5831fda50 100644 --- a/tensorflow/lite/interpreter.h +++ b/tensorflow/lite/interpreter.h @@ -412,7 +412,11 @@ class Interpreter { /// 2. kTfLiteDelegateError: Delegation failed due to an error in the /// delegate. The Interpreter has been restored to its pre-delegation state. /// NOTE: This undoes all delegates previously applied to the Interpreter. - /// 3. kTfLiteError: Unexpected/runtime failure. + /// 3. kTfLiteApplicationError : Delegation failed to be applied due to the + /// incompatibility with the TfLite runtime, e.g., the model graph is already + /// immutable when applying the delegate. However, the interpreter could still + /// be invoked. + /// 4. kTfLiteError: Unexpected/runtime failure. /// WARNING: This is an experimental API and subject to change. TfLiteStatus ModifyGraphWithDelegate(TfLiteDelegate* delegate); diff --git a/tensorflow/lite/interpreter_test.cc b/tensorflow/lite/interpreter_test.cc index 66728ea89e9..b70908e7162 100644 --- a/tensorflow/lite/interpreter_test.cc +++ b/tensorflow/lite/interpreter_test.cc @@ -49,6 +49,13 @@ class InterpreterTest : public ::testing::Test { protected: TfLiteContext* GetInterpreterContext() { return interpreter_.context_; } + std::vector<Interpreter::TfLiteDelegatePtr>* + mutable_lazy_delegate_providers() { + return &interpreter_.lazy_delegate_providers_; + } + + bool HasDelegates() { return interpreter_.HasDelegates(); } + Interpreter interpreter_; }; @@ -1782,6 +1789,63 @@ TEST_F(TestCustomAllocation, ResizeTensorsWithEnoughMemory) { VerifyInvoke(); } +// Tests related to lazy delegate providers that are primarily used for applying +// TfLite delegates by default. +class TestLazyDelegateProvider : public InterpreterTest { + protected: + struct DummyLazyDelegateProvider : public TfLiteDelegate { + explicit DummyLazyDelegateProvider(int64_t support_flags) { + data_ = static_cast<void*>(this); + flags = support_flags; + Prepare = [](TfLiteContext*, TfLiteDelegate* delegate) -> TfLiteStatus { + return kTfLiteOk; + }; + } + }; + + void InitWithLazyDelegate(int64_t delegate_flags, + bool create_dyanmic_tensor = false) { + TfLiteRegistration reg = {nullptr, nullptr, nullptr, nullptr}; + ASSERT_EQ(interpreter_.AddTensors(2), kTfLiteOk); + interpreter_.SetInputs({0}); + interpreter_.SetOutputs({1}); + interpreter_.AddNodeWithParameters({0}, {1}, nullptr, 0, nullptr, ®); + + Interpreter::TfLiteDelegatePtr delegate( + new DummyLazyDelegateProvider(delegate_flags), + [](TfLiteDelegate* delegate) { + auto* dummy = + static_cast<DummyLazyDelegateProvider*>(delegate->data_); + delete dummy; + }); + mutable_lazy_delegate_providers()->push_back(std::move(delegate)); + + if (create_dyanmic_tensor) { + // Mark the output as dynamic tensor. + interpreter_.tensor(1)->data.raw = nullptr; + interpreter_.tensor(1)->allocation_type = kTfLiteDynamic; + } + } +}; + +TEST_F(TestLazyDelegateProvider, ApplicationSuccess) { + InitWithLazyDelegate(kTfLiteDelegateFlagsNone); + EXPECT_EQ(kTfLiteOk, interpreter_.AllocateTensors()); + // We clear Interpreter::lazy_delegate_providers_ after they are tried out. + EXPECT_TRUE(mutable_lazy_delegate_providers()->empty()); + EXPECT_TRUE(HasDelegates()); +} + +TEST_F(TestLazyDelegateProvider, ApplicationSkipped) { + InitWithLazyDelegate(kTfLiteDelegateFlagsNone, + true /* create_dyanmic_tensor */); + EXPECT_EQ(kTfLiteOk, interpreter_.AllocateTensors()); + EXPECT_TRUE(mutable_lazy_delegate_providers()->empty()); + // As the delegate doesn't allow dynamic tensor, the delegate won't be applied + // and the interpreter doesn't have any delegate applied. + EXPECT_FALSE(HasDelegates()); +} + } // namespace } // namespace tflite diff --git a/tensorflow/lite/tools/benchmark/experimental/c/c_api_types.h b/tensorflow/lite/tools/benchmark/experimental/c/c_api_types.h index 8917c254825..e04e1a12cd4 100644 --- a/tensorflow/lite/tools/benchmark/experimental/c/c_api_types.h +++ b/tensorflow/lite/tools/benchmark/experimental/c/c_api_types.h @@ -46,8 +46,17 @@ extern "C" { typedef enum TfLiteStatus { kTfLiteOk = 0, + + // Generally referring to an error in the runtime (i.e. interpreter) kTfLiteError = 1, + + // Generally referring to an error from a TfLiteDelegate itself. kTfLiteDelegateError = 2, + + // Generally referring to an error in applying a delegate due to + // incompatibility between runtime and delegate, e.g., this error is returned + // when trying to apply a TfLite delegate onto a model graph that's already + // immutable. kTfLiteApplicationError = 3 } TfLiteStatus;