diff --git a/tensorflow/lite/delegates/utils/BUILD b/tensorflow/lite/delegates/utils/BUILD index 069da167455..2fbe51c98af 100644 --- a/tensorflow/lite/delegates/utils/BUILD +++ b/tensorflow/lite/delegates/utils/BUILD @@ -26,10 +26,10 @@ cc_test( name = "simple_delegate_test", srcs = ["simple_delegate_test.cc"], deps = [ - ":simple_delegate", "//tensorflow/lite:framework", "//tensorflow/lite:kernel_api", "//tensorflow/lite/c:common", + "//tensorflow/lite/delegates/utils/dummy_delegate", "//tensorflow/lite/kernels:builtin_ops", "@com_google_googletest//:gtest_main", ], diff --git a/tensorflow/lite/delegates/utils/dummy_delegate/BUILD b/tensorflow/lite/delegates/utils/dummy_delegate/BUILD new file mode 100644 index 00000000000..a451b51e47f --- /dev/null +++ b/tensorflow/lite/delegates/utils/dummy_delegate/BUILD @@ -0,0 +1,78 @@ +load("//tensorflow/lite:build_def.bzl", "tflite_copts") +load("//tensorflow/lite/tools/evaluation/tasks:build_def.bzl", "task_linkopts") + +package( + default_visibility = [ + "//visibility:public", + ], + licenses = ["notice"], # Apache 2.0 +) + +cc_library( + name = "dummy_delegate", + srcs = [ + "dummy_delegate.cc", + ], + hdrs = [ + "dummy_delegate.h", + ], + deps = [ + "//tensorflow/lite/c:common", + "//tensorflow/lite/delegates/utils:simple_delegate", + ], +) + +#### The following are for using the dummy test delegate in TFLite tooling #### +cc_library( + name = "dummy_delegate_provider", + srcs = ["dummy_delegate_provider.cc"], + copts = tflite_copts(), + deps = [ + ":dummy_delegate", + "//tensorflow/lite/tools/delegates:delegate_provider_hdr", + ], + alwayslink = 1, +) + +cc_binary( + name = "benchmark_model_plus_dummy_delegate", + copts = tflite_copts(), + linkopts = task_linkopts(), + deps = [ + ":dummy_delegate_provider", + "//tensorflow/lite/tools/benchmark:benchmark_model_main", + ], +) + +cc_binary( + name = "inference_diff_plus_dummy_delegate", + copts = tflite_copts(), + linkopts = task_linkopts(), + deps = [ + ":dummy_delegate_provider", + "//tensorflow/lite/tools/evaluation/tasks:task_executor_main", + "//tensorflow/lite/tools/evaluation/tasks/inference_diff:run_eval_lib", + ], +) + +cc_binary( + name = "imagenet_classification_eval_plus_dummy_delegate", + copts = tflite_copts(), + linkopts = task_linkopts(), + deps = [ + ":dummy_delegate_provider", + "//tensorflow/lite/tools/evaluation/tasks:task_executor_main", + "//tensorflow/lite/tools/evaluation/tasks/imagenet_image_classification:run_eval_lib", + ], +) + +cc_binary( + name = "coco_object_detection_eval_plus_dummy_delegate", + copts = tflite_copts(), + linkopts = task_linkopts(), + deps = [ + ":dummy_delegate_provider", + "//tensorflow/lite/tools/evaluation/tasks:task_executor_main", + "//tensorflow/lite/tools/evaluation/tasks/coco_object_detection:run_eval_lib", + ], +) diff --git a/tensorflow/lite/delegates/utils/dummy_delegate/README.md b/tensorflow/lite/delegates/utils/dummy_delegate/README.md new file mode 100644 index 00000000000..be3ccae8810 --- /dev/null +++ b/tensorflow/lite/delegates/utils/dummy_delegate/README.md @@ -0,0 +1,11 @@ +#Description +A dummy delegate implementation to illustrate + +* How to use [SimpleDelegateInterface and SimpleDelegateKernelInterface](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/utils/simple_delegate.h) + to faciliate a TFLite delgate creation. A more sophisticated example could be + refered to the [Flex delegate](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/delegates/flex) + +* How to leverage the [delegate registrar](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/tools/delegates) + to plug in a delegate in TFLite benchmark and task evaluation tools. + +More detailed guide is coming soon. diff --git a/tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate.cc b/tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate.cc new file mode 100644 index 00000000000..47b67a5fbdd --- /dev/null +++ b/tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate.cc @@ -0,0 +1,99 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +#include "tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate.h" + +#include <utility> + +#include "tensorflow/lite/delegates/utils/simple_delegate.h" + +namespace tflite { +namespace dummy_test { + +// Dummy delegate kernel. +class DummyDelegateKernel : public SimpleDelegateKernelInterface { + public: + explicit DummyDelegateKernel(const DummyDelegateOptions& options) + : options_(options) {} + + TfLiteStatus Init(TfLiteContext* context, + const TfLiteDelegateParams* params) override { + return !options_.error_during_init ? kTfLiteOk : kTfLiteError; + } + + TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) override { + return !options_.error_during_prepare ? kTfLiteOk : kTfLiteError; + } + + TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) override { + return !options_.error_during_invoke ? kTfLiteOk : kTfLiteError; + } + + private: + const DummyDelegateOptions options_; +}; + +// DummyDelegate implements the interface of SimpleDelegateInterface. +// This holds the Delegate capabilities. +class DummyDelegate : public SimpleDelegateInterface { + public: + explicit DummyDelegate(const DummyDelegateOptions& options) + : options_(options) {} + bool IsNodeSupportedByDelegate(const TfLiteRegistration* registration, + const TfLiteNode* node, + TfLiteContext* context) const override { + return options_.allowed_builtin_code == registration->builtin_code; + } + + TfLiteStatus Initialize(TfLiteContext* context) override { return kTfLiteOk; } + + const char* Name() const override { + static constexpr char kName[] = "DummyDelegate"; + return kName; + } + + std::unique_ptr<SimpleDelegateKernelInterface> CreateDelegateKernelInterface() + override { + return std::make_unique<DummyDelegateKernel>(options_); + } + + private: + const DummyDelegateOptions options_; +}; + +} // namespace dummy_test +} // namespace tflite + +DummyDelegateOptions TfLiteDummyDelegateOptionsDefault() { + DummyDelegateOptions options = {0}; + // Just assign an invalid builtin code so that this dummy test delegate will + // not support any node by default. + options.allowed_builtin_code = -1; + return options; +} + +// Creates a new delegate instance that need to be destroyed with +// `TfLiteDummyDelegateDelete` when delegate is no longer used by TFLite. +// When `options` is set to `nullptr`, the above default values are used: +TfLiteDelegate* TfLiteDummyDelegateCreate(const DummyDelegateOptions* options) { + std::unique_ptr<tflite::dummy_test::DummyDelegate> dummy( + new tflite::dummy_test::DummyDelegate( + options ? *options : TfLiteDummyDelegateOptionsDefault())); + return tflite::TfLiteDelegateFactory::CreateSimpleDelegate(std::move(dummy)); +} + +// Destroys a delegate created with `TfLiteDummyDelegateCreate` call. +void TfLiteDummyDelegateDelete(TfLiteDelegate* delegate) { + tflite::TfLiteDelegateFactory::DeleteSimpleDelegate(delegate); +} diff --git a/tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate.h b/tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate.h new file mode 100644 index 00000000000..94023aa7d21 --- /dev/null +++ b/tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate.h @@ -0,0 +1,60 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ + +#ifndef TENSORFLOW_LITE_DELEGATES_UTILS_DUMMY_DELEGATE_DUMMY_DELEGATE_H_ +#define TENSORFLOW_LITE_DELEGATES_UTILS_DUMMY_DELEGATE_DUMMY_DELEGATE_H_ + +#include <memory> + +#include "tensorflow/lite/c/common.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +typedef struct { + // Allowed ops to delegate. + int allowed_builtin_code; + // Report error during init. + bool error_during_init; + // Report error during prepare. + bool error_during_prepare; + // Report error during invoke. + bool error_during_invoke; +} DummyDelegateOptions; + +// Returns a structure with the default delegate options. +DummyDelegateOptions TfLiteDummyDelegateOptionsDefault(); + +// Creates a new delegate instance that needs to be destroyed with +// `TfLiteDummyDelegateDelete` when delegate is no longer used by TFLite. +// When `options` is set to `nullptr`, the above default values are used: +TfLiteDelegate* TfLiteDummyDelegateCreate(const DummyDelegateOptions* options); + +// Destroys a delegate created with `TfLiteDummyDelegateCreate` call. +void TfLiteDummyDelegateDelete(TfLiteDelegate* delegate); +#ifdef __cplusplus +} +#endif // __cplusplus + +// A convenient wrapper that returns C++ std::unique_ptr for automatic memory +// management. +inline std::unique_ptr<TfLiteDelegate, void (*)(TfLiteDelegate*)> +TfLiteDummyDelegateCreateUnique(const DummyDelegateOptions* options) { + return std::unique_ptr<TfLiteDelegate, void (*)(TfLiteDelegate*)>( + TfLiteDummyDelegateCreate(options), TfLiteDummyDelegateDelete); +} + +#endif // TENSORFLOW_LITE_DELEGATES_UTILS_DUMMY_DELEGATE_DUMMY_DELEGATE_H_ diff --git a/tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate_provider.cc b/tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate_provider.cc new file mode 100644 index 00000000000..dec6584555c --- /dev/null +++ b/tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate_provider.cc @@ -0,0 +1,61 @@ +/* Copyright 2020 The TensorFlow Authors. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +==============================================================================*/ +#include <string> + +#include "tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate.h" +#include "tensorflow/lite/tools/delegates/delegate_provider.h" + +namespace tflite { +namespace tools { + +class DummyDelegateProvider : public DelegateProvider { + public: + DummyDelegateProvider() { + default_params_.AddParam("use_dummy_delegate", + ToolParam::Create<bool>(false)); + } + + std::vector<Flag> CreateFlags(ToolParams* params) const final; + + void LogParams(const ToolParams& params) const final; + + TfLiteDelegatePtr CreateTfLiteDelegate(const ToolParams& params) const final; + + std::string GetName() const final { return "DummyDelegate"; } +}; +REGISTER_DELEGATE_PROVIDER(DummyDelegateProvider); + +std::vector<Flag> DummyDelegateProvider::CreateFlags(ToolParams* params) const { + std::vector<Flag> flags = {CreateFlag<bool>("use_dummy_delegate", params, + "use the dummy delegate.")}; + return flags; +} + +void DummyDelegateProvider::LogParams(const ToolParams& params) const { + TFLITE_LOG(INFO) << "Use dummy test delegate : [" + << params.Get<bool>("use_dummy_delegate") << "]"; +} + +TfLiteDelegatePtr DummyDelegateProvider::CreateTfLiteDelegate( + const ToolParams& params) const { + if (params.Get<bool>("use_dummy_delegate")) { + auto default_options = TfLiteDummyDelegateOptionsDefault(); + return TfLiteDummyDelegateCreateUnique(&default_options); + } + return TfLiteDelegatePtr(nullptr, [](TfLiteDelegate*) {}); +} + +} // namespace tools +} // namespace tflite diff --git a/tensorflow/lite/delegates/utils/simple_delegate_test.cc b/tensorflow/lite/delegates/utils/simple_delegate_test.cc index 12a790fff1a..a521c675375 100644 --- a/tensorflow/lite/delegates/utils/simple_delegate_test.cc +++ b/tensorflow/lite/delegates/utils/simple_delegate_test.cc @@ -12,82 +12,18 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ==============================================================================*/ -#include "tensorflow/lite/delegates/utils/simple_delegate.h" - #include <memory> #include <gmock/gmock.h> #include <gtest/gtest.h> #include "tensorflow/lite/builtin_ops.h" #include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/delegates/utils/dummy_delegate/dummy_delegate.h" #include "tensorflow/lite/interpreter.h" #include "tensorflow/lite/kernels/builtin_op_kernels.h" namespace tflite { namespace { -// Delegate options. -struct TestSimpleDelegateOptions { - // Allowed ops to delegate. - int allowed_builtin_code; - // Report error during init. - bool error_during_init = false; - // Report error during prepare. - bool error_during_prepare = false; - // Report error during invoke. - bool error_during_invoke = false; -}; - -// Dummy delegate kernel. -class TestSimpleDelegateKernel : public SimpleDelegateKernelInterface { - public: - explicit TestSimpleDelegateKernel(TestSimpleDelegateOptions options) - : options_(options) {} - - TfLiteStatus Init(TfLiteContext* context, - const TfLiteDelegateParams* params) override { - return !options_.error_during_init ? kTfLiteOk : kTfLiteError; - } - - TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) override { - return !options_.error_during_prepare ? kTfLiteOk : kTfLiteError; - } - - TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) override { - return !options_.error_during_invoke ? kTfLiteOk : kTfLiteError; - } - - private: - TestSimpleDelegateOptions options_; -}; - -// Simple delegate which implements the interface of SimpleDelegateInterface. -// This holds the Delegate capabilities. -class TestSimpleDelegate : public SimpleDelegateInterface { - public: - explicit TestSimpleDelegate(TestSimpleDelegateOptions options) - : options_(options) {} - bool IsNodeSupportedByDelegate(const TfLiteRegistration* registration, - const TfLiteNode* node, - TfLiteContext* context) const override { - return options_.allowed_builtin_code == registration->builtin_code; - } - - TfLiteStatus Initialize(TfLiteContext* context) override { return kTfLiteOk; } - - const char* Name() const override { - static constexpr char kName[] = "TestSimpleDelegate"; - return kName; - } - - std::unique_ptr<SimpleDelegateKernelInterface> CreateDelegateKernelInterface() - override { - return std::make_unique<TestSimpleDelegateKernel>(options_); - } - - private: - TestSimpleDelegateOptions options_; -}; - class TestDelegate : public ::testing::Test { protected: void SetUp() override { @@ -125,16 +61,15 @@ class TestDelegate : public ::testing::Test { }; TEST_F(TestDelegate, BasicDelegate) { - TestSimpleDelegateOptions options; + DummyDelegateOptions options = TfLiteDummyDelegateOptionsDefault(); options.allowed_builtin_code = kTfLiteBuiltinAdd; - auto delegate = TfLiteDelegateFactory::Create( - std::make_unique<TestSimpleDelegate>(options)); + auto delegate = TfLiteDummyDelegateCreateUnique(&options); interpreter_->ModifyGraphWithDelegate(std::move(delegate)); ASSERT_EQ(interpreter_->execution_plan().size(), 1); int node = interpreter_->execution_plan()[0]; const auto* node_and_reg = interpreter_->node_and_registration(node); - EXPECT_STREQ("TestSimpleDelegate", node_and_reg->second.custom_name); + EXPECT_STREQ("DummyDelegate", node_and_reg->second.custom_name); EXPECT_EQ(1, node_and_reg->second.version); const TfLiteDelegateParams* params = static_cast<const TfLiteDelegateParams*>( @@ -154,42 +89,38 @@ TEST_F(TestDelegate, BasicDelegate) { } TEST_F(TestDelegate, NoNodesToDelegate) { - TestSimpleDelegateOptions options; + DummyDelegateOptions options = TfLiteDummyDelegateOptionsDefault(); options.allowed_builtin_code = kTfLiteBuiltinSub; - auto delegate = TfLiteDelegateFactory::Create( - std::make_unique<TestSimpleDelegate>(options)); + auto delegate = TfLiteDummyDelegateCreateUnique(&options); interpreter_->ModifyGraphWithDelegate(std::move(delegate)); ASSERT_EQ(interpreter_->execution_plan().size(), 3); } TEST_F(TestDelegate, DelegateFailedPrepare) { - TestSimpleDelegateOptions options; + DummyDelegateOptions options = TfLiteDummyDelegateOptionsDefault(); options.allowed_builtin_code = kTfLiteBuiltinAdd; options.error_during_prepare = true; - auto delegate = TfLiteDelegateFactory::Create( - std::make_unique<TestSimpleDelegate>(options)); + auto delegate = TfLiteDummyDelegateCreateUnique(&options); ASSERT_EQ(kTfLiteDelegateError, interpreter_->ModifyGraphWithDelegate(std::move(delegate))); } TEST_F(TestDelegate, DelegateFailedInvoke) { - TestSimpleDelegateOptions options; + DummyDelegateOptions options = TfLiteDummyDelegateOptionsDefault(); options.allowed_builtin_code = kTfLiteBuiltinAdd; options.error_during_invoke = true; - auto delegate = TfLiteDelegateFactory::Create( - std::make_unique<TestSimpleDelegate>(options)); + auto delegate = TfLiteDummyDelegateCreateUnique(&options); ASSERT_EQ(kTfLiteOk, interpreter_->ModifyGraphWithDelegate(std::move(delegate))); ASSERT_EQ(kTfLiteError, interpreter_->Invoke()); } TEST_F(TestDelegate, DelegateFailedInit) { - TestSimpleDelegateOptions options; + DummyDelegateOptions options = TfLiteDummyDelegateOptionsDefault(); options.allowed_builtin_code = kTfLiteBuiltinAdd; options.error_during_init = true; - auto delegate = TfLiteDelegateFactory::Create( - std::make_unique<TestSimpleDelegate>(options)); + auto delegate = TfLiteDummyDelegateCreateUnique(&options); ASSERT_EQ(kTfLiteDelegateError, interpreter_->ModifyGraphWithDelegate(std::move(delegate))); } diff --git a/tensorflow/lite/tools/benchmark/BUILD b/tensorflow/lite/tools/benchmark/BUILD index c94e1dba7fe..774e7ed7088 100644 --- a/tensorflow/lite/tools/benchmark/BUILD +++ b/tensorflow/lite/tools/benchmark/BUILD @@ -11,12 +11,25 @@ package( common_copts = ["-Wall"] + tflite_copts() -cc_binary( - name = "benchmark_model", +# We create a library for benchmark_main.cc to faciliate the creation of a +# customized benchmark model binary that only needs linking with extra +# dependency, e.g., enabling creating of benchmark binaries with a custom +# delegate provider. +cc_library( + name = "benchmark_model_main", srcs = [ "benchmark_main.cc", ], copts = common_copts, + deps = [ + ":benchmark_tflite_model_lib", + "//tensorflow/lite/tools:logging", + ], +) + +cc_binary( + name = "benchmark_model", + copts = common_copts, linkopts = tflite_linkopts() + select({ "//tensorflow:android": [ "-pie", # Android 5.0 and later supports only PIE @@ -27,8 +40,7 @@ cc_binary( }), tags = ["builder_default_android_arm64"], deps = [ - ":benchmark_tflite_model_lib", - "//tensorflow/lite/tools:logging", + ":benchmark_model_main", ], ) @@ -42,6 +54,7 @@ cc_binary( "//tensorflow:android": [ "-pie", # Android 5.0 and later supports only PIE "-lm", # some builtin ops, e.g., tanh, need -lm + "-Wl,--rpath=/data/local/tmp/", # Hexagon delegate libraries should be in /data/local/tmp ], "//conditions:default": [], }),