Introduces a new experimental package that:
- Defines a schema for configuring delegates - Defines a C++ plugin mechanism using the schema, so that code can support configuring arbitrary delegates without a build-time dependency PiperOrigin-RevId: 316678829 Change-Id: I36ce8a6175b550d83dfe9cf1f237a04173fb8b16
This commit is contained in:
parent
426f62af5e
commit
cb60e1c14b
|
@ -0,0 +1,165 @@
|
||||||
|
# Copyright 2019 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.
|
||||||
|
# ==============================================================================
|
||||||
|
|
||||||
|
load("@flatbuffers//:build_defs.bzl", "flatbuffer_cc_library", "flatbuffer_java_library", "flatc_path")
|
||||||
|
|
||||||
|
package(
|
||||||
|
default_visibility = [
|
||||||
|
"//visibility:public",
|
||||||
|
],
|
||||||
|
licenses = ["notice"], # Apache 2.0
|
||||||
|
)
|
||||||
|
|
||||||
|
genrule(
|
||||||
|
name = "configuration_schema",
|
||||||
|
srcs = ["configuration.proto"],
|
||||||
|
outs = ["configuration.fbs"],
|
||||||
|
# We rename the namespace since otherwise the proto classes and flatbuffer
|
||||||
|
# classes would have the same names.
|
||||||
|
cmd = """
|
||||||
|
$(location {}) --proto -o $(@D) $(location :configuration.proto)
|
||||||
|
perl -p -i -e 's/tflite.proto/tflite/' $(@D)/configuration.fbs
|
||||||
|
""".format(flatc_path),
|
||||||
|
tools = [
|
||||||
|
flatc_path,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
genrule(
|
||||||
|
name = "configuration_fbs_contents_cc",
|
||||||
|
srcs = ["configuration.fbs"],
|
||||||
|
outs = ["configuration_fbs_contents-inl.h"],
|
||||||
|
cmd = """
|
||||||
|
echo 'constexpr char configuration_fbs_contents[] = R"Delimiter(' > $(@)
|
||||||
|
cat < $(<) >> $(@)
|
||||||
|
echo ')Delimiter";' >> $(@)
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
|
proto_library(
|
||||||
|
name = "configuration_proto",
|
||||||
|
srcs = [
|
||||||
|
"configuration.proto",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_proto_library(
|
||||||
|
name = "configuration_cc_proto",
|
||||||
|
deps = [":configuration_proto"],
|
||||||
|
)
|
||||||
|
|
||||||
|
java_lite_proto_library(
|
||||||
|
name = "configuration_java_proto_lite",
|
||||||
|
deps = [":configuration_proto"],
|
||||||
|
)
|
||||||
|
|
||||||
|
flatbuffer_cc_library(
|
||||||
|
name = "configuration_fbs",
|
||||||
|
srcs = [":configuration.fbs"],
|
||||||
|
)
|
||||||
|
|
||||||
|
flatbuffer_java_library(
|
||||||
|
name = "configuration_fbs_java",
|
||||||
|
srcs = [":configuration.fbs"],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "proto_to_flatbuffer",
|
||||||
|
srcs = [
|
||||||
|
"configuration_fbs_contents-inl.h",
|
||||||
|
"proto_to_flatbuffer.cc",
|
||||||
|
],
|
||||||
|
hdrs = ["proto_to_flatbuffer.h"],
|
||||||
|
deps = [
|
||||||
|
":configuration_cc_proto",
|
||||||
|
":configuration_fbs",
|
||||||
|
"//tensorflow/core/platform:protobuf",
|
||||||
|
"//tensorflow/lite:minimal_logging",
|
||||||
|
"@flatbuffers",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "delegate_registry",
|
||||||
|
srcs = ["delegate_registry.cc"],
|
||||||
|
hdrs = ["delegate_registry.h"],
|
||||||
|
deps = [
|
||||||
|
":configuration_fbs",
|
||||||
|
"//tensorflow/lite/c:common",
|
||||||
|
"@com_google_absl//absl/synchronization",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "nnapi_plugin",
|
||||||
|
srcs = ["nnapi_plugin.cc"],
|
||||||
|
deps = [
|
||||||
|
":configuration_fbs",
|
||||||
|
":delegate_registry",
|
||||||
|
"//tensorflow/lite/delegates/nnapi:nnapi_delegate",
|
||||||
|
"@com_google_absl//absl/memory",
|
||||||
|
],
|
||||||
|
alwayslink = 1, # For registration to always run.
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_test(
|
||||||
|
name = "nnapi_plugin_test",
|
||||||
|
srcs = ["nnapi_plugin_test.cc"],
|
||||||
|
tags = [
|
||||||
|
"no_mac",
|
||||||
|
"no_windows",
|
||||||
|
"tflite_not_portable_ios",
|
||||||
|
],
|
||||||
|
deps = [
|
||||||
|
":configuration_fbs",
|
||||||
|
":delegate_registry",
|
||||||
|
":nnapi_plugin",
|
||||||
|
"//tensorflow/lite:framework",
|
||||||
|
"//tensorflow/lite/c:common",
|
||||||
|
"//tensorflow/lite/delegates/nnapi:nnapi_delegate",
|
||||||
|
"//tensorflow/lite/delegates/nnapi:nnapi_delegate_mock_test",
|
||||||
|
"//tensorflow/lite/kernels:test_util",
|
||||||
|
"@com_google_googletest//:gtest_main",
|
||||||
|
"@flatbuffers",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "hexagon_plugin",
|
||||||
|
srcs = ["hexagon_plugin.cc"],
|
||||||
|
deps = [
|
||||||
|
":configuration_fbs",
|
||||||
|
":delegate_registry",
|
||||||
|
"@com_google_absl//absl/memory",
|
||||||
|
] + select({
|
||||||
|
"//tensorflow:android": [
|
||||||
|
"//tensorflow/lite/delegates/hexagon:hexagon_delegate",
|
||||||
|
],
|
||||||
|
"//conditions:default": [],
|
||||||
|
}),
|
||||||
|
alwayslink = 1, # For registration to always run.
|
||||||
|
)
|
||||||
|
|
||||||
|
cc_library(
|
||||||
|
name = "gpu_plugin",
|
||||||
|
srcs = ["gpu_plugin.cc"],
|
||||||
|
deps = [
|
||||||
|
":configuration_fbs",
|
||||||
|
":delegate_registry",
|
||||||
|
"//tensorflow/lite/delegates/gpu:delegate",
|
||||||
|
"@com_google_absl//absl/memory",
|
||||||
|
],
|
||||||
|
alwayslink = 1, # For registration to always run.
|
||||||
|
)
|
|
@ -0,0 +1,208 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// This schema defines how to configure TFLite for delegation. These
|
||||||
|
// definitions can be used in multiple ways: as output of a compatibility list,
|
||||||
|
// in benchmarking tools and to decouple delegate instantiation from code.
|
||||||
|
//
|
||||||
|
// The schema is work-in-progress, covering the most broadly used delegates and
|
||||||
|
// options.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package tflite.proto;
|
||||||
|
|
||||||
|
// ExecutionPreference is used to match accelerators against the preferences of
|
||||||
|
// the current application or usecase. Some of the values here can appear both
|
||||||
|
// in the compatibility list and as input, some only as input.
|
||||||
|
//
|
||||||
|
// These are separate from NNAPIExecutionPreference - the compatibility list
|
||||||
|
// design doesn't assume a one-to-one mapping between which usecases
|
||||||
|
// compatibility list entries have been developed for and what settings are used
|
||||||
|
// for NNAPI.
|
||||||
|
enum ExecutionPreference {
|
||||||
|
// Match any selected preference. Whitelist (semantically - value is same as
|
||||||
|
// on input).
|
||||||
|
ANY = 0;
|
||||||
|
// Match low latency preference. Both compatibility list and input.
|
||||||
|
LOW_LATENCY = 1;
|
||||||
|
// Math low power preference. Both compatibility list and input.
|
||||||
|
LOW_POWER = 2;
|
||||||
|
// Never accelerate. Can be used for input to compatibility list or for
|
||||||
|
// standalone Acceleration configuration.
|
||||||
|
FORCE_CPU = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TFLite delegate to use.
|
||||||
|
enum Delegate {
|
||||||
|
NONE = 0;
|
||||||
|
NNAPI = 1;
|
||||||
|
GPU = 2;
|
||||||
|
HEXAGON = 3;
|
||||||
|
XNNPACK = 4;
|
||||||
|
// TODO(b/157893534): Support exposing edgetpu tflite delegate creation
|
||||||
|
// options.
|
||||||
|
EDGETPU = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum NNAPIExecutionPreference {
|
||||||
|
// Undefined.
|
||||||
|
UNDEFINED = 0;
|
||||||
|
// Prefer executing in a way that minimizes battery drain.
|
||||||
|
NNAPI_LOW_POWER = 1;
|
||||||
|
// Prefer returning a single answer as fast as possible, even if this causes
|
||||||
|
// more power consumption.
|
||||||
|
NNAPI_FAST_SINGLE_ANSWER = 2;
|
||||||
|
// Prefer maximizing the throughput of successive frames, for example when
|
||||||
|
// processing successive frames coming from the camera.
|
||||||
|
NNAPI_SUSTAINED_SPEED = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One possible acceleration configuration.
|
||||||
|
message ComputeSettings {
|
||||||
|
// Which preference to use this accelerator for.
|
||||||
|
optional ExecutionPreference preference = 1;
|
||||||
|
// How to configure TFLite
|
||||||
|
optional TFLiteSettings tflite_settings = 2;
|
||||||
|
// Identifiers to use for instrumentation and telemetry.
|
||||||
|
optional string model_namespace_for_statistics = 3;
|
||||||
|
optional string model_identifier_for_statistics = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NNAPI delegate settings.
|
||||||
|
message NNAPISettings {
|
||||||
|
// Which instance (NNAPI accelerator) to use. One driver may provide several
|
||||||
|
// accelerators (though a driver may also hide several back-ends behind one
|
||||||
|
// name, at the choice of the driver vendor).
|
||||||
|
// Note that driver introspection is only available in Android Q and later.
|
||||||
|
optional string accelerator_name = 1;
|
||||||
|
|
||||||
|
// NNAPI model compilation caching settings to be passed to
|
||||||
|
// tflite::StatefulNnApiDelegate
|
||||||
|
optional string cache_directory = 2;
|
||||||
|
optional string model_token = 3;
|
||||||
|
|
||||||
|
// NNAPI execution preference to pass. See
|
||||||
|
// https://developer.android.com/ndk/reference/group/neural-networks.html
|
||||||
|
optional NNAPIExecutionPreference execution_preference = 4;
|
||||||
|
|
||||||
|
// Number of instances to cache for the same model (for input size
|
||||||
|
// changes). This is mandatory for getting reasonable performance in that
|
||||||
|
// case.
|
||||||
|
optional int32 no_of_nnapi_instances_to_cache = 5;
|
||||||
|
|
||||||
|
// Whether to automatically fall back to TFLite CPU path.
|
||||||
|
optional FallbackSettings fallback_settings = 6;
|
||||||
|
|
||||||
|
// Whether to allow use of NNAPI CPU (nnapi-reference accelerator) on Android
|
||||||
|
// 10+ when an accelerator name is not specified. The NNAPI CPU typically
|
||||||
|
// performs less well than the TfLite built-in kernels; but allowing allows a
|
||||||
|
// model to be partially accelerated which may be a win.
|
||||||
|
optional bool allow_nnapi_cpu_on_android_10_plus = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Which GPU backend to select. Default behaviour on Android is to try OpenCL
|
||||||
|
// and if it's not available fall back to OpenGL.
|
||||||
|
enum GPUBackend {
|
||||||
|
UNSET = 0;
|
||||||
|
OPENCL = 1;
|
||||||
|
OPENGL = 2;
|
||||||
|
// Not yet supported.
|
||||||
|
// VULKAN = 3;
|
||||||
|
// METAL = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GPU Delegate settings.
|
||||||
|
//
|
||||||
|
// See
|
||||||
|
// https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/gpu/delegate.h
|
||||||
|
message GPUSettings {
|
||||||
|
optional bool is_precision_loss_allowed = 1;
|
||||||
|
optional bool enable_quantized_inference = 2 [default = true];
|
||||||
|
optional GPUBackend force_backend = 3;
|
||||||
|
// TODO(b/152019007): add remaining options.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hexagon Delegate settings.
|
||||||
|
//
|
||||||
|
// See
|
||||||
|
// https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/hexagon/hexagon_delegate.h
|
||||||
|
message HexagonSettings {
|
||||||
|
optional int32 debug_level = 1;
|
||||||
|
optional int32 powersave_level = 2;
|
||||||
|
optional bool print_graph_profile = 3;
|
||||||
|
optional bool print_graph_debug = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XNNPack Delegate settings.
|
||||||
|
//
|
||||||
|
// See
|
||||||
|
// https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/delegates/xnnpack/xnnpack_delegate.h
|
||||||
|
message XNNPackSettings {
|
||||||
|
optional int32 num_threads = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CPUSettings {
|
||||||
|
optional int32 num_threads = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// How to configure TFLite.
|
||||||
|
message TFLiteSettings {
|
||||||
|
// Which delegate to use.
|
||||||
|
optional Delegate delegate = 1;
|
||||||
|
|
||||||
|
// How to configure the chosen delegate.
|
||||||
|
// (In principle we would like to use 'oneof', but flatc turns that into an
|
||||||
|
// nested anonymous table rather than a union. See
|
||||||
|
// https://github.com/google/flatbuffers/issues/4628).
|
||||||
|
optional NNAPISettings nnapi_settings = 2;
|
||||||
|
optional GPUSettings gpu_settings = 3;
|
||||||
|
optional HexagonSettings hexagon_settings = 4;
|
||||||
|
optional XNNPackSettings xnnpack_settings = 5;
|
||||||
|
|
||||||
|
// How to configure CPU execution.
|
||||||
|
optional CPUSettings cpu_settings = 6;
|
||||||
|
|
||||||
|
// Shared delegation settings.
|
||||||
|
optional int32 max_delegated_partitions = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether to automatically fallback to TFLite CPU path on delegation errors.
|
||||||
|
//
|
||||||
|
// Typically fallback is enabled in production use but disabled in tests and
|
||||||
|
// benchmarks to ensure they test the intended path.
|
||||||
|
message FallbackSettings {
|
||||||
|
// Whether to allow automatically falling back to TfLite CPU path on
|
||||||
|
// compilation failure. Default is not allowing automatic fallback.
|
||||||
|
//
|
||||||
|
// This is useful in naive production usecases where the caller would prefer
|
||||||
|
// for the model to run even if it's not accelerated. More advanced users will
|
||||||
|
// implement fallback themselves; e.g., by using a different model on CPU.
|
||||||
|
//
|
||||||
|
// Note that compilation errors may occur either at initial
|
||||||
|
// ModifyGraphWithDelegate() time, or when calling AllocateTensors() after
|
||||||
|
// resizing.
|
||||||
|
optional bool allow_automatic_fallback_on_compilation_error = 7;
|
||||||
|
// Whether to allow automatically falling back to TfLite CPU path on
|
||||||
|
// execution error. Default is not allowing automatic fallback.
|
||||||
|
//
|
||||||
|
// Experimental, use with care (only when you have complete control over the
|
||||||
|
// client code).
|
||||||
|
//
|
||||||
|
// The caveat above for compilation error holds. Additionally, execution-time
|
||||||
|
// errors are harder to handle automatically as they require invalidating the
|
||||||
|
// TfLite interpreter which most client code has not been designed to deal
|
||||||
|
// with.
|
||||||
|
optional bool allow_automatic_fallback_on_execution_error = 8;
|
||||||
|
}
|
|
@ -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.
|
||||||
|
==============================================================================*/
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/delegate_registry.h"
|
||||||
|
|
||||||
|
#include "absl/synchronization/mutex.h"
|
||||||
|
|
||||||
|
namespace tflite {
|
||||||
|
namespace delegates {
|
||||||
|
|
||||||
|
void DelegatePluginRegistry::RegisterImpl(
|
||||||
|
const std::string& name,
|
||||||
|
std::function<
|
||||||
|
std::unique_ptr<DelegatePluginInterface>(const TFLiteSettings&)>
|
||||||
|
creator_function) {
|
||||||
|
absl::MutexLock lock(&mutex_);
|
||||||
|
factories_[name] = creator_function;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<DelegatePluginInterface> DelegatePluginRegistry::CreateImpl(
|
||||||
|
const std::string& name, const TFLiteSettings& settings) {
|
||||||
|
absl::MutexLock lock(&mutex_);
|
||||||
|
auto it = factories_.find(name);
|
||||||
|
if (it != factories_.end()) {
|
||||||
|
return it->second(settings);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DelegatePluginRegistry* DelegatePluginRegistry::GetSingleton() {
|
||||||
|
static auto* instance = new DelegatePluginRegistry();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<DelegatePluginInterface> DelegatePluginRegistry::CreateByName(
|
||||||
|
const std::string& name, const TFLiteSettings& settings) {
|
||||||
|
auto* const instance = DelegatePluginRegistry::GetSingleton();
|
||||||
|
return instance->CreateImpl(name, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
DelegatePluginRegistry::Register::Register(const std::string& name,
|
||||||
|
CreatorFunction creator_function) {
|
||||||
|
auto* const instance = DelegatePluginRegistry::GetSingleton();
|
||||||
|
instance->RegisterImpl(name, creator_function);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace delegates
|
||||||
|
} // namespace tflite
|
|
@ -0,0 +1,95 @@
|
||||||
|
/* 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_EXPERIMENTAL_ACCELERATION_CONFIGURATION_DELEGATE_REGISTRY_H_
|
||||||
|
#define TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_CONFIGURATION_DELEGATE_REGISTRY_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "absl/synchronization/mutex.h"
|
||||||
|
#include "tensorflow/lite/c/common.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/configuration_generated.h"
|
||||||
|
|
||||||
|
// Defines an interface for TFLite delegate plugins.
|
||||||
|
//
|
||||||
|
// The acceleration library aims to support all TFLite delegates based on
|
||||||
|
// configuration expressed as data (flatbuffers). However, consumers tend to
|
||||||
|
// care about size and also use a subset of delegates. Hence we don't want to
|
||||||
|
// statically build against all delegates.
|
||||||
|
//
|
||||||
|
// This interface allows plugins to handle specific delegates.
|
||||||
|
//
|
||||||
|
// Goal of this interface is not to abstract away all the differences between
|
||||||
|
// delegates. The goal is only to avoid static linking.
|
||||||
|
//
|
||||||
|
// Note to implementers: this interface may change if new delegates don't fit
|
||||||
|
// into the same design.
|
||||||
|
namespace tflite {
|
||||||
|
namespace delegates {
|
||||||
|
|
||||||
|
// Same w/ Interpreter::TfLiteDelegatePtr to avoid pulling
|
||||||
|
// tensorflow/lite/interpreter.h dependency
|
||||||
|
using TfLiteDelegatePtr =
|
||||||
|
std::unique_ptr<TfLiteDelegate, void (*)(TfLiteDelegate*)>;
|
||||||
|
|
||||||
|
class DelegatePluginInterface {
|
||||||
|
public:
|
||||||
|
virtual TfLiteDelegatePtr Create() = 0;
|
||||||
|
virtual int GetDelegateErrno(TfLiteDelegate* from_delegate) = 0;
|
||||||
|
virtual ~DelegatePluginInterface() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A stripped-down registry that allows delegate plugins to be created by name.
|
||||||
|
//
|
||||||
|
// Limitations:
|
||||||
|
// - Doesn't allow deregistration.
|
||||||
|
// - Doesn't check for duplication registration.
|
||||||
|
//
|
||||||
|
class DelegatePluginRegistry {
|
||||||
|
public:
|
||||||
|
typedef std::function<std::unique_ptr<DelegatePluginInterface>(
|
||||||
|
const TFLiteSettings&)>
|
||||||
|
CreatorFunction;
|
||||||
|
// Returns a DelegatePluginInterface registered with `name` or nullptr if no
|
||||||
|
// matching plugin found.
|
||||||
|
// TFLiteSettings is per-plugin, so that the corresponding delegate options
|
||||||
|
// data lifetime is maintained.
|
||||||
|
static std::unique_ptr<DelegatePluginInterface> CreateByName(
|
||||||
|
const std::string& name, const TFLiteSettings& settings);
|
||||||
|
|
||||||
|
// Struct to be statically allocated for registration.
|
||||||
|
struct Register {
|
||||||
|
Register(const std::string& name, CreatorFunction creator_function);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RegisterImpl(const std::string& name, CreatorFunction creator_function);
|
||||||
|
std::unique_ptr<DelegatePluginInterface> CreateImpl(
|
||||||
|
const std::string& name, const TFLiteSettings& settings);
|
||||||
|
static DelegatePluginRegistry* GetSingleton();
|
||||||
|
std::unordered_map<std::string, CreatorFunction> factories_;
|
||||||
|
absl::Mutex mutex_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace delegates
|
||||||
|
} // namespace tflite
|
||||||
|
|
||||||
|
#define TFLITE_REGISTER_DELEGATE_FACTORY_FUNCTION_VNAME(name, f) \
|
||||||
|
static auto* g_delegate_plugin_##name##_ = \
|
||||||
|
new DelegatePluginRegistry::Register(#name, f);
|
||||||
|
#define TFLITE_REGISTER_DELEGATE_FACTORY_FUNCTION(name, f) \
|
||||||
|
TFLITE_REGISTER_DELEGATE_FACTORY_FUNCTION_VNAME(name, f);
|
||||||
|
|
||||||
|
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_CONFIGURATION_DELEGATE_REGISTRY_H_
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* 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 <memory>
|
||||||
|
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
#include "tensorflow/lite/delegates/gpu/delegate.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/configuration_generated.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/delegate_registry.h"
|
||||||
|
|
||||||
|
namespace tflite {
|
||||||
|
namespace delegates {
|
||||||
|
class GpuPlugin : public DelegatePluginInterface {
|
||||||
|
public:
|
||||||
|
TfLiteDelegatePtr Create() override {
|
||||||
|
return TfLiteDelegatePtr(TfLiteGpuDelegateV2Create(&options_),
|
||||||
|
TfLiteGpuDelegateV2Delete);
|
||||||
|
}
|
||||||
|
int GetDelegateErrno(TfLiteDelegate* from_delegate) override { return 0; }
|
||||||
|
static std::unique_ptr<DelegatePluginInterface> New(
|
||||||
|
const TFLiteSettings& acceleration) {
|
||||||
|
return absl::make_unique<GpuPlugin>(acceleration);
|
||||||
|
}
|
||||||
|
explicit GpuPlugin(const TFLiteSettings& tflite_settings)
|
||||||
|
: options_(TfLiteGpuDelegateOptionsV2Default()) {
|
||||||
|
const auto* gpu_settings = tflite_settings.gpu_settings();
|
||||||
|
if (gpu_settings) {
|
||||||
|
options_.inference_priority1 =
|
||||||
|
gpu_settings->is_precision_loss_allowed()
|
||||||
|
? TFLITE_GPU_INFERENCE_PRIORITY_MIN_LATENCY
|
||||||
|
: TFLITE_GPU_INFERENCE_PRIORITY_MAX_PRECISION;
|
||||||
|
if (gpu_settings->enable_quantized_inference()) {
|
||||||
|
options_.experimental_flags |=
|
||||||
|
TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_QUANT;
|
||||||
|
}
|
||||||
|
if (gpu_settings->force_backend() == GPUBackend_OPENCL) {
|
||||||
|
options_.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_CL_ONLY;
|
||||||
|
} else if (gpu_settings->force_backend() == GPUBackend_OPENGL) {
|
||||||
|
options_.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_GL_ONLY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TfLiteGpuDelegateOptionsV2 options_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TFLITE_REGISTER_DELEGATE_FACTORY_FUNCTION(GpuPlugin, GpuPlugin::New);
|
||||||
|
|
||||||
|
} // namespace delegates
|
||||||
|
} // namespace tflite
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* 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 <memory>
|
||||||
|
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/configuration_generated.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/delegate_registry.h"
|
||||||
|
|
||||||
|
#if defined(__ARM_ARCH)
|
||||||
|
#include "tensorflow/lite/delegates/hexagon/hexagon_delegate.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace tflite {
|
||||||
|
namespace delegates {
|
||||||
|
class HexagonPlugin : public DelegatePluginInterface {
|
||||||
|
public:
|
||||||
|
TfLiteDelegatePtr Create() override {
|
||||||
|
#if defined(__ARM_ARCH)
|
||||||
|
TfLiteHexagonInit();
|
||||||
|
auto* delegate_ptr = TfLiteHexagonDelegateCreate(&options_);
|
||||||
|
TfLiteDelegatePtr delegate(delegate_ptr, [](TfLiteDelegate* delegate) {
|
||||||
|
TfLiteHexagonDelegateDelete(delegate);
|
||||||
|
TfLiteHexagonTearDown();
|
||||||
|
});
|
||||||
|
return delegate;
|
||||||
|
#else // !defined(__ARM_ARCH)
|
||||||
|
return TfLiteDelegatePtr(nullptr, [](TfLiteDelegate*) {});
|
||||||
|
#endif // defined(__ARM_ARCH)
|
||||||
|
}
|
||||||
|
int GetDelegateErrno(TfLiteDelegate* /* from_delegate */) override {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static std::unique_ptr<HexagonPlugin> New(
|
||||||
|
const TFLiteSettings& tflite_settings) {
|
||||||
|
return absl::make_unique<HexagonPlugin>(tflite_settings);
|
||||||
|
}
|
||||||
|
explicit HexagonPlugin(const TFLiteSettings& tflite_settings) {
|
||||||
|
const HexagonSettings* settings = tflite_settings.hexagon_settings();
|
||||||
|
#if defined(__ARM_ARCH)
|
||||||
|
options_ = TfLiteHexagonDelegateOptions({0});
|
||||||
|
if (settings) {
|
||||||
|
options_.debug_level = settings->debug_level();
|
||||||
|
options_.powersave_level = settings->powersave_level();
|
||||||
|
options_.print_graph_profile = settings->print_graph_profile();
|
||||||
|
options_.print_graph_debug = settings->print_graph_debug();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)settings;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(__ARM_ARCH)
|
||||||
|
TfLiteHexagonDelegateOptions options_;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
TFLITE_REGISTER_DELEGATE_FACTORY_FUNCTION(HexagonPlugin, HexagonPlugin::New);
|
||||||
|
|
||||||
|
} // namespace delegates
|
||||||
|
} // namespace tflite
|
|
@ -0,0 +1,93 @@
|
||||||
|
/* 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 <memory>
|
||||||
|
|
||||||
|
#include "absl/memory/memory.h"
|
||||||
|
#include "tensorflow/lite/delegates/nnapi/nnapi_delegate.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/configuration_generated.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/delegate_registry.h"
|
||||||
|
|
||||||
|
namespace tflite {
|
||||||
|
namespace delegates {
|
||||||
|
|
||||||
|
inline tflite::StatefulNnApiDelegate::Options::ExecutionPreference
|
||||||
|
ConvertExecutionPrefence(
|
||||||
|
NNAPIExecutionPreference from_compatibility_preference) {
|
||||||
|
using TflitePreference =
|
||||||
|
tflite::StatefulNnApiDelegate::Options::ExecutionPreference;
|
||||||
|
switch (from_compatibility_preference) {
|
||||||
|
case NNAPIExecutionPreference_NNAPI_LOW_POWER:
|
||||||
|
return TflitePreference::kLowPower;
|
||||||
|
case NNAPIExecutionPreference_NNAPI_FAST_SINGLE_ANSWER:
|
||||||
|
return TflitePreference::kFastSingleAnswer;
|
||||||
|
case NNAPIExecutionPreference_NNAPI_SUSTAINED_SPEED:
|
||||||
|
return TflitePreference::kSustainedSpeed;
|
||||||
|
default:
|
||||||
|
return TflitePreference::kUndefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NnapiPlugin : public DelegatePluginInterface {
|
||||||
|
public:
|
||||||
|
TfLiteDelegatePtr Create() override {
|
||||||
|
auto nnapi_delegate =
|
||||||
|
absl::make_unique<tflite::StatefulNnApiDelegate>(options_);
|
||||||
|
return TfLiteDelegatePtr(
|
||||||
|
nnapi_delegate.release(), [](TfLiteDelegate* delegate) {
|
||||||
|
delete reinterpret_cast<tflite::StatefulNnApiDelegate*>(delegate);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
int GetDelegateErrno(TfLiteDelegate* from_delegate) override {
|
||||||
|
auto nnapi_delegate =
|
||||||
|
reinterpret_cast<tflite::StatefulNnApiDelegate*>(from_delegate);
|
||||||
|
return nnapi_delegate->GetNnApiErrno();
|
||||||
|
}
|
||||||
|
static std::unique_ptr<NnapiPlugin> New(
|
||||||
|
const TFLiteSettings& tflite_settings) {
|
||||||
|
return absl::make_unique<NnapiPlugin>(tflite_settings);
|
||||||
|
}
|
||||||
|
explicit NnapiPlugin(const TFLiteSettings& tflite_settings) {
|
||||||
|
const NNAPISettings* nnapi_settings = tflite_settings.nnapi_settings();
|
||||||
|
if (!nnapi_settings) return;
|
||||||
|
if (nnapi_settings->accelerator_name() &&
|
||||||
|
nnapi_settings->accelerator_name()->Length() != 0) {
|
||||||
|
accelerator_ = nnapi_settings->accelerator_name()->str();
|
||||||
|
options_.accelerator_name = accelerator_.c_str();
|
||||||
|
}
|
||||||
|
if (nnapi_settings->cache_directory() &&
|
||||||
|
nnapi_settings->cache_directory()->Length() != 0) {
|
||||||
|
cache_dir_ = nnapi_settings->cache_directory()->str();
|
||||||
|
options_.cache_dir = cache_dir_.c_str();
|
||||||
|
}
|
||||||
|
if (nnapi_settings->model_token() &&
|
||||||
|
nnapi_settings->model_token()->Length() != 0) {
|
||||||
|
model_token_ = nnapi_settings->model_token()->str();
|
||||||
|
options_.model_token = model_token_.c_str();
|
||||||
|
}
|
||||||
|
options_.execution_preference =
|
||||||
|
ConvertExecutionPrefence(nnapi_settings->execution_preference());
|
||||||
|
options_.disallow_nnapi_cpu =
|
||||||
|
!nnapi_settings->allow_nnapi_cpu_on_android_10_plus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string accelerator_, cache_dir_, model_token_;
|
||||||
|
tflite::StatefulNnApiDelegate::Options options_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TFLITE_REGISTER_DELEGATE_FACTORY_FUNCTION(NnapiPlugin, NnapiPlugin::New);
|
||||||
|
|
||||||
|
} // namespace delegates
|
||||||
|
} // namespace tflite
|
|
@ -0,0 +1,175 @@
|
||||||
|
/* 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 <memory>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "flatbuffers/flatbuffers.h" // from @flatbuffers
|
||||||
|
#include "tensorflow/lite/c/common.h"
|
||||||
|
#include "tensorflow/lite/delegates/nnapi/nnapi_delegate.h"
|
||||||
|
#include "tensorflow/lite/delegates/nnapi/nnapi_delegate_mock_test.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/configuration_generated.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/delegate_registry.h"
|
||||||
|
#include "tensorflow/lite/interpreter.h"
|
||||||
|
#include "tensorflow/lite/kernels/test_util.h"
|
||||||
|
|
||||||
|
// Tests for checking that the NNAPI Delegate plugin correctly handles all the
|
||||||
|
// options from the flatbuffer.
|
||||||
|
//
|
||||||
|
// Checking done at NNAPI call level, as that is where we have a mockable
|
||||||
|
// layer.
|
||||||
|
namespace tflite {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using delegate::nnapi::NnApiMock;
|
||||||
|
|
||||||
|
class SingleAddOpModel : tflite::SingleOpModel {
|
||||||
|
public:
|
||||||
|
void Build() {
|
||||||
|
int input = AddInput({tflite::TensorType_FLOAT32, {1, 2, 2}});
|
||||||
|
int constant = AddConstInput({tflite::TensorType_FLOAT32, {1, 2, 2}},
|
||||||
|
{1.0f, 1.0f, 1.0f, 1.0f});
|
||||||
|
AddOutput({tflite::TensorType_FLOAT32, {}});
|
||||||
|
|
||||||
|
SetBuiltinOp(tflite::BuiltinOperator_ADD, tflite::BuiltinOptions_AddOptions,
|
||||||
|
tflite::CreateAddOptions(builder_).Union());
|
||||||
|
BuildInterpreter({GetShape(input), GetShape(constant)});
|
||||||
|
}
|
||||||
|
|
||||||
|
tflite::Interpreter* Interpreter() const { return interpreter_.get(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class NNAPIPluginTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
NNAPIPluginTest() : delegate_(nullptr, [](TfLiteDelegate*) {}) {}
|
||||||
|
void SetUp() override {
|
||||||
|
nnapi_ = const_cast<NnApi*>(NnApiImplementation());
|
||||||
|
nnapi_mock_ = absl::make_unique<NnApiMock>(nnapi_);
|
||||||
|
nnapi_->ANeuralNetworksModel_getSupportedOperationsForDevices =
|
||||||
|
[](const ANeuralNetworksModel* model,
|
||||||
|
const ANeuralNetworksDevice* const* devices, uint32_t numDevices,
|
||||||
|
bool* supportedOps) -> int {
|
||||||
|
supportedOps[0] = true;
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
model_.Build();
|
||||||
|
}
|
||||||
|
template <NNAPIExecutionPreference input, int output>
|
||||||
|
void CheckExecutionPreference() {
|
||||||
|
// Note - this uses a template since the NNAPI functions are C function
|
||||||
|
// pointers rather than lambdas so can't capture variables.
|
||||||
|
nnapi_->ANeuralNetworksCompilation_setPreference =
|
||||||
|
[](ANeuralNetworksCompilation* compilation, int32_t preference) {
|
||||||
|
return preference - output;
|
||||||
|
};
|
||||||
|
CreateDelegate(CreateNNAPISettings(fbb_, 0, 0, 0, input));
|
||||||
|
// Since delegation succeeds, the model becomes immutable and hence can't
|
||||||
|
// reuse it.
|
||||||
|
SingleAddOpModel model;
|
||||||
|
model.Build();
|
||||||
|
EXPECT_EQ(model.Interpreter()->ModifyGraphWithDelegate(delegate_.get()),
|
||||||
|
kTfLiteOk)
|
||||||
|
<< " given input: " << input << " expected output: " << output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateDelegate(flatbuffers::Offset<NNAPISettings> settings) {
|
||||||
|
settings_ = flatbuffers::GetTemporaryPointer(
|
||||||
|
fbb_, CreateTFLiteSettings(fbb_, tflite::Delegate_NNAPI, settings));
|
||||||
|
|
||||||
|
plugin_ = delegates::DelegatePluginRegistry::CreateByName("NnapiPlugin",
|
||||||
|
*settings_);
|
||||||
|
delegate_ = plugin_->Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
NnApi* nnapi_;
|
||||||
|
std::unique_ptr<NnApiMock> nnapi_mock_;
|
||||||
|
SingleAddOpModel model_;
|
||||||
|
flatbuffers::FlatBufferBuilder fbb_;
|
||||||
|
const TFLiteSettings* settings_ = nullptr;
|
||||||
|
delegates::TfLiteDelegatePtr delegate_;
|
||||||
|
std::unique_ptr<delegates::DelegatePluginInterface> plugin_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NNAPIPluginTest, PassesAcceleratorName) {
|
||||||
|
// Fails with non-existent "foo".
|
||||||
|
CreateDelegate(CreateNNAPISettings(fbb_, fbb_.CreateString("foo")));
|
||||||
|
EXPECT_EQ(model_.Interpreter()->ModifyGraphWithDelegate(delegate_.get()),
|
||||||
|
kTfLiteDelegateError);
|
||||||
|
|
||||||
|
// Succeeds with "test-device" supported by the mock.
|
||||||
|
CreateDelegate(CreateNNAPISettings(fbb_, fbb_.CreateString("test-device")));
|
||||||
|
EXPECT_EQ(model_.Interpreter()->ModifyGraphWithDelegate(delegate_.get()),
|
||||||
|
kTfLiteOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NNAPIPluginTest, PassesExecutionPreference) {
|
||||||
|
CheckExecutionPreference<NNAPIExecutionPreference_UNDEFINED,
|
||||||
|
StatefulNnApiDelegate::Options::kUndefined>();
|
||||||
|
CheckExecutionPreference<NNAPIExecutionPreference_NNAPI_LOW_POWER,
|
||||||
|
StatefulNnApiDelegate::Options::kLowPower>();
|
||||||
|
CheckExecutionPreference<NNAPIExecutionPreference_NNAPI_FAST_SINGLE_ANSWER,
|
||||||
|
StatefulNnApiDelegate::Options::kFastSingleAnswer>();
|
||||||
|
CheckExecutionPreference<NNAPIExecutionPreference_NNAPI_SUSTAINED_SPEED,
|
||||||
|
StatefulNnApiDelegate::Options::kSustainedSpeed>();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NNAPIPluginTest, PassesCachingParameters) {
|
||||||
|
nnapi_->ANeuralNetworksCompilation_setCaching =
|
||||||
|
[](ANeuralNetworksCompilation* compilation, const char* cacheDir,
|
||||||
|
const uint8_t* token) -> int {
|
||||||
|
if (std::string(cacheDir) != "d") return 1;
|
||||||
|
// Token is hashed with other bits, just check that it's not empty.
|
||||||
|
if (std::string(reinterpret_cast<const char*>(token)).empty()) return 2;
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
CreateDelegate(CreateNNAPISettings(fbb_, 0, fbb_.CreateString("d"),
|
||||||
|
fbb_.CreateString("t")));
|
||||||
|
EXPECT_EQ(model_.Interpreter()->ModifyGraphWithDelegate(delegate_.get()),
|
||||||
|
kTfLiteOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NNAPIPluginTest, PassesFalseNNAPICpuFlag) {
|
||||||
|
CreateDelegate(CreateNNAPISettings(fbb_, 0, 0, 0,
|
||||||
|
NNAPIExecutionPreference_UNDEFINED, 0, 0,
|
||||||
|
/* allow CPU */ false));
|
||||||
|
nnapi_->ANeuralNetworksModel_getSupportedOperationsForDevices =
|
||||||
|
[](const ANeuralNetworksModel* model,
|
||||||
|
const ANeuralNetworksDevice* const* devices, uint32_t numDevices,
|
||||||
|
bool* supportedOps) -> int {
|
||||||
|
supportedOps[0] = true;
|
||||||
|
// Since no CPU, should only pass one device.
|
||||||
|
return numDevices - 1;
|
||||||
|
};
|
||||||
|
EXPECT_EQ(model_.Interpreter()->ModifyGraphWithDelegate(delegate_.get()),
|
||||||
|
kTfLiteOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NNAPIPluginTest, PassesTrueNNAPICpuFlag) {
|
||||||
|
CreateDelegate(CreateNNAPISettings(fbb_, 0, 0, 0,
|
||||||
|
NNAPIExecutionPreference_UNDEFINED, 0, 0,
|
||||||
|
/* allow CPU */ true));
|
||||||
|
nnapi_->ANeuralNetworksModel_getSupportedOperationsForDevices =
|
||||||
|
[](const ANeuralNetworksModel* model,
|
||||||
|
const ANeuralNetworksDevice* const* devices, uint32_t numDevices,
|
||||||
|
bool* supportedOps) -> int {
|
||||||
|
supportedOps[0] = true;
|
||||||
|
// With CPU allowed, should pass two devices.
|
||||||
|
return numDevices - 2;
|
||||||
|
};
|
||||||
|
EXPECT_EQ(model_.Interpreter()->ModifyGraphWithDelegate(delegate_.get()),
|
||||||
|
kTfLiteOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace tflite
|
|
@ -0,0 +1,58 @@
|
||||||
|
/* 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/experimental/acceleration/configuration/proto_to_flatbuffer.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "flatbuffers/idl.h" // from @flatbuffers
|
||||||
|
#include "flatbuffers/util.h" // from @flatbuffers
|
||||||
|
#include "tensorflow/core/platform/protobuf.h"
|
||||||
|
#include "tensorflow/lite/minimal_logging.h"
|
||||||
|
|
||||||
|
namespace tflite {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/configuration_fbs_contents-inl.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
const ComputeSettings* ConvertFromProto(
|
||||||
|
flatbuffers::Parser* parser, const proto::ComputeSettings& proto_settings) {
|
||||||
|
std::string json;
|
||||||
|
tensorflow::protobuf::util::JsonPrintOptions options;
|
||||||
|
options.preserve_proto_field_names = true;
|
||||||
|
options.always_print_primitive_fields = true; // For catching problems.
|
||||||
|
auto status = tensorflow::protobuf::util::MessageToJsonString(proto_settings,
|
||||||
|
&json, options);
|
||||||
|
if (!status.ok()) {
|
||||||
|
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Failed to convert to Json: %s",
|
||||||
|
status.ToString().c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (!parser->Parse(configuration_fbs_contents)) {
|
||||||
|
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Failed to parse schema: %s",
|
||||||
|
parser->error_.c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
parser->SetRootType("tflite.ComputeSettings");
|
||||||
|
if (!parser->Parse(json.c_str())) {
|
||||||
|
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Failed to parse json: %s",
|
||||||
|
parser->error_.c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return flatbuffers::GetRoot<ComputeSettings>(
|
||||||
|
parser->builder_.GetBufferPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tflite
|
|
@ -0,0 +1,32 @@
|
||||||
|
/* 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_EXPERIMENTAL_ACCELERATION_CONFIGURATION_PROTO_TO_FLATBUFFER_H_
|
||||||
|
#define TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_CONFIGURATION_PROTO_TO_FLATBUFFER_H_
|
||||||
|
|
||||||
|
#include "flatbuffers/idl.h" // from @flatbuffers
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/configuration.pb.h"
|
||||||
|
#include "tensorflow/lite/experimental/acceleration/configuration/configuration_generated.h"
|
||||||
|
|
||||||
|
namespace tflite {
|
||||||
|
|
||||||
|
// Converts the protobuf version ComputeSettings to the flatbuffer version, via
|
||||||
|
// json. The parser is used for state - the returned pointer is valid only as
|
||||||
|
// long as the parser is kept alive and unmutated.
|
||||||
|
const ComputeSettings* ConvertFromProto(
|
||||||
|
flatbuffers::Parser* parser, const proto::ComputeSettings& proto_settings);
|
||||||
|
|
||||||
|
} // namespace tflite
|
||||||
|
|
||||||
|
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ACCELERATION_CONFIGURATION_PROTO_TO_FLATBUFFER_H_
|
Loading…
Reference in New Issue