chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+892
View File
@@ -0,0 +1,892 @@
#
# 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
#
# https://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.
# Builds the Tensorflow Lite runtime.
#
# WARNING: This is an experimental that is subject to change.
# This has only been tested on Windows, Linux and macOS.
#
# The following are not currently supported:
# - iOS
# - Micro backend
# - Tests
# - Many features in experimental
# - Host Tools (i.e conversion / analysis tools etc.)
cmake_minimum_required(VERSION 3.16)
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "Setting build type to Release, for debug builds use"
"'-DCMAKE_BUILD_TYPE=Debug'.")
set(CMAKE_BUILD_TYPE "Release")
endif()
# Double colon in target name means ALIAS or IMPORTED target.
cmake_policy(SET CMP0028 NEW)
# Enable MACOSX_RPATH (@rpath) for built dynamic libraries.
cmake_policy(SET CMP0042 NEW)
project(tensorflow-lite C CXX)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Use FetchContent to download TensorFlow if not provided
include(FetchContent)
set(TENSORFLOW_SOURCE_DIR "" CACHE PATH
"Directory that contains the TensorFlow project"
)
if(NOT TENSORFLOW_SOURCE_DIR)
message(STATUS "Downloading TensorFlow repository...")
FetchContent_Declare(
tensorflow
GIT_REPOSITORY https://github.com/tensorflow/tensorflow.git
# v2.21.0-rc0 has updated schema_generated.h file.
GIT_TAG v2.21.0-rc0
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/tensorflow-src
)
FetchContent_GetProperties(tensorflow)
if(NOT tensorflow_POPULATED)
FetchContent_Populate(tensorflow)
endif()
set(TENSORFLOW_SOURCE_DIR "${tensorflow_SOURCE_DIR}")
endif()
set(TF_SOURCE_DIR "${TENSORFLOW_SOURCE_DIR}/tensorflow")
set(TSL_SOURCE_DIR "${TENSORFLOW_SOURCE_DIR}/third_party/xla/third_party/tsl")
set(XLA_SOURCE_DIR "${TENSORFLOW_SOURCE_DIR}/third_party/xla/")
set(TFLITE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}")
set(CMAKE_MODULE_PATH
"${TFLITE_SOURCE_DIR}/tools/cmake/modules"
${CMAKE_MODULE_PATH}
)
set(CMAKE_PREFIX_PATH
"${TFLITE_SOURCE_DIR}/tools/cmake/modules"
${CMAKE_PREFIX_PATH}
)
include(GNUInstallDirs)
include(CMakeDependentOption)
option(TFLITE_ENABLE_INSTALL "Enable install rule" OFF)
option(TFLITE_ENABLE_LABEL_IMAGE "Enable label_image example" OFF)
option(TFLITE_ENABLE_BENCHMARK_MODEL "Enable the benchmark_model tool" OFF)
option(TFLITE_ENABLE_RUY "Enable experimental RUY integration" OFF)
option(TFLITE_ENABLE_RESOURCE "Enable experimental support for resources" ON)
option(TFLITE_ENABLE_NNAPI "Enable NNAPI (Android only)." ON)
cmake_dependent_option(TFLITE_ENABLE_NNAPI_VERBOSE_VALIDATION "Enable NNAPI verbose validation." OFF
"TFLITE_ENABLE_NNAPI" ON)
option(TFLITE_ENABLE_MMAP "Enable MMAP (unsupported on Windows)" ON)
option(TFLITE_ENABLE_GPU "Enable GPU" OFF)
option(TFLITE_ENABLE_METAL "Enable Metal delegate (iOS only)" OFF)
option(TFLITE_ENABLE_XNNPACK "Enable XNNPACK backend" ON)
option(TFLITE_ENABLE_EXTERNAL_DELEGATE "Enable External Delegate backend" ON)
option(TFLITE_KERNEL_TEST "Enable tflite kernel unit test" OFF)
if(${CMAKE_CROSSCOMPILING})
set(TFLITE_HOST_TOOLS_DIR "" CACHE PATH "Host tools directory")
if(TFLITE_HOST_TOOLS_DIR STREQUAL "")
message(FATAL_ERROR "When cross-compiling, some tools need to be available to run on the host (current required tools: flatc). Please specify where those binaries can be found by using -DTFLITE_HOST_TOOLS_DIR=<flatc_dir_path>.")
endif()
# Setup the host FlatBuffers compiler.
set(FLATC_PATHS
${TFLITE_HOST_TOOLS_DIR}
${TFLITE_HOST_TOOLS_DIR}/bin
${TFLITE_HOST_TOOLS_DIR}/flatbuffers-flatc/bin
)
find_program(FLATC_BIN flatc HINTS ${FLATC_PATHS})
if(${FLATC_BIN} STREQUAL "FLATC_BIN-NOTFOUND")
message(FATAL_ERROR "Host 'flatc' compiler has not been found in the following locations: ${FLATC_PATHS}")
else()
message(STATUS "Pre-built 'flatc' compiler for cross-compilation purposes found: ${FLATC_BIN}")
set(FLATBUFFERS_FLATC_EXECUTABLE "${FLATC_BIN}")
endif()
else()
set(FLATBUFFERS_FLATC_EXECUTABLE "${CMAKE_BINARY_DIR}/flatbuffers-flatc/bin/flatc")
set(FLATC_TARGET "flatbuffers-flatc")
endif()
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(_TFLITE_ENABLE_RUY "${TFLITE_ENABLE_RUY}")
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
set(_TFLITE_ENABLE_RUY ON)
endif()
set(_TFLITE_ENABLE_NNAPI "${TFLITE_ENABLE_NNAPI}")
if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
set(_TFLITE_ENABLE_NNAPI OFF)
endif()
set(_TFLITE_ENABLE_MMAP "${TFLITE_ENABLE_MMAP}")
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# See https://github.com/tensorflow/tensorflow/blob/\
# 2b96f3662bd776e277f86997659e61046b56c315/tensorflow/lite/tools/make/\
# Makefile#L157
set(_TFLITE_ENABLE_MMAP OFF)
endif()
# Simplifies inclusion of non-test sources and headers from a directory.
# SOURCE_DIR: Directory to search for files.
# SOURCES_VAR: Variable to append with all matching *.cc and *.h files.
# [FILTER expression0 .. expressionN]:
# Additional regular expressions to filter the set of matching
# files. By default, all files ending in "(_test|test_util)\\.(cc|h)" are
# removed.
# [RECURSE]: Whether to recursively search SOURCE_DIR.
macro(populate_source_vars SOURCE_DIR SOURCES_VAR)
cmake_parse_arguments(ARGS "RECURSE" "" "FILTER" ${ARGN})
if(ARGS_RECURSE)
set(GLOB_OP GLOB_RECURSE)
else()
set(GLOB_OP GLOB)
endif()
set(DEFAULT_FILE_FILTER ".*(_test|test_util)\\.(c|cc|h)$")
file(${GLOB_OP} FOUND_SOURCES "${SOURCE_DIR}/*.*")
list(FILTER FOUND_SOURCES INCLUDE REGEX ".*\\.(c|cc|h)$")
list(FILTER FOUND_SOURCES EXCLUDE REGEX "${DEFAULT_FILE_FILTER}")
foreach(FILE_FILTER ${ARGS_FILTER})
list(FILTER FOUND_SOURCES EXCLUDE REGEX "${FILE_FILTER}")
endforeach()
list(APPEND ${SOURCES_VAR} ${FOUND_SOURCES})
endmacro()
# Simplifies inclusion of non-test sources and headers from a directory
# relative to TFLITE_SOURCE_DIR. See populate_source_vars() for the
# description of arguments including and following SOURCES_VAR.
macro(populate_tflite_source_vars RELATIVE_DIR SOURCES_VAR)
populate_source_vars(
"${TFLITE_SOURCE_DIR}/${RELATIVE_DIR}" ${SOURCES_VAR} ${ARGN}
)
endmacro()
# Simplifies inclusion of non-test sources and headers from a directory
# relative to TF_SOURCE_DIR. See populate_source_vars() for the description of
# arguments including and following SOURCES_VAR.
macro(populate_tf_source_vars RELATIVE_DIR SOURCES_VAR)
populate_source_vars(
"${TF_SOURCE_DIR}/${RELATIVE_DIR}" ${SOURCES_VAR} ${ARGN}
)
endmacro()
# Make sure all repos have licenses.
set(OVERRIDABLE_FETCH_CONTENT_LICENSE_CHECK ON)
# Additional library dependencies based upon enabled features.
set(TFLITE_TARGET_DEPENDENCIES "")
# Find TensorFlow Lite dependencies.
find_package(absl REQUIRED)
find_package(Eigen3 REQUIRED)
find_package(farmhash REQUIRED)
find_package(fft2d REQUIRED)
find_package(FlatBuffers REQUIRED)
find_package(gemmlowp REQUIRED)
if (NOT CMAKE_SYSTEM_PROCESSOR OR CMAKE_SYSTEM_PROCESSOR MATCHES "x86")
find_package(NEON_2_SSE REQUIRED)
list(APPEND TFLITE_TARGET_DEPENDENCIES NEON_2_SSE::NEON_2_SSE)
endif()
find_package(cpuinfo REQUIRED) #CPUINFO is used by XNNPACK and RUY library
find_package(ml_dtypes REQUIRED)
find_package(ruy REQUIRED)
# Include TSL, which is in tensorflow/third_party
include_directories(
${TSL_SOURCE_DIR}
${XLA_SOURCE_DIR}
)
# Download necessary dependencies.
if(TFLITE_ENABLE_XNNPACK)
# pthreadpool is used by XNNPACK.
if(SYSTEM_PTHREADPOOL)
find_library(PTHREADPOOL_LIB pthreadpool REQUIRED)
elseif(NOT DEFINED PTHREADPOOL_SOURCE_DIR)
message(STATUS "Downloading pthreadpool to ${CMAKE_BINARY_DIR}/pthreadpool-source (define SYSTEM_PTHREADPOOL or PTHREADPOOL_SOURCE_DIR to avoid it)")
configure_file(cmake/DownloadPThreadPool.cmake "${CMAKE_BINARY_DIR}/pthreadpool-download/CMakeLists.txt")
execute_process(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/pthreadpool-download")
execute_process(COMMAND "${CMAKE_COMMAND}" --build .
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/pthreadpool-download")
set(PTHREADPOOL_SOURCE_DIR "${CMAKE_BINARY_DIR}/pthreadpool-source" CACHE STRING "pthreadpool source directory")
endif()
# Configure pthreadpool
if(NOT SYSTEM_PTHREADPOOL AND NOT TARGET pthreadpool)
set(PTHREADPOOL_BUILD_TESTS OFF CACHE BOOL "")
set(PTHREADPOOL_BUILD_BENCHMARKS OFF CACHE BOOL "")
set(PTHREADPOOL_ALLOW_DEPRECATED_API OFF CACHE BOOL "")
add_subdirectory(
"${PTHREADPOOL_SOURCE_DIR}"
"${CMAKE_BINARY_DIR}/pthreadpool")
endif()
list(APPEND TFLITE_TARGET_DEPENDENCIES pthreadpool)
IF(NOT DEFINED FP16_SOURCE_DIR)
MESSAGE(STATUS "Downloading FP16 to ${CMAKE_BINARY_DIR}/FP16-source (define FP16_SOURCE_DIR to avoid it)")
CONFIGURE_FILE(cmake/DownloadFP16.cmake "${CMAKE_BINARY_DIR}/FP16-download/CMakeLists.txt")
EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" -G "${CMAKE_GENERATOR}" .
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/FP16-download")
EXECUTE_PROCESS(COMMAND "${CMAKE_COMMAND}" --build .
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/FP16-download")
SET(FP16_SOURCE_DIR "${CMAKE_BINARY_DIR}/FP16-source" CACHE STRING "FP16 source directory")
ENDIF()
endif()
set(TF_TARGET_PRIVATE_OPTIONS "")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
# TensorFlow uses a heap of deprecated proto fields so surpress these
# warnings until they're fixed.
list(APPEND TF_TARGET_PRIVATE_OPTIONS "-Wno-deprecated-declarations")
endif()
# Additional compiler flags used when compiling TF Lite.
set(TFLITE_TARGET_PUBLIC_OPTIONS "-DEIGEN_NEON_GEBP_NR=4")
set(TFLITE_TARGET_PRIVATE_OPTIONS "")
set(TFLITE_TARGET_PRIVATE_DEFINITIONS "")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang$")
# TFLite uses deprecated methods in neon2sse which generates a huge number of
# warnings so surpress these until they're fixed.
list(APPEND TFLITE_TARGET_PRIVATE_OPTIONS "-Wno-deprecated-declarations")
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
# Use NOMINMAX to disable the min / max macros in windows.h as they break
# use of std::min std::max.
# Use NOGDI to ERROR macro which breaks TensorFlow logging.
# Disable mmap, which is not available on Windows.
list(APPEND TFLITE_TARGET_PRIVATE_OPTIONS "-DNOMINMAX" "-DNOGDI" "-DTFLITE_MMAP_DISABLED")
# lite/kernels/conv.cc has more than 64k sections so enable /bigobj to
# support compilation with MSVC2015.
if(MSVC)
list(APPEND TFLITE_TARGET_PRIVATE_OPTIONS "/bigobj")
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
message("Disabling MSVC /O2 optimization for Win32")
set(CompFlags
CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_RELWITHDEBINFO
CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELWITHDEBINFO
)
foreach (CompFlag ${CompFlags})
string(REGEX REPLACE "(\/Ob. )" "" ${CompFlag} "${${CompFlag}}")
string(REPLACE "/O2" "/O1" ${CompFlag} "${${CompFlag}}")
list(REMOVE_DUPLICATES ${CompFlag})
set(${CompFlag} "${${CompFlag}}" CACHE INTERNAL "")
endforeach()
endif()
list(APPEND TFLITE_TARGET_PRIVATE_DEFINITIONS "_USE_MATH_DEFINES")
elseif(CMAKE_COMPILER_IS_GNUCXX)
list(APPEND TFLITE_TARGET_PRIVATE_OPTIONS "-Wa,-mbig-obj")
endif()
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Android")
find_library(ANDROID_LOG_LIB log)
list(APPEND TFLITE_TARGET_DEPENDENCIES
log
)
endif()
# Build a list of source files to compile into the TF Lite library.
populate_tflite_source_vars("." TFLITE_SRCS)
if(CMAKE_SYSTEM_NAME MATCHES "Windows" AND BUILD_SHARED_LIBS)
list(FILTER TFLITE_SRCS EXCLUDE REGEX ".*simple_memory_arena_debug_dump\\.cc$")
endif()
# This particular file is excluded because the more explicit approach to enable
# XNNPACK delegate is preferred to the weak-symbol one.
list(FILTER TFLITE_SRCS EXCLUDE REGEX ".*tflite_with_xnnpack\\.cc$")
# Exclude Flex related files.
list(FILTER TFLITE_SRCS EXCLUDE REGEX ".*with_selected_ops\\.cc$")
# Exclude tensorflow_profiler_logger files.
list(FILTER TFLITE_SRCS EXCLUDE REGEX ".*tensorflow_profiler_logger\\.cc$")
# Handle TFLite logging source.
list(FILTER TFLITE_SRCS EXCLUDE REGEX ".*minimal_logging_.*\\.cc$")
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
list(APPEND TFLITE_SRCS ${TFLITE_SOURCE_DIR}/minimal_logging_android.cc)
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "iOS")
list(APPEND TFLITE_SRCS ${TFLITE_SOURCE_DIR}/minimal_logging_ios.cc)
else()
list(APPEND TFLITE_SRCS ${TFLITE_SOURCE_DIR}/minimal_logging_default.cc)
endif()
populate_tflite_source_vars("core" TFLITE_CORE_SRCS)
populate_tflite_source_vars(
"core/acceleration/configuration" TFLITE_CORE_ACCELERATION_SRCS
FILTER "xnnpack_plugin.*"
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars("core/api" TFLITE_CORE_API_SRCS)
populate_tflite_source_vars("core/async" TFLITE_CORE_ASYNC_SRCS)
populate_tflite_source_vars("core/async/c" TFLITE_CORE_ASYNC_C_SRCS)
populate_tflite_source_vars("core/async/interop" TFLITE_CORE_ASYNC_INTEROP_SRCS)
populate_tflite_source_vars("core/async/interop/c" TFLITE_CORE_ASYNC_INTEROP_C_SRCS)
populate_tflite_source_vars("core/c" TFLITE_CORE_C_SRCS)
populate_tflite_source_vars("core/experimental/acceleration/configuration" TFLITE_CORE_EXPERIMENTAL_SRCS)
populate_tflite_source_vars("core/kernels" TFLITE_CORE_KERNELS_SRCS)
populate_tflite_source_vars("core/tools" TFLITE_CORE_TOOLS_SRCS)
populate_tflite_source_vars("c" TFLITE_C_SRCS)
populate_tflite_source_vars("delegates" TFLITE_DELEGATES_SRCS)
if(TFLITE_ENABLE_GPU)
find_package(opencl_headers REQUIRED)
find_package(vulkan_headers REQUIRED)
find_package(fp16_headers REQUIRED)
# Android NDK already has OpenGL, EGL headers.
if(NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "Android")
find_package(opengl_headers REQUIRED)
find_package(egl_headers REQUIRED)
endif()
populate_tflite_source_vars(
"delegates/gpu/cl" TFLITE_DELEGATES_GPU_CL_SRCS
FILTER "(_test|gl_interop|gpu_api_delegate|egl_sync)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/cl/default" TFLITE_DELEGATES_GPU_CL_DEFAULT_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/cl/kernels" TFLITE_DELEGATES_GPU_CL_KERNELS_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/common/default" TFLITE_DELEGATES_GPU_COMMON_DEFAULT_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/common/memory_management"
TFLITE_DELEGATES_GPU_COMMON_MEMORY_MANAGEMENT_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/common/selectors" TFLITE_DELEGATES_GPU_COMMON_SELECTORS_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/common/selectors/default" TFLITE_DELEGATES_GPU_COMMON_SELECTORS_DEFAULT_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/common" TFLITE_DELEGATES_GPU_COMMON_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/common/task"
TFLITE_DELEGATES_GPU_COMMON_TASK_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/common/tasks"
TFLITE_DELEGATES_GPU_COMMON_TASKS_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/common/tasks/special"
TFLITE_DELEGATES_GPU_COMMON_TASKS_SPECIAL_SRCS
FILTER "(_test)\\.(cc|h)$"
)
populate_tflite_source_vars(
"delegates/gpu/common/transformations"
TFLITE_DELEGATES_GPU_COMMON_TRANSFORMATIONS_SRCS
FILTER "(_test)\\.(cc|h)$"
)
list(APPEND TFLITE_DELEGATES_GPU_SRCS
${TFLITE_SOURCE_DIR}/delegates/gpu/api.cc
${TFLITE_SOURCE_DIR}/delegates/gpu/delegate.cc
${TFLITE_SOURCE_DIR}/delegates/gpu/delegate.h
${TFLITE_SOURCE_DIR}/delegates/gpu/delegate_options.cc
${TFLITE_SOURCE_DIR}/delegates/gpu/delegate_options.h
${TFLITE_SOURCE_DIR}/delegates/gpu/tflite_profile.cc
${TFLITE_SOURCE_DIR}/experimental/acceleration/compatibility/android_info.cc
${TFLITE_DELEGATES_GPU_CL_SRCS}
${TFLITE_DELEGATES_GPU_CL_DEFAULT_SRCS}
${TFLITE_DELEGATES_GPU_CL_KERNELS_SRCS}
${TFLITE_DELEGATES_GPU_COMMON_DEFAULT_SRCS}
${TFLITE_DELEGATES_GPU_COMMON_MEMORY_MANAGEMENT_SRCS}
${TFLITE_DELEGATES_GPU_COMMON_SELECTORS_SRCS}
${TFLITE_DELEGATES_GPU_COMMON_SELECTORS_DEFAULT_SRCS}
${TFLITE_DELEGATES_GPU_COMMON_SRCS}
${TFLITE_DELEGATES_GPU_COMMON_TASK_SRCS}
${TFLITE_DELEGATES_GPU_COMMON_TASKS_SRCS}
${TFLITE_DELEGATES_GPU_COMMON_TASKS_SPECIAL_SRCS}
${TFLITE_DELEGATES_GPU_COMMON_TRANSFORMATIONS_SRCS}
${TFLITE_SOURCE_DIR}/tools/versioning/gpu_compatibility.cc
${TFLITE_SOURCE_DIR}/tools/versioning/op_signature.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/tools/versioning/op_signature.cc
)
include_directories(
AFTER
${TFLITE_SOURCE_DIR}/delegates/gpu/common
${TFLITE_SOURCE_DIR}/delegates/gpu/common/task
)
if(TFLITE_ENABLE_METAL AND "${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
#
# libmetal_delegate library
#
enable_language(OBJCXX)
list(APPEND TFLITE_DELEGATES_METAL_SRCS
${TFLITE_SOURCE_DIR}/delegates/gpu/metal_delegate.mm
${TFLITE_SOURCE_DIR}/delegates/gpu/metal/buffer.cc
${TFLITE_SOURCE_DIR}/delegates/gpu/metal/buffer_convert.mm
${TFLITE_SOURCE_DIR}/delegates/gpu/metal/common.mm
${TFLITE_SOURCE_DIR}/delegates/gpu/metal/compute_task.cc
${TFLITE_SOURCE_DIR}/delegates/gpu/metal/inference_context.cc
${TFLITE_SOURCE_DIR}/delegates/gpu/metal/metal_arguments.cc
${TFLITE_SOURCE_DIR}/delegates/gpu/metal/metal_device.cc
${TFLITE_SOURCE_DIR}/delegates/gpu/metal/metal_spatial_tensor.cc
)
add_library(metal_delegate STATIC
${TFLITE_DELEGATES_METAL_SRCS}
)
target_include_directories(metal_delegate PUBLIC
${CMAKE_BINARY_DIR}/abseil-cpp
${CMAKE_BINARY_DIR}/flatbuffers/include
PRIVATE ${TENSORFLOW_SOURCE_DIR}
)
#
# generate flatbuffers header for inference_context
#
if(FLATBUFFERS_FLATC_EXECUTABLE)
set(FLATC ${FLATBUFFERS_FLATC_EXECUTABLE})
else()
set(FLATC flatc)
endif()
add_custom_command(
OUTPUT ${TFLITE_SOURCE_DIR}/delegates/gpu/metal/inference_context_generated.h
COMMAND ${FLATC} --scoped-enums
-I ${TENSORFLOW_SOURCE_DIR}
-o ${TFLITE_SOURCE_DIR}/delegates/gpu/metal
-c ${TFLITE_SOURCE_DIR}/delegates/gpu/metal/inference_context.fbs
)
add_custom_target(
inference_context_cc_fbs
DEPENDS ${TFLITE_SOURCE_DIR}/delegates/gpu/metal/inference_context_generated.h
)
add_dependencies(metal_delegate inference_context_cc_fbs)
#
# supplementary libraries for libmetal_delegate
#
list(APPEND CC_SRCS
buffer
compute_task
inference_context
metal_arguments
metal_device
metal_spatial_tensor
)
SET(METAL_DELEGATE_PATH ${TFLITE_SOURCE_DIR}/delegates/gpu/metal/)
foreach(lib_name ${CC_SRCS})
set_source_files_properties(${METAL_DELEGATE_PATH}${lib_name}.cc PROPERTIES LANGUAGE OBJCXX)
add_library("${lib_name}" STATIC ${METAL_DELEGATE_PATH}${lib_name}.cc)
target_include_directories("${lib_name}" PUBLIC
${CMAKE_BINARY_DIR}/abseil-cpp
${CMAKE_BINARY_DIR}/flatbuffers/include
)
set_target_properties(${lib_name} PROPERTIES LINKER_LANGUAGE OBJCXX)
target_link_libraries(${lib_name})
endforeach()
list(APPEND MM_SRCS
buffer_convert
common
)
foreach(lib_name ${MM_SRCS})
add_library("${lib_name}" STATIC ${METAL_DELEGATE_PATH}${lib_name}.mm)
target_include_directories("${lib_name}" PUBLIC
${CMAKE_BINARY_DIR}/abseil-cpp
${CMAKE_BINARY_DIR}/flatbuffers/include
)
target_link_libraries(${lib_name})
endforeach()
endif()
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DCL_DELEGATE_NO_GL" "-DEGL_NO_X11")
list(APPEND TFLITE_TARGET_DEPENDENCIES
absl::any
absl::flat_hash_map
)
endif()
if(_TFLITE_ENABLE_NNAPI)
find_package(fp16_headers REQUIRED)
populate_tflite_source_vars("delegates/nnapi"
TFLITE_DELEGATES_NNAPI_SRCS
FILTER "(_test_list|_disabled)\\.(cc|h)$"
)
populate_tflite_source_vars(
"nnapi" TFLITE_NNAPI_SRCS FILTER "(_disabled)\\.(cc|h)$"
)
list(APPEND TFLITE_NNAPI_SRCS
"${TFLITE_SOURCE_DIR}/nnapi/sl/SupportLibrary.cc"
)
if(${TFLITE_ENABLE_NNAPI_VERBOSE_VALIDATION})
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DNNAPI_VERBOSE_VALIDATION")
endif()
else()
set(TFLITE_DELEGATES_NNAPI_SRCS
"${TFLITE_SOURCE_DIR}/delegates/nnapi/nnapi_delegate_disabled.cc"
)
set(TFLITE_NNAPI_SRCS
"${TFLITE_SOURCE_DIR}/nnapi/nnapi_implementation_disabled.cc"
)
endif()
if(TFLITE_ENABLE_XNNPACK)
find_package(fp16_headers REQUIRED)
find_package(XNNPACK REQUIRED)
set(XNNPACK_NEON_2_SSE "")
if (NOT CMAKE_SYSTEM_PROCESSOR OR CMAKE_SYSTEM_PROCESSOR MATCHES "x86")
find_package(NEON_2_SSE REQUIRED)
list(APPEND XNNPACK_NEON_2_SSE NEON_2_SSE::NEON_2_SSE)
endif()
populate_tflite_source_vars("delegates/xnnpack"
TFLITE_DELEGATES_XNNPACK_SRCS
FILTER ".*(_test|_tester)\\.(cc|h)"
)
add_custom_command(
OUTPUT "${PROJECT_BINARY_DIR}/tensorflow/lite/delegates/xnnpack/weight_cache_schema_generated.h"
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c
-o "${PROJECT_BINARY_DIR}/tensorflow/lite/delegates/xnnpack/"
--gen-mutable --gen-object-api
"${TFLITE_SOURCE_DIR}/delegates/xnnpack/weight_cache_schema.fbs"
COMMAND ${CMAKE_COMMAND} -E make_directory "${PROJECT_BINARY_DIR}/tflite/delegates/xnnpack"
COMMAND ${CMAKE_COMMAND} -E copy
"${PROJECT_BINARY_DIR}/tensorflow/lite/delegates/xnnpack/weight_cache_schema_generated.h"
"${PROJECT_BINARY_DIR}/tflite/delegates/xnnpack/weight_cache_schema_generated.h"
DEPENDS "${FLATC_TARGET}" "${TFLITE_SOURCE_DIR}/delegates/xnnpack/weight_cache_schema.fbs"
)
add_custom_target(
xnnpack_weight_cache_schema_cc_fbs
DEPENDS "${PROJECT_BINARY_DIR}/tensorflow/lite/delegates/xnnpack/weight_cache_schema_generated.h"
)
add_library(xnnpack-delegate STATIC
"${TFLITE_DELEGATES_XNNPACK_SRCS}"
"${PROJECT_BINARY_DIR}/tensorflow/lite/delegates/xnnpack/weight_cache_schema_generated.h"
)
target_include_directories(xnnpack-delegate
PUBLIC $<BUILD_INTERFACE:${TENSORFLOW_SOURCE_DIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE "${PROJECT_BINARY_DIR}"
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/.."
PRIVATE "${PROJECT_BINARY_DIR}/tensorflow"
PRIVATE "${CMAKE_CURRENT_BINARY_DIR}"
PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/tflite"
)
add_dependencies(xnnpack-delegate xnnpack_weight_cache_schema_cc_fbs)
target_link_libraries(xnnpack-delegate
Eigen3::Eigen
absl::span
flatbuffers::flatbuffers
gemmlowp::gemmlowp
ruy::ruy
${XNNPACK_NEON_2_SSE}
)
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DTFLITE_KERNEL_USE_XNNPACK")
list(APPEND TFLITE_TARGET_DEPENDENCIES
xnnpack-delegate
XNNPACK
)
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DTFLITE_BUILD_WITH_XNNPACK_DELEGATE")
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DXNNPACK_DELEGATE_ENABLE_QS8")
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DXNNPACK_DELEGATE_ENABLE_QU8")
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DXNNPACK_DELEGATE_USE_LATEST_OPS")
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DXNNPACK_DELEGATE_ENABLE_SUBGRAPH_RESHAPING")
endif()
if(TFLITE_ENABLE_EXTERNAL_DELEGATE)
populate_tflite_source_vars("delegates/external"
TFLITE_DELEGATES_EXTERNAL_SRCS
FILTER ".*(_test|_tester)\\.(cc|h)"
)
endif()
populate_tflite_source_vars("experimental/remat"
TFLITE_EXPERIMENTAL_REMAT_SRCS
FILTER ".*_test\\.(cc|h)$"
)
if (TFLITE_ENABLE_RESOURCE)
populate_tflite_source_vars("experimental/resource"
TFLITE_EXPERIMENTAL_RESOURCE_SRCS
)
endif()
populate_tflite_source_vars("experimental/ruy"
TFLITE_EXPERIMENTAL_RUY_SRCS
FILTER
".*(test(_fast|_slow|_special_specs))\\.(cc|h)$"
".*(benchmark|tune_tool|example)\\.(cc|h)$"
)
populate_tflite_source_vars("experimental/ruy/profiler"
TFLITE_EXPERIMENTAL_RUY_PROFILER_SRCS
FILTER ".*(test|test_instrumented_library)\\.(cc|h)$"
)
if(_TFLITE_ENABLE_RUY)
message(STATUS "RUY is enabled.")
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DTFLITE_WITH_RUY")
endif()
populate_tflite_source_vars("kernels"
TFLITE_KERNEL_SRCS
FILTER "([^/]*_test_util_internal|test_[^/]*|[^/]*_ops_wrapper)\\.(cc|h)$"
)
populate_tflite_source_vars("kernels/internal" TFLITE_KERNEL_INTERNAL_SRCS)
populate_tflite_source_vars("kernels/internal/optimized"
TFLITE_KERNEL_INTERNAL_OPT_SRCS
)
populate_tflite_source_vars("kernels/internal/optimized/integer_ops"
TFLITE_KERNEL_INTERNAL_OPT_INTEGER_OPS_SRCS
)
populate_tflite_source_vars("kernels/internal/optimized/sparse_ops"
TFLITE_KERNEL_INTERNAL_OPT_SPARSE_OPS_SRCS
)
populate_tflite_source_vars("kernels/internal/reference"
TFLITE_KERNEL_INTERNAL_REF_SRCS
)
populate_tflite_source_vars("kernels/internal/reference/integer_ops"
TFLITE_KERNEL_INTERNAL_REF_INTEGER_OPS_SRCS
)
populate_tflite_source_vars("kernels/internal/reference/sparse_ops"
TFLITE_KERNEL_INTERNAL_REF_SPARSE_OPS_SRCS
)
populate_tflite_source_vars("kernels/internal/optimized/4bit"
TFLITE_KERNEL_INTERNAL_OPT_4BIT_SRCS
FILTER "(.*neon_.*|.*sse_.*)\\.(cc|h)"
)
set(TFLITE_PROFILER_SRCS
${TFLITE_SOURCE_DIR}/profiling/platform_profiler.cc
${TFLITE_SOURCE_DIR}/profiling/root_profiler.h
${TFLITE_SOURCE_DIR}/profiling/root_profiler.cc
${TFLITE_SOURCE_DIR}/profiling/telemetry/profiler.cc
${TFLITE_SOURCE_DIR}/profiling/telemetry/profiler.h
${TFLITE_SOURCE_DIR}/profiling/telemetry/telemetry.cc
${TFLITE_SOURCE_DIR}/profiling/telemetry/c/telemetry_setting_internal.cc
${TFLITE_SOURCE_DIR}/profiling/telemetry/c/telemetry_setting_internal.h
${TFLITE_SOURCE_DIR}/profiling/telemetry/c/profiler.h
${TFLITE_SOURCE_DIR}/profiling/telemetry/c/telemetry_setting.h
${TFLITE_SOURCE_DIR}/profiling/telemetry/telemetry_status.h
)
if(CMAKE_SYSTEM_NAME MATCHES "Android")
list(APPEND TFLITE_PROFILER_SRCS
${TFLITE_SOURCE_DIR}/profiling/atrace_profiler.cc
)
elseif(CMAKE_SYSTEM_NAME MATCHES "iOS")
enable_language(OBJCXX)
list(APPEND TFLITE_PROFILER_SRCS
${TFLITE_SOURCE_DIR}/profiling/signpost_profiler.mm
)
set_source_files_properties(${TFLITE_SOURCE_DIR}/profiling/signpost_profiler.mm PROPERTIES COMPILE_FLAGS -fno-objc-arc)
endif()
# TFLite library
set(_ALL_TFLITE_SRCS
# go/keep-sorted start
${TFLITE_CORE_ACCELERATION_SRCS}
${TFLITE_CORE_API_SRCS}
${TFLITE_CORE_ASYNC_C_SRCS}
${TFLITE_CORE_ASYNC_INTEROP_C_SRCS}
${TFLITE_CORE_ASYNC_INTEROP_SRCS}
${TFLITE_CORE_ASYNC_SRCS}
${TFLITE_CORE_C_SRCS}
${TFLITE_CORE_EXPERIMENTAL_SRCS}
${TFLITE_CORE_KERNELS_SRCS}
${TFLITE_CORE_SRCS}
${TFLITE_CORE_TOOLS_SRCS}
${TFLITE_C_SRCS}
${TFLITE_DELEGATES_EXTERNAL_SRCS}
${TFLITE_DELEGATES_FLEX_SRCS}
${TFLITE_DELEGATES_GPU_SRCS}
${TFLITE_DELEGATES_NNAPI_SRCS}
${TFLITE_DELEGATES_SRCS}
${TFLITE_EXPERIMENTAL_REMAT_SRCS}
${TFLITE_EXPERIMENTAL_RESOURCE_SRCS}
${TFLITE_EXPERIMENTAL_RUY_PROFILER_SRCS}
${TFLITE_EXPERIMENTAL_RUY_SRCS}
${TFLITE_KERNEL_INTERNAL_OPT_4BIT_SRCS}
${TFLITE_KERNEL_INTERNAL_OPT_INTEGER_OPS_SRCS}
${TFLITE_KERNEL_INTERNAL_OPT_SPARSE_OPS_SRCS}
${TFLITE_KERNEL_INTERNAL_OPT_SRCS}
${TFLITE_KERNEL_INTERNAL_REF_INTEGER_OPS_SRCS}
${TFLITE_KERNEL_INTERNAL_REF_SPARSE_OPS_SRCS}
${TFLITE_KERNEL_INTERNAL_REF_SRCS}
${TFLITE_KERNEL_INTERNAL_SRCS}
${TFLITE_KERNEL_SRCS}
${TFLITE_NNAPI_SRCS}
${TFLITE_PROFILER_SRCS}
${TFLITE_SOURCE_DIR}/internal/signature_def.h
${TFLITE_SOURCE_DIR}/kernels/internal/utils/sparsity_format_converter.cc
${TFLITE_SOURCE_DIR}/schema/conversion_metadata_generated.h
${TFLITE_SOURCE_DIR}/schema/schema_generated.h
${TFLITE_SRCS}
${TF_SOURCE_DIR}/compiler/mlir/lite/allocation.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/allocation.h
${TF_SOURCE_DIR}/compiler/mlir/lite/core/api/error_reporter.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/core/api/error_reporter.h
${TF_SOURCE_DIR}/compiler/mlir/lite/core/api/flatbuffer_conversions.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/core/api/verifier.h
${TF_SOURCE_DIR}/compiler/mlir/lite/core/c/tflite_types.h
${TF_SOURCE_DIR}/compiler/mlir/lite/core/macros.h
${TF_SOURCE_DIR}/compiler/mlir/lite/core/model_builder_base.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/core/model_builder_base.h
${TF_SOURCE_DIR}/compiler/mlir/lite/experimental/remat/metadata_util.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/experimental/remat/metadata_util.h
${TF_SOURCE_DIR}/compiler/mlir/lite/mmap_allocation.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/mmap_allocation_disabled.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/schema/conversion_metadata_generated.h
${TF_SOURCE_DIR}/compiler/mlir/lite/schema/schema_generated.h
${TF_SOURCE_DIR}/compiler/mlir/lite/schema/schema_utils.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/utils/control_edges.h
${TF_SOURCE_DIR}/compiler/mlir/lite/utils/string_utils.cc
${TF_SOURCE_DIR}/compiler/mlir/lite/utils/string_utils.h
# go/keep-sorted end
)
if(_TFLITE_ENABLE_MMAP)
list(FILTER _ALL_TFLITE_SRCS EXCLUDE REGEX ".*mmap_allocation_disabled\\.cc$")
else()
list(FILTER _ALL_TFLITE_SRCS EXCLUDE REGEX ".*mmap_allocation\\.cc$")
endif()
add_library(tensorflow-lite
${_ALL_TFLITE_SRCS}
)
set(_ALL_TFLITE_HDRS ${_ALL_TFLITE_SRCS})
list(FILTER _ALL_TFLITE_HDRS INCLUDE REGEX ".*\\.h$")
target_include_directories(tensorflow-lite
PUBLIC
$<BUILD_INTERFACE:${TENSORFLOW_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>
)
target_link_libraries(tensorflow-lite
PUBLIC
Eigen3::Eigen
absl::flags
absl::hash
absl::span
absl::status
absl::strings
absl::synchronization
absl::variant
farmhash
fft2d_fftsg2d
flatbuffers::flatbuffers
gemmlowp::gemmlowp
ml_dtypes
ruy::ruy
${CMAKE_DL_LIBS}
${TFLITE_TARGET_DEPENDENCIES}
)
if (NOT BUILD_SHARED_LIBS)
list(APPEND TFLITE_TARGET_PUBLIC_OPTIONS "-DTFL_STATIC_LIBRARY_BUILD")
endif()
target_compile_options(tensorflow-lite
PUBLIC ${TFLITE_TARGET_PUBLIC_OPTIONS}
PRIVATE ${TFLITE_TARGET_PRIVATE_OPTIONS}
)
target_compile_definitions(tensorflow-lite
PRIVATE
TF_MAJOR_VERSION=2
TF_MINOR_VERSION=19
TF_PATCH_VERSION=0
TF_VERSION_SUFFIX=""
)
add_library(${PROJECT_NAME}::tensorflowlite ALIAS tensorflow-lite)
# The install targets.
if(TFLITE_ENABLE_INSTALL)
install(
TARGETS tensorflow-lite
EXPORT ${PROJECT_NAME}Targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
foreach(hdr ${_ALL_TFLITE_HDRS})
get_filename_component(dir ${hdr} DIRECTORY)
file(RELATIVE_PATH dir ${CMAKE_CURRENT_SOURCE_DIR} ${dir})
install(
FILES ${hdr}
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/tensorflow/lite/${dir}"
)
endforeach()
install(
EXPORT ${PROJECT_NAME}Targets
NAMESPACE ${PROJECT_NAME}::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
# Generate config file that's used by find_package(tensorflow-lite CONFIG).
include(CMakePackageConfigHelpers)
configure_package_config_file(
"tools/cmake/${PROJECT_NAME}Config.cmake.in"
"${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
install(FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
endif()
# The kernel tests.
if(TFLITE_KERNEL_TEST)
enable_testing()
add_subdirectory(${TFLITE_SOURCE_DIR}/kernels)
endif()
# Add the generated headers directory. Required for maintaining the
# tensorflow/lite directory structure for generated headers.
set(TFLITE_GENERATED_HEADERS_DIR ${CMAKE_BINARY_DIR}/tensorflow/lite)
# Add the profiling proto directory.
add_subdirectory(${TFLITE_SOURCE_DIR}/profiling/proto)
# Add the benchmark result proto directory.
add_subdirectory(${TFLITE_SOURCE_DIR}/tools/benchmark/proto)
# Add the tf example directory.
add_subdirectory(${TF_SOURCE_DIR}/core/example ${CMAKE_BINARY_DIR}/example_proto_generated)
# The benchmark tool.
add_subdirectory(${TFLITE_SOURCE_DIR}/tools/benchmark)
# The label_image example.
add_subdirectory(${TFLITE_SOURCE_DIR}/examples/label_image)
# Python interpreter wrapper.
add_library(_pywrap_tensorflow_interpreter_wrapper SHARED EXCLUDE_FROM_ALL
${TFLITE_SOURCE_DIR}/python/interpreter_wrapper/interpreter_wrapper.cc
${TFLITE_SOURCE_DIR}/python/interpreter_wrapper/interpreter_wrapper_pybind11.cc
${TFLITE_SOURCE_DIR}/python/interpreter_wrapper/numpy.cc
${TFLITE_SOURCE_DIR}/python/interpreter_wrapper/python_error_reporter.cc
${TFLITE_SOURCE_DIR}/python/interpreter_wrapper/python_utils.cc
)
# To remove "lib" prefix.
set_target_properties(_pywrap_tensorflow_interpreter_wrapper PROPERTIES PREFIX "")
target_include_directories(_pywrap_tensorflow_interpreter_wrapper
PUBLIC
${TENSORFLOW_SOURCE_DIR}
)
target_link_libraries(_pywrap_tensorflow_interpreter_wrapper
tensorflow-lite
${CMAKE_DL_LIBS}
)
target_compile_options(_pywrap_tensorflow_interpreter_wrapper
PUBLIC ${TFLITE_TARGET_PUBLIC_OPTIONS}
PRIVATE ${TFLITE_TARGET_PRIVATE_OPTIONS}
)
if(TFLITE_ENABLE_XNNPACK)
target_compile_options(xnnpack-delegate
PUBLIC ${TFLITE_TARGET_PUBLIC_OPTIONS}
PRIVATE ${TFLITE_TARGET_PRIVATE_OPTIONS}
)
endif()
+9
View File
@@ -0,0 +1,9 @@
# TensorFlow Lite
TensorFlow Lite is TensorFlow's lightweight solution for mobile and embedded
devices. It enables low-latency inference of on-device machine learning models
with a small binary size and fast performance supporting hardware acceleration.
- See the documentation: https://www.tensorflow.org/lite/
- Documentation edits can be made here: [tensorflow/lite/g3doc](./g3doc/)
@@ -0,0 +1,436 @@
# 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.
# ==============================================================================
# buildifier: disable=out-of-order-load
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_shell//shell:sh_test.bzl", "sh_test")
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")
load("@com_google_protobuf//bazel:java_lite_proto_library.bzl", "java_lite_proto_library")
load("@flatbuffers//:build_defs.bzl", "DEFAULT_FLATC_ARGS", "flatbuffer_android_library", "flatbuffer_cc_library", "flatbuffer_java_library", "flatc_path")
load("//tensorflow:tensorflow.default.bzl", "get_compatible_with_portable")
load("//tensorflow/lite:build_def.bzl", "tflite_copts", "tflite_copts_warnings")
load("//tensorflow/lite:special_rules.bzl", "tflite_portable_test_suite")
load("//tensorflow/lite/core/shims:cc_library_with_tflite.bzl", "cc_library_with_tflite", "cc_test_with_tflite")
# copybara:uncomment load("//tools/build_defs/proto/cpp:cc_proto_library.bzl", "cc_proto_library")
load(":build_defs.bzl", "flatbuffer_schema_compat_test")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//visibility:public",
],
licenses = ["notice"],
)
# We generate a FlatBuffer schema from the Protobuf schema.
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/' $@
""".format(flatc_path),
compatible_with = get_compatible_with_portable(),
tools = [flatc_path],
)
# We also do the same transformation for the _previous_
# version of the schema -- this is used to test that changes
# to the schema preserve binary backwards compatibility.
genrule(
name = "configuration_prev_schema",
srcs = ["testdata/configuration.proto_prev"], # Must NOT end in '.proto'.
outs = ["configuration.prev.fbs"], # MUST end in '.fbs'.
# We rename the namespace since otherwise the proto classes and flatbuffer
# classes would have the same names.
cmd = """
cp $(location :testdata/configuration.proto_prev) $(@D)/configuration.prev.proto
$(location {}) --proto -o $(@D) $(@D)/configuration.prev.proto
perl -p -i -e 's/tflite.proto/tflite/' $@
""".format(flatc_path),
compatible_with = get_compatible_with_portable(),
tools = [flatc_path],
)
# Test that changes to the proto file preserve binary backwards compatibility
# of the generated FlatBuffer schema, relative to the one generated from the
# previous proto file.
flatbuffer_schema_compat_test(
name = "configuration_abi_stability_test",
ref_schema = ":configuration.prev.fbs",
schema = ":configuration.fbs",
)
# Test that changes to the proto file OR to the FlatBuffer proto-to-flatbuffer
# schema conversion itself will preserve binary backwards compatibility of the
# generated FlatBuffer schema, relative to an older snapshot of the
# generated FlatBuffer schema.
flatbuffer_schema_compat_test(
name = "configuration_flatbuffer_abi_stability_test",
ref_schema = "testdata/configuration.old.fbs",
schema = ":configuration.fbs",
)
# Test that the previous version of the proto is different than the current version.
sh_test(
name = "prev_is_different_than_current_test",
srcs = ["prev_is_different_than_current_test.sh"],
data = [
"configuration.proto",
"testdata/configuration.proto_prev",
],
)
# Generate a C++ header containing the contents of the FlatBuffer schema
# as a char array literal. This is potentially useful for embedding in programs
# (e.g. for JSON parsing using that schema).
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";' >> $(@)
""",
)
exports_files(["configuration.proto"])
proto_library(
name = "configuration_proto",
srcs = [
"configuration.proto",
],
compatible_with = get_compatible_with_portable(),
)
cc_proto_library(
name = "configuration_cc_proto",
compatible_with = get_compatible_with_portable(),
deps = [":configuration_proto"],
)
java_lite_proto_library(
name = "configuration_java_proto_lite",
deps = [":configuration_proto"],
)
flatbuffer_cc_library(
name = "configuration_fbs",
srcs = [":configuration.fbs"],
compatible_with = get_compatible_with_portable(),
flatc_args = DEFAULT_FLATC_ARGS + ["--gen-compare"],
)
flatbuffer_java_library(
name = "configuration_fbs_java",
srcs = [":configuration.fbs"],
)
flatbuffer_android_library(
name = "configuration_fbs_android",
srcs = [":configuration.fbs"],
)
cc_library(
name = "proto_to_flatbuffer",
srcs = [
"proto_to_flatbuffer.cc",
],
hdrs = ["proto_to_flatbuffer.h"],
deps = [
":configuration_cc_proto",
":configuration_fbs",
"//tensorflow/lite:minimal_logging",
"@flatbuffers",
],
)
cc_test(
name = "proto_to_flatbuffer_test",
srcs = ["proto_to_flatbuffer_test.cc"],
deps = [
":configuration_cc_proto",
":proto_to_flatbuffer",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "flatbuffer_to_proto",
srcs = [
"flatbuffer_to_proto.cc",
],
hdrs = ["flatbuffer_to_proto.h"],
compatible_with = get_compatible_with_portable(),
deps = [
":configuration_cc_proto",
":configuration_fbs",
"//tensorflow/lite:minimal_logging",
"@flatbuffers",
],
)
cc_test(
name = "flatbuffer_to_proto_test",
srcs = ["flatbuffer_to_proto_test.cc"],
deps = [
":configuration_cc_proto",
":configuration_fbs",
":flatbuffer_to_proto",
"@com_google_googletest//:gtest_main",
],
)
cc_library_with_tflite(
name = "delegate_registry",
hdrs = ["delegate_registry.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts_warnings(),
deps = [
":configuration_fbs",
"//tensorflow/lite/core/acceleration/configuration:delegate_registry",
"//tensorflow/lite/core/c:common",
"@com_google_absl//absl/synchronization",
],
)
cc_library_with_tflite(
name = "delegate_plugin_converter",
srcs = ["delegate_plugin_converter.cc"],
hdrs = ["delegate_plugin_converter.h"],
tflite_deps = [
"//tensorflow/lite/acceleration/configuration/c:delegate_plugin",
"//tensorflow/lite/acceleration/configuration:delegate_registry",
"//tensorflow/lite/c:common",
],
deps = ["@com_google_absl//absl/memory"],
)
cc_library_with_tflite(
name = "nnapi_plugin",
compatible_with = get_compatible_with_portable(),
deps = ["//tensorflow/lite/core/acceleration/configuration:nnapi_plugin"],
)
# Commented under b/279852433 because caused an error in the OSS
# TODO(zhurakovskyi): Uncomment when fixed.
# copybara:uncomment_begin
# cc_library(
# name = "hexagon_plugin",
# srcs = ["hexagon_plugin.cc"],
# deps = [
# ":configuration_fbs",
# "@com_google_absl//absl/memory",
# "//tensorflow/lite/core/acceleration/configuration:delegate_registry",
# ] + select({
# "//third_party/bazel_platforms/cpu:aarch64": [
# "//tensorflow/lite/delegates/hexagon:hexagon_delegate",
# ],
# "//third_party/bazel_platforms/cpu:armv7": [
# "//tensorflow/lite/delegates/hexagon:hexagon_delegate",
# ],
# "//conditions:default": [],
# }),
# alwayslink = 1, # For registration to always run.
# )
# copybara:uncomment_end
cc_library(
name = "gpu_plugin",
deps = [
":gpu_plugin_impl",
],
)
common_copts = tflite_copts() + tflite_copts_warnings()
cc_library(
name = "gpu_plugin_impl",
srcs = ["gpu_plugin.cc"],
hdrs = ["gpu_plugin.h"],
copts = common_copts + select({
"//tensorflow:ios": [
"-xobjective-c++",
],
"//tensorflow:macos_arm64": [
"-xobjective-c++",
],
"//conditions:default": [],
}),
visibility = [
"//tensorflow/lite/core/acceleration/configuration/c:__pkg__",
"//tensorflow/lite/experimental/acceleration/configuration:__pkg__",
],
deps = [
":configuration_fbs",
"//tensorflow/lite/core/acceleration/configuration:delegate_registry",
"@com_google_absl//absl/memory",
] + select({
"//tensorflow/lite/delegates/gpu:supports_gpu_delegate": [
"//tensorflow/lite/delegates/gpu:delegate",
],
"//conditions:default": [],
}) + select({
"//tensorflow:ios": [
"//tensorflow/lite/delegates/gpu:metal_delegate",
],
"//tensorflow:macos_arm64": [
"//tensorflow/lite/delegates/gpu:metal_delegate",
],
"//conditions:default": [],
}),
alwayslink = 1, # For registration to always run.
)
cc_test(
name = "gpu_plugin_test",
srcs = ["gpu_plugin_test.cc"],
tags = [
# TODO(b/214492180): Enable the tests for mac/ios too. This most likely
# needs TAP to recognize the xobjective-c++ flag.
"no_mac",
"tflite_not_portable_ios",
],
deps = [
":configuration_cc_proto",
":configuration_fbs",
":gpu_plugin_impl",
":proto_to_flatbuffer",
"//tensorflow/lite/core/acceleration/configuration:delegate_registry",
"@com_google_googletest//:gtest_main",
"@flatbuffers//:runtime_cc",
],
)
cc_library_with_tflite(
name = "xnnpack_plugin",
compatible_with = get_compatible_with_portable(),
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/acceleration/configuration:xnnpack_plugin"],
)
cc_test_with_tflite(
name = "xnnpack_plugin_with_tflite_test",
srcs = ["xnnpack_plugin_test.cc"],
# The variant of this test that links against TF Lite in Play services
# isn't portable to iOS / Mac or Android, because it relies on a separate
# shared library that isn't included in the executable, and the testing
# infrastructure for iOS and Android doesn't propagate data dependencies
# to the test device. So we disable this test on those devices.
# TODO(b/306161304): ideally we ought to apply these tags only to the
# variant for TF Lite in Play services. In the mean time, we apply those
# tags to the whole test, but also duplicate the test below using cc_test
# without the tags.
tags = [
"no_mac",
"tflite_not_portable_android",
"tflite_not_portable_ios",
],
tflite_deps = [
":xnnpack_plugin",
"//tensorflow/lite:test_util",
"//tensorflow/lite/acceleration/configuration:delegate_registry",
],
deps = [
":configuration_fbs",
"@com_google_googletest//:gtest_main",
"@flatbuffers//:runtime_cc",
"@pthreadpool",
],
)
# This duplicates xnnnpack_plugin_with_tflite_test above, but without the tags,
# to ensure that this test does get run on iOS and Android.
cc_test(
name = "xnnpack_plugin_test",
srcs = ["xnnpack_plugin_test.cc"],
deps = [
":configuration_fbs",
":xnnpack_plugin",
"//tensorflow/lite:test_util",
"//tensorflow/lite/acceleration/configuration:delegate_registry",
"@com_google_googletest//:gtest_main",
"@flatbuffers//:runtime_cc",
"@pthreadpool",
],
)
cc_library(
name = "coreml_plugin",
srcs = ["coreml_plugin.cc"],
deps = [
":configuration_fbs",
"//tensorflow/lite:minimal_logging",
"//tensorflow/lite/core/acceleration/configuration:delegate_registry",
"@com_google_absl//absl/memory",
] + select({
"//tensorflow:macos": [
"//tensorflow/lite/delegates/coreml:coreml_delegate",
],
"//tensorflow:ios": [
"//tensorflow/lite/delegates/coreml:coreml_delegate",
],
"//conditions:default": [],
}),
alwayslink = 1, # For registration to always run.
)
# TODO(b/260582614): Add support for TF Lite in Play Services.
cc_library(
name = "stable_delegate_plugin",
srcs = ["stable_delegate_plugin.cc"],
hdrs = ["stable_delegate_plugin.h"],
deps = [
":configuration_fbs",
"//tensorflow/lite/acceleration/configuration/c:delegate_plugin",
"//tensorflow/lite/acceleration/configuration/c:stable_delegate",
"//tensorflow/lite/c:common",
"//tensorflow/lite/core/acceleration/configuration:delegate_registry",
"//tensorflow/lite/delegates/utils/experimental/stable_delegate:delegate_loader",
"//tensorflow/lite/tools:logging",
"@com_google_absl//absl/memory",
"@flatbuffers//:runtime_cc",
],
alwayslink = 1, # For registration to always run.
)
cc_test(
name = "stable_delegate_plugin_test",
srcs = ["stable_delegate_plugin_test.cc"],
data = ["//tensorflow/lite/delegates/utils/experimental/stable_delegate:libtensorflowlite_stable_xnnpack_delegate.so"],
tags = [
# TODO(b/259303511): Propagate build config to data correctly to enable the test on x86 platforms.
"no_test_android_x86",
],
deps = [
":configuration_fbs",
":stable_delegate_plugin",
"//tensorflow/lite/core/acceleration/configuration:delegate_registry",
"//tensorflow/lite/delegates/xnnpack:xnnpack_delegate",
"@com_google_googletest//:gtest_main",
"@flatbuffers//:runtime_cc",
"@pthreadpool",
],
)
tflite_portable_test_suite()
@@ -0,0 +1,43 @@
# Copyright 2022 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.
# ==============================================================================
"""Build macros for checking ABI compatibility."""
load("@flatbuffers//:build_defs.bzl", "flatc_path")
load("@rules_shell//shell:sh_test.bzl", "sh_test")
def flatbuffer_schema_compat_test(name, ref_schema, schema):
"""Generates a test for schema binary compatibility.
Generates a test that the specified schema file is binary backwards
compatible with a reference schema (e.g. a previous version of the
schema).
Note: currently this build macro requires that the schema be a single
fully self-contained .fbs file; it does not yet support includes.
"""
native.genrule(
name = name + "_gen",
srcs = [ref_schema, schema],
outs = [name + "_test.sh"],
tools = [flatc_path],
cmd = ("echo $(rootpath {}) --conform $(rootpath {}) $(rootpath {}) > $@"
.format(flatc_path, ref_schema, schema)),
)
sh_test(
name = name,
srcs = [name + "_test.sh"],
data = [flatc_path, ref_schema, schema],
)
@@ -0,0 +1,107 @@
# Copyright 2021 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.
# ==============================================================================
# C API for delegate plugins.
load("//tensorflow:tensorflow.default.bzl", "get_compatible_with_portable")
load("//tensorflow/lite:build_def.bzl", "tflite_copts", "tflite_copts_warnings")
load(
"//tensorflow/lite/core/shims:cc_library_with_tflite.bzl",
"cc_library_with_tflite_with_c_headers_test",
)
# LINT.IfChange(tflite_acceleration_exported_headers)
exports_files([
"delegate_plugin.h",
"gpu_plugin.h",
"xnnpack_plugin.h",
])
# LINT.ThenChange(
# ../../../core/acceleration/configuration/c/BUILD:tflite_acceleration_exported_headers,
# ../../../java/BUILD:tflite_acceleration_exported_headers
# )
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = ["//visibility:private"],
licenses = ["notice"],
)
cc_library_with_tflite_with_c_headers_test(
name = "delegate_plugin",
hdrs = ["delegate_plugin.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
generate_opaque_delegate_target = True,
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/acceleration/configuration/c:delegate_plugin"],
)
cc_library_with_tflite_with_c_headers_test(
name = "nnapi_plugin",
hdrs = ["nnapi_plugin.h"],
copts = tflite_copts() + tflite_copts_warnings(),
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/acceleration/configuration/c:nnapi_plugin"],
)
test_suite(
name = "nnapi_plugin_test",
tests = [
"//tensorflow/lite/core/acceleration/configuration/c:nnapi_plugin_test",
],
)
cc_library_with_tflite_with_c_headers_test(
name = "gpu_plugin",
hdrs = ["gpu_plugin.h"],
copts = tflite_copts() + tflite_copts_warnings(),
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/acceleration/configuration/c:gpu_plugin"],
)
# For non-Android platforms, this should be built with '--copt=-DCL_DELEGATE_NO_GL'.
# On non-supported platforms (i.e. non-Android platforms if -DCL_DELEGATE_NO_GL wasn't specified),
# the test srcs are set to the empty list, so the test will succeed without testing anything.
test_suite(
name = "gpu_plugin_test",
tests = [
"//tensorflow/lite/core/acceleration/configuration/c:gpu_plugin_test",
],
)
cc_library_with_tflite_with_c_headers_test(
name = "xnnpack_plugin",
hdrs = ["xnnpack_plugin.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/acceleration/configuration/c:xnnpack_plugin"],
)
test_suite(
name = "xnnpack_plugin_test",
tests = [
"//tensorflow/lite/core/acceleration/configuration/c:xnnpack_plugin_test",
],
)
cc_library_with_tflite_with_c_headers_test(
name = "stable_delegate",
hdrs = ["stable_delegate.h"],
generate_opaque_delegate_target = True,
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/acceleration/configuration/c:stable_delegate"],
)
@@ -0,0 +1,23 @@
/* Copyright 2021 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_ACCELERATION_CONFIGURATION_C_DELEGATE_PLUGIN_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_DELEGATE_PLUGIN_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/acceleration/configuration/c/delegate_plugin.h
#include "tensorflow/lite/core/acceleration/configuration/c/delegate_plugin.h"
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_DELEGATE_PLUGIN_H_
@@ -0,0 +1,23 @@
/* Copyright 2022 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_ACCELERATION_CONFIGURATION_C_GPU_PLUGIN_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_GPU_PLUGIN_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/acceleration/configuration/c/gpu_plugin.h
#include "tensorflow/lite/core/acceleration/configuration/c/gpu_plugin.h"
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_GPU_PLUGIN_H_
@@ -0,0 +1,26 @@
/* 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_ACCELERATION_CONFIGURATION_C_NNAPI_PLUGIN_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_NNAPI_PLUGIN_H_
/// WARNING: this header file is DEPRECATED.
/// See https://developer.android.com/ndk/guides/neuralnetworks/migration-guide.
/// For documentation, see
/// third_party/tensorflow/lite/core/acceleration/configuration/c/nnapi_plugin.h
#include "tensorflow/lite/core/acceleration/configuration/c/nnapi_plugin.h"
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_NNAPI_PLUGIN_H_
@@ -0,0 +1,23 @@
/* Copyright 2022 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_ACCELERATION_CONFIGURATION_C_STABLE_DELEGATE_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_STABLE_DELEGATE_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/acceleration/configuration/c/stable_delegate.h
#include "tensorflow/lite/core/acceleration/configuration/c/stable_delegate.h"
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_STABLE_DELEGATE_H_
@@ -0,0 +1,23 @@
/* 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_ACCELERATION_CONFIGURATION_C_XNNPACK_PLUGIN_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_XNNPACK_PLUGIN_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin.h
#include "tensorflow/lite/core/acceleration/configuration/c/xnnpack_plugin.h"
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_C_XNNPACK_PLUGIN_H_
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -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/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/core/acceleration/configuration/delegate_registry.h"
#include "tensorflow/lite/minimal_logging.h"
// Guarding anyway although this file not expected to be compiled for non-Apple.
#if defined(__APPLE__)
#include "tensorflow/lite/delegates/coreml/coreml_delegate.h"
namespace tflite {
namespace delegates {
class CoreMLPlugin : public DelegatePluginInterface {
public:
TfLiteDelegatePtr Create() override {
TfLiteDelegate* delegate_ptr = TfLiteCoreMlDelegateCreate(&options_);
TfLiteDelegatePtr delegate(delegate_ptr, [](TfLiteDelegate* delegate) {
TfLiteCoreMlDelegateDelete(delegate);
});
return delegate;
}
int GetDelegateErrno(TfLiteDelegate* /* from_delegate */) override {
return 0;
}
static std::unique_ptr<CoreMLPlugin> New(
const TFLiteSettings& tflite_settings) {
return absl::make_unique<CoreMLPlugin>(tflite_settings);
}
explicit CoreMLPlugin(const TFLiteSettings& tflite_settings) {
const CoreMLSettings* settings = tflite_settings.coreml_settings();
options_ = TfLiteCoreMlDelegateOptions({});
// Using the proto defaults if the settings were not set.
switch (settings->enabled_devices()) {
case tflite::CoreMLSettings_::EnabledDevices_DEVICES_ALL:
options_.enabled_devices = TfLiteCoreMlDelegateAllDevices;
break;
case tflite::CoreMLSettings_::EnabledDevices_DEVICES_WITH_NEURAL_ENGINE:
options_.enabled_devices = TfLiteCoreMlDelegateDevicesWithNeuralEngine;
break;
default:
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Invalid devices enum: %d",
settings->enabled_devices());
}
options_.coreml_version = settings->coreml_version();
options_.max_delegated_partitions = settings->max_delegated_partitions();
options_.min_nodes_per_partition = settings->min_nodes_per_partition();
}
private:
TfLiteCoreMlDelegateOptions options_;
};
TFLITE_REGISTER_DELEGATE_FACTORY_FUNCTION(CoreMLPlugin, CoreMLPlugin::New);
} // namespace delegates
} // namespace tflite
#endif // __APPLE__
@@ -0,0 +1,59 @@
/* Copyright 2021 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/acceleration/configuration/delegate_plugin_converter.h"
#include <functional>
#include <memory>
#include "tensorflow/lite/c/common.h"
namespace tflite {
namespace delegates {
using ::tflite::delegates::DelegatePluginInterface;
using ::tflite::delegates::TfLiteOpaqueDelegatePtr;
// This class implements the C++ DelegatePluginInterface using
// the equivalent C API, which is the TfLiteDelegatePlugin struct.
class DelegatePluginViaCApi : public DelegatePluginInterface {
public:
explicit DelegatePluginViaCApi(const TfLiteOpaqueDelegatePlugin& plugin_c_api,
const ::tflite::TFLiteSettings& settings)
: plugin_c_api_(plugin_c_api), tflite_settings_(settings) {}
TfLiteOpaqueDelegatePtr Create() override {
return TfLiteOpaqueDelegatePtr(plugin_c_api_.create(&tflite_settings_),
plugin_c_api_.destroy);
}
int GetDelegateErrno(TfLiteOpaqueDelegate* from_delegate) override {
return plugin_c_api_.get_delegate_errno(from_delegate);
}
private:
TfLiteOpaqueDelegatePlugin plugin_c_api_;
const ::tflite::TFLiteSettings& tflite_settings_;
};
std::function<
std::unique_ptr<DelegatePluginInterface>(const ::tflite::TFLiteSettings&)>
DelegatePluginConverter(const TfLiteOpaqueDelegatePlugin& plugin_c_api) {
return [plugin_c_api](const ::tflite::TFLiteSettings& settings)
-> std::unique_ptr<DelegatePluginInterface> {
return std::make_unique<DelegatePluginViaCApi>(plugin_c_api, settings);
};
}
} // namespace delegates
} // namespace tflite
@@ -0,0 +1,38 @@
/* Copyright 2021 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_ACCELERATION_CONFIGURATION_DELEGATE_PLUGIN_CONVERTER_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_DELEGATE_PLUGIN_CONVERTER_H_
#include <functional>
#include <memory>
#include "tensorflow/lite/acceleration/configuration/c/delegate_plugin.h"
#include "tensorflow/lite/acceleration/configuration/delegate_registry.h"
namespace tflite {
namespace delegates {
// Converts from the C delegate plugin API to the C++ delegate plugin API.
// Given an instance of the (C) TfLiteOpaqueDelegatePlugin struct, this returns
// a function that takes a TFLiteSettings FlatBuffer and returns a unique_ptr to
// an instance of the (C++) DelegatePluginInterface abstract class.
std::function<std::unique_ptr<tflite::delegates::DelegatePluginInterface>(
const ::tflite::TFLiteSettings&)>
DelegatePluginConverter(const TfLiteOpaqueDelegatePlugin& plugin_c_api);
} // namespace delegates
} // namespace tflite
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_DELEGATE_PLUGIN_CONVERTER_H_
@@ -0,0 +1,33 @@
/* Copyright 2021 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_ACCELERATION_CONFIGURATION_DELEGATE_REGISTRY_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_DELEGATE_REGISTRY_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/acceleration/configuration/delegate_registry.h
#include "tensorflow/lite/core/acceleration/configuration/delegate_registry.h" // IWYU pragma: export
namespace tflite {
namespace delegates {
using TfLiteOpaqueDelegatePtr = ::tflite::delegates::TfLiteDelegatePtr;
using DelegatePluginInterface = ::tflite::delegates::DelegatePluginInterface;
using DelegatePluginRegistry = ::tflite::delegates::DelegatePluginRegistry;
} // namespace delegates
} // namespace tflite
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_DELEGATE_REGISTRY_H_
@@ -0,0 +1,805 @@
/* Copyright 2021 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/acceleration/configuration/flatbuffer_to_proto.h"
#include "tensorflow/lite/acceleration/configuration/configuration.pb.h"
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/minimal_logging.h"
namespace tflite {
namespace {
proto::ExecutionPreference ConvertExecutionPreference(
ExecutionPreference preference) {
switch (preference) {
case ExecutionPreference_ANY:
return proto::ExecutionPreference::ANY;
case ExecutionPreference_LOW_LATENCY:
return proto::ExecutionPreference::LOW_LATENCY;
case ExecutionPreference_LOW_POWER:
return proto::ExecutionPreference::LOW_POWER;
case ExecutionPreference_FORCE_CPU:
return proto::ExecutionPreference::FORCE_CPU;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for ExecutionPreference: %d", preference);
return proto::ExecutionPreference::ANY;
}
proto::Delegate ConvertDelegate(Delegate delegate) {
switch (delegate) {
case Delegate_NONE:
return proto::Delegate::NONE;
case Delegate_NNAPI:
return proto::Delegate::NNAPI;
case Delegate_GPU:
return proto::Delegate::GPU;
case Delegate_HEXAGON:
return proto::Delegate::HEXAGON;
case Delegate_XNNPACK:
return proto::Delegate::XNNPACK;
case Delegate_EDGETPU:
return proto::Delegate::EDGETPU;
case Delegate_EDGETPU_CORAL:
return proto::Delegate::EDGETPU_CORAL;
case Delegate_CORE_ML:
return proto::Delegate::CORE_ML;
case Delegate_ARMNN:
return proto::Delegate::ARMNN;
case Delegate_MTK_NEURON:
return proto::Delegate::MTK_NEURON;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Unexpected value for Delegate: %d",
delegate);
return proto::Delegate::NONE;
}
proto::NNAPIExecutionPreference ConvertNNAPIExecutionPreference(
NNAPIExecutionPreference preference) {
switch (preference) {
case NNAPIExecutionPreference_UNDEFINED:
return proto::NNAPIExecutionPreference::UNDEFINED;
case NNAPIExecutionPreference_NNAPI_LOW_POWER:
return proto::NNAPIExecutionPreference::NNAPI_LOW_POWER;
case NNAPIExecutionPreference_NNAPI_FAST_SINGLE_ANSWER:
return proto::NNAPIExecutionPreference::NNAPI_FAST_SINGLE_ANSWER;
case NNAPIExecutionPreference_NNAPI_SUSTAINED_SPEED:
return proto::NNAPIExecutionPreference::NNAPI_SUSTAINED_SPEED;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for NNAPIExecutionPreference: %d",
preference);
return proto::NNAPIExecutionPreference::UNDEFINED;
}
proto::NNAPIExecutionPriority ConvertNNAPIExecutionPriority(
NNAPIExecutionPriority priority) {
switch (priority) {
case NNAPIExecutionPriority_NNAPI_PRIORITY_UNDEFINED:
return proto::NNAPIExecutionPriority::NNAPI_PRIORITY_UNDEFINED;
case NNAPIExecutionPriority_NNAPI_PRIORITY_LOW:
return proto::NNAPIExecutionPriority::NNAPI_PRIORITY_LOW;
case NNAPIExecutionPriority_NNAPI_PRIORITY_MEDIUM:
return proto::NNAPIExecutionPriority::NNAPI_PRIORITY_MEDIUM;
case NNAPIExecutionPriority_NNAPI_PRIORITY_HIGH:
return proto::NNAPIExecutionPriority::NNAPI_PRIORITY_HIGH;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for NNAPIExecutionPriority: %d", priority);
return proto::NNAPIExecutionPriority::NNAPI_PRIORITY_UNDEFINED;
}
proto::GPUBackend ConvertGPUBackend(GPUBackend backend) {
switch (backend) {
case GPUBackend_UNSET:
return proto::GPUBackend::UNSET;
case GPUBackend_OPENCL:
return proto::GPUBackend::OPENCL;
case GPUBackend_OPENGL:
return proto::GPUBackend::OPENGL;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Unexpected value for GPUBackend: %d",
backend);
return proto::GPUBackend::UNSET;
}
proto::GPUInferenceUsage ConvertGPUInferenceUsage(
GPUInferenceUsage preference) {
switch (preference) {
case GPUInferenceUsage_GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER:
return proto::GPUInferenceUsage::
GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER;
case GPUInferenceUsage_GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED:
return proto::GPUInferenceUsage::GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for GPUInferenceUsage: %d", preference);
return proto::GPUInferenceUsage::GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER;
}
proto::GPUInferencePriority ConvertGPUInferencePriority(
GPUInferencePriority priority) {
switch (priority) {
case GPUInferencePriority_GPU_PRIORITY_AUTO:
return proto::GPUInferencePriority::GPU_PRIORITY_AUTO;
case GPUInferencePriority_GPU_PRIORITY_MAX_PRECISION:
return proto::GPUInferencePriority::GPU_PRIORITY_MAX_PRECISION;
case GPUInferencePriority_GPU_PRIORITY_MIN_LATENCY:
return proto::GPUInferencePriority::GPU_PRIORITY_MIN_LATENCY;
case GPUInferencePriority_GPU_PRIORITY_MIN_MEMORY_USAGE:
return proto::GPUInferencePriority::GPU_PRIORITY_MIN_MEMORY_USAGE;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for GPUInferencePriority: %d", priority);
return proto::GPUInferencePriority::GPU_PRIORITY_AUTO;
}
proto::EdgeTpuPowerState ConvertEdgeTpuPowerState(EdgeTpuPowerState state) {
switch (state) {
case EdgeTpuPowerState_UNDEFINED_POWERSTATE:
return proto::EdgeTpuPowerState::UNDEFINED_POWERSTATE;
case EdgeTpuPowerState_TPU_CORE_OFF:
return proto::EdgeTpuPowerState::TPU_CORE_OFF;
case EdgeTpuPowerState_READY:
return proto::EdgeTpuPowerState::READY;
case EdgeTpuPowerState_ACTIVE_MIN_POWER:
return proto::EdgeTpuPowerState::ACTIVE_MIN_POWER;
case EdgeTpuPowerState_ACTIVE_VERY_LOW_POWER:
return proto::EdgeTpuPowerState::ACTIVE_VERY_LOW_POWER;
case EdgeTpuPowerState_ACTIVE_LOW_POWER:
return proto::EdgeTpuPowerState::ACTIVE_LOW_POWER;
case EdgeTpuPowerState_ACTIVE:
return proto::EdgeTpuPowerState::ACTIVE;
case EdgeTpuPowerState_OVER_DRIVE:
return proto::EdgeTpuPowerState::OVER_DRIVE;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for EdgeTpuSettings::PowerState: %d",
state);
return proto::EdgeTpuPowerState::UNDEFINED_POWERSTATE;
}
proto::FallbackSettings ConvertFallbackSettings(
const FallbackSettings& settings) {
proto::FallbackSettings proto_settings;
proto_settings.set_allow_automatic_fallback_on_compilation_error(
settings.allow_automatic_fallback_on_compilation_error());
proto_settings.set_allow_automatic_fallback_on_execution_error(
settings.allow_automatic_fallback_on_execution_error());
return proto_settings;
}
proto::NNAPISettings ConvertNNAPISettings(const NNAPISettings& settings) {
proto::NNAPISettings proto_settings;
if (settings.accelerator_name() != nullptr) {
proto_settings.set_accelerator_name(settings.accelerator_name()->str());
}
if (settings.cache_directory() != nullptr) {
proto_settings.set_cache_directory(settings.cache_directory()->str());
}
if (settings.model_token() != nullptr) {
proto_settings.set_model_token(settings.model_token()->str());
}
proto_settings.set_execution_preference(
ConvertNNAPIExecutionPreference(settings.execution_preference()));
proto_settings.set_no_of_nnapi_instances_to_cache(
settings.no_of_nnapi_instances_to_cache());
if (settings.fallback_settings() != nullptr) {
*(proto_settings.mutable_fallback_settings()) =
ConvertFallbackSettings(*settings.fallback_settings());
}
proto_settings.set_allow_nnapi_cpu_on_android_10_plus(
settings.allow_nnapi_cpu_on_android_10_plus());
proto_settings.set_execution_priority(
ConvertNNAPIExecutionPriority(settings.execution_priority()));
proto_settings.set_allow_dynamic_dimensions(
settings.allow_dynamic_dimensions());
proto_settings.set_allow_fp16_precision_for_fp32(
settings.allow_fp16_precision_for_fp32());
proto_settings.set_use_burst_computation(settings.use_burst_computation());
proto_settings.set_support_library_handle(settings.support_library_handle());
return proto_settings;
}
proto::GPUSettings ConvertGPUSettings(const GPUSettings& settings) {
proto::GPUSettings proto_settings;
proto_settings.set_is_precision_loss_allowed(
settings.is_precision_loss_allowed());
proto_settings.set_enable_quantized_inference(
settings.enable_quantized_inference());
proto_settings.set_force_backend(ConvertGPUBackend(settings.force_backend()));
proto_settings.set_inference_priority1(
ConvertGPUInferencePriority(settings.inference_priority1()));
proto_settings.set_inference_priority2(
ConvertGPUInferencePriority(settings.inference_priority2()));
proto_settings.set_inference_priority3(
ConvertGPUInferencePriority(settings.inference_priority3()));
proto_settings.set_inference_preference(
ConvertGPUInferenceUsage(settings.inference_preference()));
if (settings.cache_directory() != nullptr) {
proto_settings.set_cache_directory(settings.cache_directory()->str());
}
if (settings.model_token() != nullptr) {
proto_settings.set_model_token(settings.model_token()->str());
}
return proto_settings;
}
proto::HexagonSettings ConvertHexagonSettings(const HexagonSettings& settings) {
proto::HexagonSettings proto_settings;
proto_settings.set_debug_level(settings.debug_level());
proto_settings.set_powersave_level(settings.powersave_level());
proto_settings.set_print_graph_profile(settings.print_graph_profile());
proto_settings.set_print_graph_debug(settings.print_graph_debug());
return proto_settings;
}
proto::XNNPackSettings ConvertXNNPackSettings(const XNNPackSettings& settings) {
proto::XNNPackSettings proto_settings;
proto_settings.set_num_threads(settings.num_threads());
proto_settings.set_flags(::tflite::proto::XNNPackFlags(settings.flags()));
return proto_settings;
}
proto::CoreMLSettings ConvertCoreMLSettings(const CoreMLSettings& settings) {
proto::CoreMLSettings proto_settings;
switch (settings.enabled_devices()) {
case CoreMLSettings_::EnabledDevices_DEVICES_ALL:
proto_settings.set_enabled_devices(proto::CoreMLSettings::DEVICES_ALL);
break;
case CoreMLSettings_::EnabledDevices_DEVICES_WITH_NEURAL_ENGINE:
proto_settings.set_enabled_devices(
proto::CoreMLSettings::DEVICES_WITH_NEURAL_ENGINE);
break;
default:
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Invalid devices enum: %d",
settings.enabled_devices());
}
proto_settings.set_coreml_version(settings.coreml_version());
proto_settings.set_max_delegated_partitions(
settings.max_delegated_partitions());
proto_settings.set_min_nodes_per_partition(
settings.min_nodes_per_partition());
return proto_settings;
}
proto::CPUSettings ConvertCPUSettings(const CPUSettings& settings) {
proto::CPUSettings proto_settings;
proto_settings.set_num_threads(settings.num_threads());
return proto_settings;
}
proto::EdgeTpuDeviceSpec ConvertEdgeTpuDeviceSpec(
const EdgeTpuDeviceSpec& device_spec) {
proto::EdgeTpuDeviceSpec proto_settings;
if (device_spec.device_paths() != nullptr) {
for (int i = 0; i < device_spec.device_paths()->size(); ++i) {
auto device_path = device_spec.device_paths()->Get(i);
proto_settings.add_device_paths(device_path->str());
}
}
proto_settings.set_platform_type(
static_cast<proto::EdgeTpuDeviceSpec::PlatformType>(
device_spec.platform_type()));
proto_settings.set_num_chips(device_spec.num_chips());
proto_settings.set_chip_family(device_spec.chip_family());
return proto_settings;
}
proto::EdgeTpuSettings ConvertEdgeTpuSettings(const EdgeTpuSettings& settings) {
proto::EdgeTpuSettings proto_settings;
proto_settings.set_inference_power_state(
ConvertEdgeTpuPowerState(settings.inference_power_state()));
proto_settings.set_inference_priority(settings.inference_priority());
if (settings.model_token() != nullptr) {
proto_settings.set_model_token(settings.model_token()->str());
}
if (settings.edgetpu_device_spec() != nullptr) {
*(proto_settings.mutable_edgetpu_device_spec()) =
ConvertEdgeTpuDeviceSpec(*settings.edgetpu_device_spec());
}
proto_settings.set_float_truncation_type(
static_cast<proto::EdgeTpuSettings::FloatTruncationType>(
settings.float_truncation_type()));
auto inactive_powre_configs = settings.inactive_power_configs();
if (inactive_powre_configs != nullptr) {
for (int i = 0; i < inactive_powre_configs->size(); ++i) {
auto config = inactive_powre_configs->Get(i);
auto proto_config = proto_settings.add_inactive_power_configs();
proto_config->set_inactive_power_state(
ConvertEdgeTpuPowerState(config->inactive_power_state()));
proto_config->set_inactive_timeout_us(config->inactive_timeout_us());
}
}
proto_settings.set_use_tpu_server(settings.use_tpu_server());
return proto_settings;
}
proto::StableDelegateLoaderSettings ConvertStableDelegateLoaderSettings(
const StableDelegateLoaderSettings& settings) {
proto::StableDelegateLoaderSettings proto_settings;
if (settings.delegate_path() != nullptr) {
proto_settings.set_delegate_path(settings.delegate_path()->str());
}
if (settings.delegate_name() != nullptr) {
proto_settings.set_delegate_name(settings.delegate_name()->str());
}
return proto_settings;
}
proto::CoralSettings ConvertCoralSettings(const CoralSettings& settings) {
proto::CoralSettings proto_settings;
if (settings.device() != nullptr) {
proto_settings.set_device(settings.device()->str());
}
proto_settings.set_performance(
static_cast<proto::CoralSettings::Performance>(settings.performance()));
proto_settings.set_usb_always_dfu(settings.usb_always_dfu());
proto_settings.set_usb_max_bulk_in_queue_length(
settings.usb_max_bulk_in_queue_length());
return proto_settings;
}
proto::GoogleEdgeTpuSettings::Priority ConvertGoogleEdgeTpuPriority(
GoogleEdgeTpuSettings_::Priority priority) {
switch (priority) {
case GoogleEdgeTpuSettings_::Priority_PRIORITY_UNDEFINED:
return proto::GoogleEdgeTpuSettings::PRIORITY_UNDEFINED;
case GoogleEdgeTpuSettings_::Priority_PRIORITY_LOW:
return proto::GoogleEdgeTpuSettings::PRIORITY_LOW;
case GoogleEdgeTpuSettings_::Priority_PRIORITY_MEDIUM:
return proto::GoogleEdgeTpuSettings::PRIORITY_MEDIUM;
case GoogleEdgeTpuSettings_::Priority_PRIORITY_HIGH:
return proto::GoogleEdgeTpuSettings::PRIORITY_HIGH;
}
}
proto::GoogleEdgeTpuSettings::TriState ConvertGoogleEdgeTpuTriState(
GoogleEdgeTpuSettings_::TriState tri_state) {
switch (tri_state) {
case GoogleEdgeTpuSettings_::TriState_TRISTATE_UNDEFINED:
return proto::GoogleEdgeTpuSettings::TRISTATE_UNDEFINED;
case GoogleEdgeTpuSettings_::TriState_TRISTATE_FALSE:
return proto::GoogleEdgeTpuSettings::TRISTATE_FALSE;
case GoogleEdgeTpuSettings_::TriState_TRISTATE_TRUE:
return proto::GoogleEdgeTpuSettings::TRISTATE_TRUE;
}
}
proto::GoogleEdgeTpuSettings ConvertGoogleEdgetpuSettings(
const GoogleEdgeTpuSettings& settings) {
proto::GoogleEdgeTpuSettings proto_settings;
proto_settings.set_log_verbosity(settings.log_verbosity());
proto_settings.set_enable_tracing(settings.enable_tracing());
proto_settings.set_priority(
ConvertGoogleEdgeTpuPriority(settings.priority()));
if (settings.extension_data()) {
proto_settings.set_extension_data(settings.extension_data()->data(),
settings.extension_data()->size());
}
if (settings.model_identifier()) {
proto_settings.set_model_identifier(settings.model_identifier()->str());
}
proto_settings.set_use_async_api(settings.use_async_api());
proto_settings.set_delegate_should_manage_cache_for_inputs(
settings.delegate_should_manage_cache_for_inputs());
proto_settings.set_delegate_should_manage_cache_for_outputs(
settings.delegate_should_manage_cache_for_outputs());
proto_settings.set_prefer_cache_coherency_for_inputs(
ConvertGoogleEdgeTpuTriState(
settings.prefer_cache_coherency_for_inputs()));
proto_settings.set_prefer_cache_coherency_for_outputs(
ConvertGoogleEdgeTpuTriState(
settings.prefer_cache_coherency_for_outputs()));
proto_settings.set_allow_fp16_precision_for_fp32(
settings.allow_fp16_precision_for_fp32());
return proto_settings;
}
proto::CompilationCachingSettings ConvertCompilationCachingSettings(
const CompilationCachingSettings& settings) {
proto::CompilationCachingSettings proto_settings;
if (settings.cache_dir() != nullptr) {
proto_settings.set_cache_dir(settings.cache_dir()->str());
}
if (settings.model_token() != nullptr) {
proto_settings.set_model_token(settings.model_token()->str());
}
return proto_settings;
}
proto::MtkNeuronSettings ConvertMtkNeuronSettings(
const MtkNeuronSettings& settings) {
proto::MtkNeuronSettings proto_settings;
proto_settings.set_execution_preference(
static_cast<proto::MtkNeuronSettings_ExecutionPreference>(
settings.execution_preference()));
proto_settings.set_execution_priority(
static_cast<proto::MtkNeuronSettings_ExecutionPriority>(
settings.execution_priority()));
auto optimization_hints = settings.optimization_hints();
if (optimization_hints != nullptr) {
for (auto hint : *optimization_hints) {
proto_settings.add_optimization_hints(
static_cast<proto::MtkNeuronSettings_OptimizationHint>(hint));
}
}
proto_settings.set_operation_check_mode(
static_cast<proto::MtkNeuronSettings_OperationCheckMode>(
settings.operation_check_mode()));
proto_settings.set_allow_fp16_precision_for_fp32(
settings.allow_fp16_precision_for_fp32());
proto_settings.set_use_ahwb(settings.use_ahwb());
proto_settings.set_use_cacheable_buffer(settings.use_cacheable_buffer());
auto compile_options = settings.compile_options();
if (compile_options != nullptr) {
for (auto option : *compile_options) {
proto_settings.add_compile_options(option->str());
}
}
auto accelerator_names = settings.accelerator_names();
if (accelerator_names != nullptr) {
for (auto name : *accelerator_names) {
proto_settings.add_accelerator_names(name->str());
}
}
if (settings.neuron_config_path()) {
proto_settings.set_neuron_config_path(settings.neuron_config_path()->str());
}
proto_settings.set_inference_deadline_ms(settings.inference_deadline_ms());
proto_settings.set_inference_abort_time_ms(
settings.inference_abort_time_ms());
return proto_settings;
}
proto::TFLiteSettings ConvertTfliteSettings(const TFLiteSettings& settings) {
proto::TFLiteSettings proto_settings;
proto_settings.set_delegate(ConvertDelegate(settings.delegate()));
if (settings.nnapi_settings() != nullptr) {
*proto_settings.mutable_nnapi_settings() =
ConvertNNAPISettings(*settings.nnapi_settings());
}
if (settings.gpu_settings() != nullptr) {
*proto_settings.mutable_gpu_settings() =
ConvertGPUSettings(*settings.gpu_settings());
}
if (settings.hexagon_settings() != nullptr) {
*proto_settings.mutable_hexagon_settings() =
ConvertHexagonSettings(*settings.hexagon_settings());
}
if (settings.xnnpack_settings() != nullptr) {
*proto_settings.mutable_xnnpack_settings() =
ConvertXNNPackSettings(*settings.xnnpack_settings());
}
if (settings.coreml_settings() != nullptr) {
*proto_settings.mutable_coreml_settings() =
ConvertCoreMLSettings(*settings.coreml_settings());
}
if (settings.cpu_settings() != nullptr) {
*proto_settings.mutable_cpu_settings() =
ConvertCPUSettings(*settings.cpu_settings());
}
proto_settings.set_max_delegated_partitions(
settings.max_delegated_partitions());
if (settings.edgetpu_settings() != nullptr) {
*proto_settings.mutable_edgetpu_settings() =
ConvertEdgeTpuSettings(*settings.edgetpu_settings());
}
if (settings.coral_settings() != nullptr) {
*proto_settings.mutable_coral_settings() =
ConvertCoralSettings(*settings.coral_settings());
}
if (settings.fallback_settings() != nullptr) {
*proto_settings.mutable_fallback_settings() =
ConvertFallbackSettings(*settings.fallback_settings());
}
proto_settings.set_disable_default_delegates(
settings.disable_default_delegates());
if (settings.stable_delegate_loader_settings() != nullptr) {
*proto_settings.mutable_stable_delegate_loader_settings() =
ConvertStableDelegateLoaderSettings(
*settings.stable_delegate_loader_settings());
}
if (settings.google_edgetpu_settings() != nullptr) {
*proto_settings.mutable_google_edgetpu_settings() =
ConvertGoogleEdgetpuSettings(*settings.google_edgetpu_settings());
}
if (settings.compilation_caching_settings() != nullptr) {
*proto_settings.mutable_compilation_caching_settings() =
ConvertCompilationCachingSettings(
*settings.compilation_caching_settings());
}
if (settings.mtk_neuron_settings() != nullptr) {
*proto_settings.mutable_mtk_neuron_settings() =
ConvertMtkNeuronSettings(*settings.mtk_neuron_settings());
}
return proto_settings;
}
proto::ModelFile ConvertModelFile(const ModelFile& model_file) {
proto::ModelFile proto_settings;
if (model_file.filename() != nullptr) {
proto_settings.set_filename(model_file.filename()->str());
}
proto_settings.set_fd(model_file.fd());
proto_settings.set_offset(model_file.offset());
proto_settings.set_length(model_file.length());
return proto_settings;
}
proto::BenchmarkStoragePaths ConvertBenchmarkStoragePaths(
const BenchmarkStoragePaths& storage_paths) {
proto::BenchmarkStoragePaths proto_settings;
if (storage_paths.storage_file_path() != nullptr) {
proto_settings.set_storage_file_path(
storage_paths.storage_file_path()->str());
}
if (storage_paths.data_directory_path() != nullptr) {
proto_settings.set_data_directory_path(
storage_paths.data_directory_path()->str());
}
return proto_settings;
}
proto::MinibenchmarkSettings ConvertMinibenchmarkSettings(
const MinibenchmarkSettings& settings) {
proto::MinibenchmarkSettings proto_settings;
if (settings.settings_to_test() != nullptr &&
settings.settings_to_test()->size() > 0) {
for (int i = 0; i < settings.settings_to_test()->size(); ++i) {
auto tflite_setting = settings.settings_to_test()->Get(i);
auto proto_tflite_setting = proto_settings.add_settings_to_test();
*proto_tflite_setting = ConvertTfliteSettings(*tflite_setting);
}
}
if (settings.model_file() != nullptr) {
*(proto_settings.mutable_model_file()) =
ConvertModelFile(*settings.model_file());
}
if (settings.storage_paths() != nullptr) {
*(proto_settings.mutable_storage_paths()) =
ConvertBenchmarkStoragePaths(*settings.storage_paths());
}
return proto_settings;
}
proto::BenchmarkEventType ConvertBenchmarkEventType(BenchmarkEventType type) {
switch (type) {
case BenchmarkEventType_UNDEFINED_BENCHMARK_EVENT_TYPE:
return proto::BenchmarkEventType::UNDEFINED_BENCHMARK_EVENT_TYPE;
case BenchmarkEventType_START:
return proto::BenchmarkEventType::START;
case BenchmarkEventType_END:
return proto::BenchmarkEventType::END;
case BenchmarkEventType_ERROR:
return proto::BenchmarkEventType::ERROR;
case BenchmarkEventType_LOGGED:
return proto::BenchmarkEventType::LOGGED;
case BenchmarkEventType_RECOVERED_ERROR:
return proto::BenchmarkEventType::RECOVERED_ERROR;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for BenchmarkEventType: %d", type);
return proto::BenchmarkEventType::UNDEFINED_BENCHMARK_EVENT_TYPE;
}
proto::BenchmarkMetric ConvertBenchmarkMetric(const BenchmarkMetric& metric) {
proto::BenchmarkMetric proto_metric;
if (metric.name() != nullptr) {
proto_metric.set_name(metric.name()->str());
}
auto values = metric.values();
if (values != nullptr) {
for (int i = 0; i < values->size(); ++i) {
proto_metric.add_values(values->Get(i));
}
}
return proto_metric;
}
proto::BenchmarkResult ConvertBenchmarkResult(const BenchmarkResult& result) {
proto::BenchmarkResult proto_result;
auto initialization_time_us = result.initialization_time_us();
if (initialization_time_us != nullptr) {
for (int i = 0; i < initialization_time_us->size(); ++i) {
proto_result.add_initialization_time_us(initialization_time_us->Get(i));
}
}
auto inference_time_us = result.inference_time_us();
if (inference_time_us != nullptr) {
for (int i = 0; i < inference_time_us->size(); ++i) {
proto_result.add_inference_time_us(inference_time_us->Get(i));
}
}
proto_result.set_max_memory_kb(result.max_memory_kb());
proto_result.set_ok(result.ok());
auto metrics = result.metrics();
if (metrics != nullptr) {
for (int i = 0; i < metrics->size(); ++i) {
*proto_result.add_metrics() = ConvertBenchmarkMetric(*metrics->Get(i));
}
}
return proto_result;
}
proto::BenchmarkStage ConvertBenchmarkStage(BenchmarkStage stage) {
switch (stage) {
case BenchmarkStage_UNKNOWN:
return proto::BenchmarkStage::UNKNOWN;
case BenchmarkStage_INITIALIZATION:
return proto::BenchmarkStage::INITIALIZATION;
case BenchmarkStage_INFERENCE:
return proto::BenchmarkStage::INFERENCE;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Unexpected value for BenchmarkStage: %d",
stage);
return proto::BenchmarkStage::UNKNOWN;
}
proto::ErrorCode ConvertBenchmarkErrorCode(const ErrorCode& code) {
proto::ErrorCode proto_code;
proto_code.set_source(ConvertDelegate(code.source()));
proto_code.set_tflite_error(code.tflite_error());
proto_code.set_underlying_api_error(code.underlying_api_error());
return proto_code;
}
proto::BenchmarkError ConvertBenchmarkError(const BenchmarkError& error) {
proto::BenchmarkError proto_error;
proto_error.set_stage(ConvertBenchmarkStage(error.stage()));
proto_error.set_exit_code(error.exit_code());
proto_error.set_signal(error.signal());
auto error_codes = error.error_code();
if (error_codes != nullptr) {
for (int i = 0; i < error_codes->size(); ++i) {
*proto_error.add_error_code() =
ConvertBenchmarkErrorCode(*error_codes->Get(i));
}
}
proto_error.set_mini_benchmark_error_code(error.mini_benchmark_error_code());
return proto_error;
}
proto::BenchmarkEvent ConvertBenchmarkEvent(const BenchmarkEvent& event) {
proto::BenchmarkEvent proto_event;
if (event.tflite_settings() != nullptr) {
*proto_event.mutable_tflite_settings() =
ConvertTfliteSettings(*event.tflite_settings());
}
proto_event.set_event_type(ConvertBenchmarkEventType(event.event_type()));
if (event.result() != nullptr) {
*proto_event.mutable_result() = ConvertBenchmarkResult(*event.result());
}
if (event.error() != nullptr) {
*proto_event.mutable_error() = ConvertBenchmarkError(*event.error());
}
proto_event.set_boottime_us(event.boottime_us());
proto_event.set_wallclock_us(event.wallclock_us());
return proto_event;
}
proto::BestAccelerationDecision ConvertBestAccelerationDecision(
const BestAccelerationDecision& decision) {
proto::BestAccelerationDecision proto_decision;
proto_decision.set_number_of_source_events(
decision.number_of_source_events());
if (decision.min_latency_event() != nullptr) {
*proto_decision.mutable_min_latency_event() =
ConvertBenchmarkEvent(*decision.min_latency_event());
}
proto_decision.set_min_inference_time_us(decision.min_inference_time_us());
return proto_decision;
}
proto::BenchmarkInitializationFailure ConvertBenchmarkInitializationFailure(
const BenchmarkInitializationFailure& init_failure) {
proto::BenchmarkInitializationFailure proto_init_failure;
proto_init_failure.set_initialization_status(
init_failure.initialization_status());
return proto_init_failure;
}
} // namespace
proto::ComputeSettings ConvertFromFlatbuffer(
const ComputeSettings& settings, bool skip_mini_benchmark_settings) {
proto::ComputeSettings proto_settings;
proto_settings.set_preference(
ConvertExecutionPreference(settings.preference()));
if (settings.tflite_settings() != nullptr) {
*(proto_settings.mutable_tflite_settings()) =
ConvertTfliteSettings(*settings.tflite_settings());
}
if (settings.model_namespace_for_statistics() != nullptr) {
proto_settings.set_model_namespace_for_statistics(
settings.model_namespace_for_statistics()->str());
}
if (settings.model_identifier_for_statistics() != nullptr) {
proto_settings.set_model_identifier_for_statistics(
settings.model_identifier_for_statistics()->str());
}
if (!skip_mini_benchmark_settings &&
settings.settings_to_test_locally() != nullptr) {
*(proto_settings.mutable_settings_to_test_locally()) =
ConvertMinibenchmarkSettings(*settings.settings_to_test_locally());
}
return proto_settings;
}
proto::ComputeSettings ConvertFromFlatbuffer(
const ComputeSettingsT& settings, bool skip_mini_benchmark_settings) {
flatbuffers::FlatBufferBuilder fbb;
fbb.Finish(ComputeSettings::Pack(fbb, &settings));
auto settings_fbb =
flatbuffers::GetRoot<ComputeSettings>(fbb.GetBufferPointer());
return ConvertFromFlatbuffer(*settings_fbb, skip_mini_benchmark_settings);
}
proto::MiniBenchmarkEvent ConvertFromFlatbuffer(
const MiniBenchmarkEvent& event) {
proto::MiniBenchmarkEvent proto_event;
proto_event.set_is_log_flushing_event(event.is_log_flushing_event());
if (event.best_acceleration_decision() != nullptr) {
*proto_event.mutable_best_acceleration_decision() =
ConvertBestAccelerationDecision(*event.best_acceleration_decision());
}
if (event.initialization_failure() != nullptr) {
*proto_event.mutable_initialization_failure() =
ConvertBenchmarkInitializationFailure(*event.initialization_failure());
}
if (event.benchmark_event() != nullptr) {
*proto_event.mutable_benchmark_event() =
ConvertBenchmarkEvent(*event.benchmark_event());
}
return proto_event;
}
proto::MiniBenchmarkEvent ConvertFromFlatbuffer(
const MiniBenchmarkEventT& event) {
flatbuffers::FlatBufferBuilder fbb;
fbb.Finish(MiniBenchmarkEvent::Pack(fbb, &event));
auto event_fbb =
flatbuffers::GetRoot<MiniBenchmarkEvent>(fbb.GetBufferPointer());
return ConvertFromFlatbuffer(*event_fbb);
}
} // namespace tflite
@@ -0,0 +1,41 @@
/* Copyright 2021 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_ACCELERATION_CONFIGURATION_FLATBUFFER_TO_PROTO_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_FLATBUFFER_TO_PROTO_H_
#include "flatbuffers/flatbuffers.h" // from @flatbuffers
#include "tensorflow/lite/acceleration/configuration/configuration.pb.h"
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
namespace tflite {
// Converts the provided ComputeSettings from flatbuffer to proto format.
proto::ComputeSettings ConvertFromFlatbuffer(
const ComputeSettings& settings, bool skip_mini_benchmark_settings = false);
proto::ComputeSettings ConvertFromFlatbuffer(
const ComputeSettingsT& settings,
bool skip_mini_benchmark_settings = false);
// Converts the provided MiniBenchmarkEvent from flatbuffer to proto format.
proto::MiniBenchmarkEvent ConvertFromFlatbuffer(
const MiniBenchmarkEvent& event);
proto::MiniBenchmarkEvent ConvertFromFlatbuffer(
const MiniBenchmarkEventT& event);
} // namespace tflite
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_FLATBUFFER_TO_PROTO_H_
@@ -0,0 +1,801 @@
/* Copyright 2021 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/acceleration/configuration/flatbuffer_to_proto.h"
#include <cstdint>
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include "tensorflow/lite/acceleration/configuration/configuration.pb.h"
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
namespace tflite {
namespace acceleration {
namespace {
class ConversionTest : public ::testing::Test {
protected:
void CheckDelegateEnum(Delegate input, proto::Delegate output) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->delegate = input;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(output, compute.tflite_settings().delegate());
}
void CheckExecutionPreference(ExecutionPreference input,
proto::ExecutionPreference output) {
settings_.preference = input;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(output, compute.preference());
}
void CheckNNAPIExecutionPreference(NNAPIExecutionPreference input,
proto::NNAPIExecutionPreference output) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->nnapi_settings =
std::make_unique<NNAPISettingsT>();
settings_.tflite_settings->nnapi_settings->execution_preference = input;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(
output,
compute.tflite_settings().nnapi_settings().execution_preference());
}
void CheckNNAPIExecutionPriority(NNAPIExecutionPriority input,
proto::NNAPIExecutionPriority output) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->nnapi_settings =
std::make_unique<NNAPISettingsT>();
settings_.tflite_settings->nnapi_settings->execution_priority = input;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(output,
compute.tflite_settings().nnapi_settings().execution_priority());
}
void CheckGPUBackend(GPUBackend input, proto::GPUBackend output) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->gpu_settings = std::make_unique<GPUSettingsT>();
settings_.tflite_settings->gpu_settings->force_backend = input;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(output, compute.tflite_settings().gpu_settings().force_backend());
}
ComputeSettingsT settings_;
MiniBenchmarkEventT event_;
};
TEST_F(ConversionTest, Delegate) {
CheckDelegateEnum(Delegate_NONE, proto::Delegate::NONE);
CheckDelegateEnum(Delegate_NNAPI, proto::Delegate::NNAPI);
CheckDelegateEnum(Delegate_GPU, proto::Delegate::GPU);
CheckDelegateEnum(Delegate_HEXAGON, proto::Delegate::HEXAGON);
CheckDelegateEnum(Delegate_EDGETPU, proto::Delegate::EDGETPU);
CheckDelegateEnum(Delegate_EDGETPU_CORAL, proto::Delegate::EDGETPU_CORAL);
CheckDelegateEnum(Delegate_XNNPACK, proto::Delegate::XNNPACK);
CheckDelegateEnum(Delegate_CORE_ML, proto::Delegate::CORE_ML);
}
TEST_F(ConversionTest, ExecutionPreference) {
CheckExecutionPreference(ExecutionPreference_ANY,
proto::ExecutionPreference::ANY);
CheckExecutionPreference(ExecutionPreference_LOW_LATENCY,
proto::ExecutionPreference::LOW_LATENCY);
CheckExecutionPreference(ExecutionPreference_LOW_POWER,
proto::ExecutionPreference::LOW_POWER);
CheckExecutionPreference(ExecutionPreference_FORCE_CPU,
proto::ExecutionPreference::FORCE_CPU);
}
TEST_F(ConversionTest, ModelIdentifier) {
settings_.model_identifier_for_statistics = "id";
settings_.model_namespace_for_statistics = "ns";
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(compute.model_namespace_for_statistics(), "ns");
EXPECT_EQ(compute.model_identifier_for_statistics(), "id");
}
TEST_F(ConversionTest, NNAPISettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->nnapi_settings =
std::make_unique<NNAPISettingsT>();
NNAPISettingsT* input_settings =
settings_.tflite_settings->nnapi_settings.get();
input_settings->accelerator_name = "a";
input_settings->cache_directory = "d";
input_settings->model_token = "t";
input_settings->allow_fp16_precision_for_fp32 = true;
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::NNAPISettings output_settings =
compute.tflite_settings().nnapi_settings();
EXPECT_EQ(output_settings.accelerator_name(), "a");
EXPECT_EQ(output_settings.cache_directory(), "d");
EXPECT_EQ(output_settings.model_token(), "t");
EXPECT_TRUE(output_settings.allow_fp16_precision_for_fp32());
EXPECT_FALSE(output_settings.allow_nnapi_cpu_on_android_10_plus());
EXPECT_FALSE(output_settings.fallback_settings()
.allow_automatic_fallback_on_compilation_error());
EXPECT_FALSE(output_settings.fallback_settings()
.allow_automatic_fallback_on_execution_error());
input_settings->fallback_settings = std::make_unique<FallbackSettingsT>();
input_settings->fallback_settings
->allow_automatic_fallback_on_compilation_error = true;
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().nnapi_settings();
EXPECT_TRUE(output_settings.fallback_settings()
.allow_automatic_fallback_on_compilation_error());
EXPECT_FALSE(output_settings.fallback_settings()
.allow_automatic_fallback_on_execution_error());
input_settings->fallback_settings
->allow_automatic_fallback_on_compilation_error = false;
input_settings->fallback_settings
->allow_automatic_fallback_on_execution_error = true;
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().nnapi_settings();
EXPECT_FALSE(output_settings.fallback_settings()
.allow_automatic_fallback_on_compilation_error());
EXPECT_TRUE(output_settings.fallback_settings()
.allow_automatic_fallback_on_execution_error());
input_settings->allow_fp16_precision_for_fp32 = false;
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().nnapi_settings();
EXPECT_FALSE(output_settings.allow_fp16_precision_for_fp32());
}
TEST_F(ConversionTest, NNAPIAllowDynamicDimensions) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->nnapi_settings =
std::make_unique<NNAPISettingsT>();
NNAPISettingsT* input_settings =
settings_.tflite_settings->nnapi_settings.get();
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::NNAPISettings output_settings =
compute.tflite_settings().nnapi_settings();
EXPECT_FALSE(output_settings.allow_dynamic_dimensions());
input_settings->allow_dynamic_dimensions = true;
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().nnapi_settings();
EXPECT_TRUE(output_settings.allow_dynamic_dimensions());
}
TEST_F(ConversionTest, NNAPIBurstComputation) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->nnapi_settings =
std::make_unique<NNAPISettingsT>();
NNAPISettingsT* input_settings =
settings_.tflite_settings->nnapi_settings.get();
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::NNAPISettings output_settings =
compute.tflite_settings().nnapi_settings();
EXPECT_FALSE(output_settings.use_burst_computation());
input_settings->use_burst_computation = true;
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().nnapi_settings();
EXPECT_TRUE(output_settings.use_burst_computation());
}
TEST_F(ConversionTest, NNAPIExecutionPreference) {
CheckNNAPIExecutionPreference(
NNAPIExecutionPreference_NNAPI_FAST_SINGLE_ANSWER,
proto::NNAPIExecutionPreference::NNAPI_FAST_SINGLE_ANSWER);
CheckNNAPIExecutionPreference(
NNAPIExecutionPreference_NNAPI_LOW_POWER,
proto::NNAPIExecutionPreference::NNAPI_LOW_POWER);
CheckNNAPIExecutionPreference(
NNAPIExecutionPreference_NNAPI_SUSTAINED_SPEED,
proto::NNAPIExecutionPreference::NNAPI_SUSTAINED_SPEED);
CheckNNAPIExecutionPreference(NNAPIExecutionPreference_UNDEFINED,
proto::NNAPIExecutionPreference::UNDEFINED);
}
TEST_F(ConversionTest, NNAPIExecutionPriority) {
CheckNNAPIExecutionPriority(
NNAPIExecutionPriority_NNAPI_PRIORITY_LOW,
proto::NNAPIExecutionPriority::NNAPI_PRIORITY_LOW);
CheckNNAPIExecutionPriority(
NNAPIExecutionPriority_NNAPI_PRIORITY_MEDIUM,
proto::NNAPIExecutionPriority::NNAPI_PRIORITY_MEDIUM);
CheckNNAPIExecutionPriority(
NNAPIExecutionPriority_NNAPI_PRIORITY_HIGH,
proto::NNAPIExecutionPriority::NNAPI_PRIORITY_HIGH);
CheckNNAPIExecutionPriority(
NNAPIExecutionPriority_NNAPI_PRIORITY_UNDEFINED,
proto::NNAPIExecutionPriority::NNAPI_PRIORITY_UNDEFINED);
}
TEST_F(ConversionTest, NNAPISupportLibraryHandle) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->nnapi_settings =
std::make_unique<NNAPISettingsT>();
NNAPISettingsT* input_settings =
settings_.tflite_settings->nnapi_settings.get();
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::NNAPISettings output_settings =
compute.tflite_settings().nnapi_settings();
EXPECT_EQ(output_settings.support_library_handle(), 0);
input_settings->support_library_handle = std::numeric_limits<int64_t>::max();
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().nnapi_settings();
EXPECT_EQ(output_settings.support_library_handle(),
std::numeric_limits<int64_t>::max());
}
TEST_F(ConversionTest, GPUSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->gpu_settings = std::make_unique<GPUSettingsT>();
GPUSettingsT* input_settings = settings_.tflite_settings->gpu_settings.get();
input_settings->is_precision_loss_allowed = true;
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::GPUSettings output_settings = compute.tflite_settings().gpu_settings();
EXPECT_TRUE(output_settings.is_precision_loss_allowed());
input_settings->is_precision_loss_allowed = false;
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().gpu_settings();
EXPECT_FALSE(output_settings.is_precision_loss_allowed());
EXPECT_TRUE(output_settings.enable_quantized_inference());
input_settings->enable_quantized_inference = false;
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().gpu_settings();
EXPECT_FALSE(output_settings.enable_quantized_inference());
}
TEST_F(ConversionTest, GPUBacked) {
CheckGPUBackend(GPUBackend_UNSET, proto::GPUBackend::UNSET);
CheckGPUBackend(GPUBackend_OPENCL, proto::GPUBackend::OPENCL);
CheckGPUBackend(GPUBackend_OPENGL, proto::GPUBackend::OPENGL);
}
TEST_F(ConversionTest, GPUInferencePriority) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->gpu_settings = std::make_unique<GPUSettingsT>();
GPUSettingsT* input_settings = settings_.tflite_settings->gpu_settings.get();
input_settings->inference_priority1 =
GPUInferencePriority_GPU_PRIORITY_MIN_MEMORY_USAGE;
input_settings->inference_priority2 =
GPUInferencePriority_GPU_PRIORITY_MIN_LATENCY;
// Third priority is AUTO by default.
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::GPUSettings output_settings = compute.tflite_settings().gpu_settings();
EXPECT_EQ(proto::GPUInferencePriority::GPU_PRIORITY_MIN_MEMORY_USAGE,
output_settings.inference_priority1());
EXPECT_EQ(proto::GPUInferencePriority::GPU_PRIORITY_MIN_LATENCY,
output_settings.inference_priority2());
EXPECT_EQ(proto::GPUInferencePriority::GPU_PRIORITY_AUTO,
output_settings.inference_priority3());
}
TEST_F(ConversionTest, GPUInferencePreference) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->gpu_settings = std::make_unique<GPUSettingsT>();
GPUSettingsT* input_settings = settings_.tflite_settings->gpu_settings.get();
input_settings->inference_preference =
GPUInferenceUsage_GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER;
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::GPUSettings output_settings = compute.tflite_settings().gpu_settings();
EXPECT_EQ(
proto::GPUInferenceUsage::GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER,
output_settings.inference_preference());
input_settings->inference_preference =
GPUInferenceUsage_GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED;
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().gpu_settings();
EXPECT_EQ(proto::GPUInferenceUsage::GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED,
output_settings.inference_preference());
}
TEST_F(ConversionTest, HexagonSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->hexagon_settings =
std::make_unique<HexagonSettingsT>();
HexagonSettingsT* input_settings =
settings_.tflite_settings->hexagon_settings.get();
input_settings->debug_level = 1;
input_settings->powersave_level = 2;
input_settings->print_graph_profile = true;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
const proto::HexagonSettings& output_settings =
compute.tflite_settings().hexagon_settings();
EXPECT_EQ(1, output_settings.debug_level());
EXPECT_EQ(2, output_settings.powersave_level());
EXPECT_TRUE(output_settings.print_graph_profile());
EXPECT_FALSE(output_settings.print_graph_debug());
}
TEST_F(ConversionTest, EdgeTpuSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->edgetpu_settings =
std::make_unique<EdgeTpuSettingsT>();
EdgeTpuSettingsT* input_settings =
settings_.tflite_settings->edgetpu_settings.get();
constexpr EdgeTpuPowerState kInferencePowerState = EdgeTpuPowerState_ACTIVE;
constexpr EdgeTpuPowerState kInactivePowerState =
EdgeTpuPowerState_ACTIVE_MIN_POWER;
constexpr int64_t kInactiveTimeoutUs = 300000;
constexpr int kInferencePriority = 2;
const std::string kModelToken = "model_token";
constexpr EdgeTpuSettings_::FloatTruncationType kFloatTruncationType =
EdgeTpuSettings_::FloatTruncationType_HALF;
constexpr bool kUseTpuServer = true;
input_settings->inference_power_state = kInferencePowerState;
input_settings->inference_priority = kInferencePriority;
input_settings->model_token = kModelToken;
input_settings->float_truncation_type = kFloatTruncationType;
input_settings->use_tpu_server = kUseTpuServer;
std::unique_ptr<EdgeTpuInactivePowerConfigT> inactive_power_config(
new EdgeTpuInactivePowerConfigT());
inactive_power_config->inactive_power_state = kInactivePowerState;
inactive_power_config->inactive_timeout_us = kInactiveTimeoutUs;
input_settings->inactive_power_configs.emplace_back(
std::move(inactive_power_config));
constexpr EdgeTpuDeviceSpec_::PlatformType kPlatformType =
EdgeTpuDeviceSpec_::PlatformType_MMIO;
constexpr int kNumChips = 1;
const std::string kDevicePath = "/dev/abrolhos";
constexpr int kChipFamily = 1;
input_settings->edgetpu_device_spec = std::make_unique<EdgeTpuDeviceSpecT>();
EdgeTpuDeviceSpecT* input_spec = input_settings->edgetpu_device_spec.get();
input_spec->platform_type = kPlatformType;
input_spec->num_chips = kNumChips;
input_spec->chip_family = kChipFamily;
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::EdgeTpuSettings output_settings =
compute.tflite_settings().edgetpu_settings();
EXPECT_EQ(
static_cast<EdgeTpuPowerState>(output_settings.inference_power_state()),
kInferencePowerState);
EXPECT_EQ(output_settings.inactive_power_configs().size(), 1);
EXPECT_EQ(
static_cast<EdgeTpuPowerState>(output_settings.inactive_power_configs()
.at(0)
.inactive_power_state()),
kInactivePowerState);
EXPECT_EQ(
output_settings.inactive_power_configs().at(0).inactive_timeout_us(),
kInactiveTimeoutUs);
EXPECT_EQ(output_settings.inference_priority(), kInferencePriority);
EXPECT_EQ(output_settings.model_token(), kModelToken);
EXPECT_EQ(static_cast<EdgeTpuSettings_::FloatTruncationType>(
output_settings.float_truncation_type()),
kFloatTruncationType);
EXPECT_EQ(output_settings.use_tpu_server(), kUseTpuServer);
EXPECT_EQ(static_cast<EdgeTpuDeviceSpec_::PlatformType>(
output_settings.edgetpu_device_spec().platform_type()),
kPlatformType);
EXPECT_EQ(output_settings.edgetpu_device_spec().num_chips(), kNumChips);
EXPECT_EQ(output_settings.edgetpu_device_spec().device_paths_size(), 0);
EXPECT_EQ(output_settings.edgetpu_device_spec().chip_family(), kChipFamily);
input_spec->device_paths.push_back(kDevicePath);
compute = ConvertFromFlatbuffer(settings_);
output_settings = compute.tflite_settings().edgetpu_settings();
EXPECT_EQ(output_settings.edgetpu_device_spec().device_paths().size(), 1);
EXPECT_EQ(output_settings.edgetpu_device_spec().device_paths()[0],
kDevicePath);
}
TEST_F(ConversionTest, XNNPackSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->xnnpack_settings =
std::make_unique<XNNPackSettingsT>();
XNNPackSettingsT* input_settings =
settings_.tflite_settings->xnnpack_settings.get();
input_settings->num_threads = 2;
input_settings->flags =
tflite::XNNPackFlags::XNNPackFlags_TFLITE_XNNPACK_DELEGATE_FLAG_QS8_QU8;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(compute.tflite_settings().xnnpack_settings().num_threads(), 2);
EXPECT_EQ(compute.tflite_settings().xnnpack_settings().flags(), 3);
}
TEST_F(ConversionTest, CoreMLSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->coreml_settings =
std::make_unique<CoreMLSettingsT>();
CoreMLSettingsT* input_settings =
settings_.tflite_settings->coreml_settings.get();
input_settings->enabled_devices =
CoreMLSettings_::EnabledDevices_DEVICES_WITH_NEURAL_ENGINE;
input_settings->coreml_version = 3;
input_settings->max_delegated_partitions = 10;
input_settings->min_nodes_per_partition = 4;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(compute.tflite_settings().coreml_settings().enabled_devices(),
proto::CoreMLSettings::DEVICES_WITH_NEURAL_ENGINE);
EXPECT_EQ(compute.tflite_settings().coreml_settings().coreml_version(), 3);
EXPECT_EQ(
compute.tflite_settings().coreml_settings().max_delegated_partitions(),
10);
EXPECT_EQ(
compute.tflite_settings().coreml_settings().min_nodes_per_partition(), 4);
}
TEST_F(ConversionTest, CoralSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->coral_settings =
std::make_unique<CoralSettingsT>();
CoralSettingsT* input_settings =
settings_.tflite_settings->coral_settings.get();
input_settings->device = "test";
input_settings->performance = CoralSettings_::Performance_HIGH;
input_settings->usb_always_dfu = true;
input_settings->usb_max_bulk_in_queue_length = 768;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
const proto::CoralSettings& output_settings =
compute.tflite_settings().coral_settings();
EXPECT_EQ("test", output_settings.device());
EXPECT_TRUE(output_settings.usb_always_dfu());
EXPECT_EQ(proto::CoralSettings::HIGH, output_settings.performance());
EXPECT_EQ(768, output_settings.usb_max_bulk_in_queue_length());
}
TEST_F(ConversionTest, StableDelegateLoaderSettings) {
const std::string kDelegatePath = "TEST_DELEGATE_PATH";
const std::string kDelegateName = "TEST_DELEGATE_NAME";
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->stable_delegate_loader_settings =
std::make_unique<StableDelegateLoaderSettingsT>();
settings_.tflite_settings->stable_delegate_loader_settings->delegate_path =
kDelegatePath;
settings_.tflite_settings->stable_delegate_loader_settings->delegate_name =
kDelegateName;
const proto::StableDelegateLoaderSettings output_settings =
ConvertFromFlatbuffer(settings_)
.tflite_settings()
.stable_delegate_loader_settings();
EXPECT_EQ(output_settings.delegate_path(), kDelegatePath);
EXPECT_EQ(output_settings.delegate_name(), kDelegateName);
}
TEST_F(ConversionTest, CPUSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->cpu_settings = std::make_unique<CPUSettingsT>();
settings_.tflite_settings->cpu_settings->num_threads = 2;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(compute.tflite_settings().cpu_settings().num_threads(), 2);
}
TEST_F(ConversionTest, MaxDelegatedPartitions) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->max_delegated_partitions = 2;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(compute.tflite_settings().max_delegated_partitions(), 2);
}
TEST_F(ConversionTest, GoogleEdgeTpuSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->google_edgetpu_settings =
std::make_unique<GoogleEdgeTpuSettingsT>();
GoogleEdgeTpuSettingsT* input_settings =
settings_.tflite_settings->google_edgetpu_settings.get();
input_settings->priority = GoogleEdgeTpuSettings_::Priority_PRIORITY_HIGH;
input_settings->allow_fp16_precision_for_fp32 = true;
std::vector<uint8_t> extension_data{1, 2, 3};
input_settings->extension_data = extension_data;
input_settings->model_identifier = "model";
input_settings->prefer_cache_coherency_for_inputs =
GoogleEdgeTpuSettings_::TriState_TRISTATE_TRUE;
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::GoogleEdgeTpuSettings output_settings =
compute.tflite_settings().google_edgetpu_settings();
EXPECT_EQ(output_settings.priority(),
proto::GoogleEdgeTpuSettings::PRIORITY_HIGH);
EXPECT_TRUE(output_settings.allow_fp16_precision_for_fp32());
EXPECT_EQ(output_settings.extension_data().size(), 3);
EXPECT_EQ(output_settings.model_identifier(), "model");
EXPECT_EQ(output_settings.prefer_cache_coherency_for_inputs(),
proto::GoogleEdgeTpuSettings::TRISTATE_TRUE);
}
TEST_F(ConversionTest, CompilationCachingSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->compilation_caching_settings =
std::make_unique<CompilationCachingSettingsT>();
CompilationCachingSettingsT* input_settings =
settings_.tflite_settings->compilation_caching_settings.get();
input_settings->cache_dir = "/tmp";
input_settings->model_token = "model";
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
proto::CompilationCachingSettings output_settings =
compute.tflite_settings().compilation_caching_settings();
EXPECT_EQ(output_settings.cache_dir(), "/tmp");
EXPECT_EQ(output_settings.model_token(), "model");
}
TEST_F(ConversionTest, MtkNeuronSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->mtk_neuron_settings =
std::make_unique<MtkNeuronSettingsT>();
MtkNeuronSettingsT* input_settings =
settings_.tflite_settings->mtk_neuron_settings.get();
input_settings->execution_preference =
MtkNeuronSettings_::ExecutionPreference_PREFERENCE_UNDEFINED;
input_settings->execution_priority =
MtkNeuronSettings_::ExecutionPriority_PRIORITY_MEDIUM;
input_settings->optimization_hints = {
MtkNeuronSettings_::OptimizationHint_OPTIMIZATION_LOW_LATENCY,
MtkNeuronSettings_::OptimizationHint_OPTIMIZATION_BATCH_PROCESSING};
input_settings->operation_check_mode =
MtkNeuronSettings_::OperationCheckMode_PER_NODE_OPERATION_CHECK;
input_settings->allow_fp16_precision_for_fp32 = true;
input_settings->use_ahwb = false;
input_settings->use_cacheable_buffer = true;
input_settings->compile_options = {"TEST_COMPILE_OPTIONS"};
input_settings->accelerator_names = {"TEST_ACCELERATOR_NAME"};
input_settings->neuron_config_path = "TEST_NEURON_CONFIG_PATH";
input_settings->inference_deadline_ms = 1337;
input_settings->inference_abort_time_ms = 42;
const proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
const proto::MtkNeuronSettings& output_settings =
compute.tflite_settings().mtk_neuron_settings();
EXPECT_EQ(output_settings.execution_preference(),
proto::MtkNeuronSettings::PREFERENCE_UNDEFINED);
EXPECT_EQ(output_settings.execution_priority(),
proto::MtkNeuronSettings::PRIORITY_MEDIUM);
EXPECT_EQ(output_settings.optimization_hints().size(), 2);
EXPECT_EQ(output_settings.optimization_hints().at(0),
proto::MtkNeuronSettings::OPTIMIZATION_LOW_LATENCY);
EXPECT_EQ(output_settings.optimization_hints().at(1),
proto::MtkNeuronSettings::OPTIMIZATION_BATCH_PROCESSING);
EXPECT_EQ(output_settings.operation_check_mode(),
proto::MtkNeuronSettings::PER_NODE_OPERATION_CHECK);
EXPECT_TRUE(output_settings.allow_fp16_precision_for_fp32());
EXPECT_FALSE(output_settings.use_ahwb());
EXPECT_TRUE(output_settings.use_cacheable_buffer());
EXPECT_EQ(output_settings.compile_options().size(), 1);
EXPECT_EQ(output_settings.compile_options().at(0), "TEST_COMPILE_OPTIONS");
EXPECT_EQ(output_settings.accelerator_names().size(), 1);
EXPECT_EQ(output_settings.accelerator_names().at(0), "TEST_ACCELERATOR_NAME");
EXPECT_EQ(output_settings.neuron_config_path(), "TEST_NEURON_CONFIG_PATH");
EXPECT_EQ(output_settings.inference_deadline_ms(), 1337);
EXPECT_EQ(output_settings.inference_abort_time_ms(), 42);
}
TEST_F(ConversionTest, MiniBenchmarkSettings) {
settings_.tflite_settings = std::make_unique<TFLiteSettingsT>();
settings_.tflite_settings->cpu_settings = std::make_unique<CPUSettingsT>();
settings_.tflite_settings->cpu_settings->num_threads = 2;
settings_.model_identifier_for_statistics = "id";
settings_.model_namespace_for_statistics = "ns";
settings_.settings_to_test_locally =
std::make_unique<MinibenchmarkSettingsT>();
MinibenchmarkSettingsT* mini_settings =
settings_.settings_to_test_locally.get();
mini_settings->model_file = std::make_unique<ModelFileT>();
mini_settings->model_file->filename = "test_model";
mini_settings->storage_paths = std::make_unique<BenchmarkStoragePathsT>();
mini_settings->storage_paths->storage_file_path = "/data/local/tmp";
std::unique_ptr<TFLiteSettingsT> xnnpack(new TFLiteSettingsT());
xnnpack->xnnpack_settings = std::make_unique<XNNPackSettingsT>();
xnnpack->xnnpack_settings->num_threads = 2;
std::unique_ptr<TFLiteSettingsT> hexagon(new TFLiteSettingsT());
hexagon->hexagon_settings = std::make_unique<HexagonSettingsT>();
hexagon->hexagon_settings->powersave_level = 3;
std::unique_ptr<TFLiteSettingsT> coreml(new TFLiteSettingsT());
coreml->coreml_settings = std::make_unique<CoreMLSettingsT>();
coreml->coreml_settings->enabled_devices =
CoreMLSettings_::EnabledDevices_DEVICES_WITH_NEURAL_ENGINE;
coreml->coreml_settings->coreml_version = 3;
coreml->coreml_settings->max_delegated_partitions = 10;
coreml->coreml_settings->min_nodes_per_partition = 4;
mini_settings->settings_to_test.emplace_back(std::move(xnnpack));
mini_settings->settings_to_test.emplace_back(std::move(hexagon));
mini_settings->settings_to_test.emplace_back(std::move(coreml));
proto::ComputeSettings compute = ConvertFromFlatbuffer(settings_);
EXPECT_EQ(2, compute.tflite_settings().cpu_settings().num_threads());
EXPECT_EQ("id", compute.model_identifier_for_statistics());
EXPECT_EQ("ns", compute.model_namespace_for_statistics());
EXPECT_TRUE(compute.has_settings_to_test_locally());
const proto::MinibenchmarkSettings& mini_output =
compute.settings_to_test_locally();
EXPECT_EQ("test_model", mini_output.model_file().filename());
EXPECT_EQ("/data/local/tmp", mini_output.storage_paths().storage_file_path());
EXPECT_EQ(3, mini_output.settings_to_test_size());
EXPECT_EQ(
2, mini_output.settings_to_test().at(0).xnnpack_settings().num_threads());
EXPECT_EQ(3, mini_output.settings_to_test()
.at(1)
.hexagon_settings()
.powersave_level());
EXPECT_EQ(
proto::CoreMLSettings::DEVICES_WITH_NEURAL_ENGINE,
mini_output.settings_to_test().at(2).coreml_settings().enabled_devices());
EXPECT_EQ(
3,
mini_output.settings_to_test().at(2).coreml_settings().coreml_version());
EXPECT_EQ(10, mini_output.settings_to_test()
.at(2)
.coreml_settings()
.max_delegated_partitions());
EXPECT_EQ(4, mini_output.settings_to_test()
.at(2)
.coreml_settings()
.min_nodes_per_partition());
compute =
ConvertFromFlatbuffer(settings_, /*skip_mini_benchmark_settings=*/true);
EXPECT_EQ(2, compute.tflite_settings().cpu_settings().num_threads());
EXPECT_EQ("id", compute.model_identifier_for_statistics());
EXPECT_EQ("ns", compute.model_namespace_for_statistics());
EXPECT_FALSE(compute.has_settings_to_test_locally());
}
TEST_F(ConversionTest, BestAccelerationDecisionEvent) {
event_.is_log_flushing_event = true;
event_.best_acceleration_decision =
std::make_unique<BestAccelerationDecisionT>();
event_.best_acceleration_decision->number_of_source_events = 4;
event_.best_acceleration_decision->min_inference_time_us = 3000;
proto::MiniBenchmarkEvent proto_event = ConvertFromFlatbuffer(event_);
EXPECT_TRUE(proto_event.is_log_flushing_event());
const auto& best_decision = proto_event.best_acceleration_decision();
EXPECT_EQ(4, best_decision.number_of_source_events());
EXPECT_EQ(3000, best_decision.min_inference_time_us());
EXPECT_FALSE(best_decision.has_min_latency_event());
event_.best_acceleration_decision->min_latency_event =
std::make_unique<BenchmarkEventT>();
auto* min_event = event_.best_acceleration_decision->min_latency_event.get();
min_event->event_type = BenchmarkEventType_END;
min_event->tflite_settings = std::make_unique<TFLiteSettingsT>();
min_event->tflite_settings->delegate = Delegate_XNNPACK;
min_event->tflite_settings->xnnpack_settings =
std::make_unique<XNNPackSettingsT>();
min_event->tflite_settings->xnnpack_settings->num_threads = 2;
min_event->result = std::make_unique<BenchmarkResultT>();
min_event->result->initialization_time_us.push_back(100);
min_event->result->initialization_time_us.push_back(110);
min_event->result->inference_time_us.push_back(3000);
min_event->result->inference_time_us.push_back(3500);
min_event->result->max_memory_kb = 1234;
min_event->result->ok = true;
min_event->boottime_us = 1111;
min_event->wallclock_us = 2222;
proto_event = ConvertFromFlatbuffer(event_);
EXPECT_TRUE(proto_event.best_acceleration_decision().has_min_latency_event());
const auto& proto_min_event =
proto_event.best_acceleration_decision().min_latency_event();
EXPECT_EQ(proto::BenchmarkEventType::END, proto_min_event.event_type());
EXPECT_EQ(proto::Delegate::XNNPACK,
proto_min_event.tflite_settings().delegate());
EXPECT_EQ(2,
proto_min_event.tflite_settings().xnnpack_settings().num_threads());
EXPECT_TRUE(proto_min_event.has_result());
EXPECT_EQ(2, proto_min_event.result().initialization_time_us_size());
EXPECT_EQ(100, proto_min_event.result().initialization_time_us()[0]);
EXPECT_EQ(110, proto_min_event.result().initialization_time_us()[1]);
EXPECT_EQ(2, proto_min_event.result().inference_time_us_size());
EXPECT_EQ(3000, proto_min_event.result().inference_time_us()[0]);
EXPECT_EQ(3500, proto_min_event.result().inference_time_us()[1]);
EXPECT_EQ(1234, proto_min_event.result().max_memory_kb());
EXPECT_TRUE(proto_min_event.result().ok());
EXPECT_EQ(1111, proto_min_event.boottime_us());
EXPECT_EQ(2222, proto_min_event.wallclock_us());
}
TEST_F(ConversionTest, BenchmarkInitializationEvent) {
event_.initialization_failure =
std::make_unique<BenchmarkInitializationFailureT>();
event_.initialization_failure->initialization_status = 101;
proto::MiniBenchmarkEvent proto_event = ConvertFromFlatbuffer(event_);
EXPECT_FALSE(proto_event.is_log_flushing_event());
EXPECT_EQ(101, proto_event.initialization_failure().initialization_status());
}
TEST_F(ConversionTest, BenchmarkError) {
event_.benchmark_event = std::make_unique<BenchmarkEventT>();
event_.benchmark_event->error = std::make_unique<BenchmarkErrorT>();
auto* error = event_.benchmark_event->error.get();
error->stage = BenchmarkStage_INITIALIZATION;
error->exit_code = 123;
error->signal = 321;
error->mini_benchmark_error_code = 456;
std::unique_ptr<ErrorCodeT> code1(new ErrorCodeT());
code1->source = Delegate_EDGETPU;
code1->tflite_error = 3;
code1->underlying_api_error = 301;
error->error_code.emplace_back(std::move(code1));
std::unique_ptr<ErrorCodeT> code2(new ErrorCodeT());
code2->source = Delegate_NNAPI;
code2->tflite_error = 4;
code2->underlying_api_error = 404;
error->error_code.emplace_back(std::move(code2));
const proto::MiniBenchmarkEvent proto_event = ConvertFromFlatbuffer(event_);
const auto& proto_error = proto_event.benchmark_event().error();
EXPECT_EQ(proto::BenchmarkStage::INITIALIZATION, proto_error.stage());
EXPECT_EQ(123, proto_error.exit_code());
EXPECT_EQ(321, proto_error.signal());
EXPECT_EQ(456, proto_error.mini_benchmark_error_code());
EXPECT_EQ(2, proto_error.error_code_size());
EXPECT_EQ(proto::Delegate::EDGETPU, proto_error.error_code()[0].source());
EXPECT_EQ(3, proto_error.error_code()[0].tflite_error());
EXPECT_EQ(301, proto_error.error_code()[0].underlying_api_error());
EXPECT_EQ(proto::Delegate::NNAPI, proto_error.error_code()[1].source());
EXPECT_EQ(4, proto_error.error_code()[1].tflite_error());
EXPECT_EQ(404, proto_error.error_code()[1].underlying_api_error());
}
TEST_F(ConversionTest, BenchmarkMetric) {
event_.benchmark_event = std::make_unique<BenchmarkEventT>();
event_.benchmark_event->result = std::make_unique<BenchmarkResultT>();
std::unique_ptr<BenchmarkMetricT> metric(new BenchmarkMetricT());
metric->name = "test";
metric->values.push_back(1.234);
metric->values.push_back(5.678);
event_.benchmark_event->result->metrics.emplace_back(std::move(metric));
const proto::MiniBenchmarkEvent proto_event = ConvertFromFlatbuffer(event_);
EXPECT_EQ(1, proto_event.benchmark_event().result().metrics_size());
const auto& proto_metric =
proto_event.benchmark_event().result().metrics()[0];
EXPECT_EQ("test", proto_metric.name());
EXPECT_EQ(2, proto_metric.values_size());
EXPECT_FLOAT_EQ(1.234, proto_metric.values()[0]);
EXPECT_FLOAT_EQ(5.678, proto_metric.values()[1]);
}
} // namespace
} // namespace acceleration
} // namespace tflite
@@ -0,0 +1,165 @@
/* 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/acceleration/configuration/gpu_plugin.h"
#include <memory>
#include <string>
#include "absl/memory/memory.h"
namespace tflite {
namespace delegates {
int GpuPlugin::GetDelegateErrno(TfLiteDelegate* from_delegate) { return 0; }
std::unique_ptr<DelegatePluginInterface> GpuPlugin::New(
const TFLiteSettings& acceleration) {
return std::make_unique<GpuPlugin>(acceleration);
}
#if TFLITE_SUPPORTS_GPU_DELEGATE
namespace {
TfLiteGpuInferencePriority ConvertInferencePriority(
GPUInferencePriority priority) {
switch (priority) {
case GPUInferencePriority_GPU_PRIORITY_AUTO:
return TFLITE_GPU_INFERENCE_PRIORITY_AUTO;
case GPUInferencePriority_GPU_PRIORITY_MAX_PRECISION:
return TFLITE_GPU_INFERENCE_PRIORITY_MAX_PRECISION;
case GPUInferencePriority_GPU_PRIORITY_MIN_LATENCY:
return TFLITE_GPU_INFERENCE_PRIORITY_MIN_LATENCY;
case GPUInferencePriority_GPU_PRIORITY_MIN_MEMORY_USAGE:
return TFLITE_GPU_INFERENCE_PRIORITY_MIN_MEMORY_USAGE;
}
}
std::string GetCacheDirImpl(const TFLiteSettings& tflite_settings) {
if (tflite_settings.compilation_caching_settings() &&
tflite_settings.compilation_caching_settings()->cache_dir() &&
tflite_settings.compilation_caching_settings()->cache_dir()->size() > 0) {
return tflite_settings.compilation_caching_settings()->cache_dir()->str();
} else if (tflite_settings.gpu_settings() &&
tflite_settings.gpu_settings()->cache_directory() &&
tflite_settings.gpu_settings()->cache_directory()->size() > 0) {
return tflite_settings.gpu_settings()->cache_directory()->str();
} else {
return "";
}
}
std::string GetModelTokenImpl(const TFLiteSettings& tflite_settings) {
if (tflite_settings.compilation_caching_settings() &&
tflite_settings.compilation_caching_settings()->model_token() &&
tflite_settings.compilation_caching_settings()->model_token()->size() >
0) {
return tflite_settings.compilation_caching_settings()->model_token()->str();
} else if (tflite_settings.gpu_settings() &&
tflite_settings.gpu_settings()->model_token() &&
tflite_settings.gpu_settings()->model_token()->size()) {
return tflite_settings.gpu_settings()->model_token()->str();
} else {
return "";
}
}
} // namespace
TfLiteDelegatePtr GpuPlugin::Create() {
return TfLiteDelegatePtr(TfLiteGpuDelegateV2Create(&options_),
TfLiteGpuDelegateV2Delete);
}
GpuPlugin::GpuPlugin(const TFLiteSettings& tflite_settings)
: options_(TfLiteGpuDelegateOptionsV2Default()) {
if (tflite_settings.max_delegated_partitions() >= 0) {
options_.max_delegated_partitions =
tflite_settings.max_delegated_partitions();
}
const auto* gpu_settings = tflite_settings.gpu_settings();
if (!gpu_settings) return;
options_.inference_preference = gpu_settings->inference_preference();
if (gpu_settings->inference_priority1() > 0) {
// User has specified their own inference priorities, so just copy over.
options_.inference_priority1 =
ConvertInferencePriority(gpu_settings->inference_priority1());
options_.inference_priority2 =
ConvertInferencePriority(gpu_settings->inference_priority2());
options_.inference_priority3 =
ConvertInferencePriority(gpu_settings->inference_priority3());
} else {
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;
}
const std::string cache_dir = GetCacheDirImpl(tflite_settings);
const std::string model_token = GetModelTokenImpl(tflite_settings);
if (!cache_dir.empty() && !model_token.empty()) {
cache_dir_ = cache_dir;
model_token_ = model_token;
options_.serialization_dir = cache_dir_.c_str();
options_.model_token = model_token_.c_str();
options_.experimental_flags |=
TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION;
}
}
#elif defined(REAL_IPHONE_DEVICE)
TfLiteDelegatePtr GpuPlugin::Create() {
return TfLiteDelegatePtr(TFLGpuDelegateCreate(&options_),
&TFLGpuDelegateDelete);
}
GpuPlugin::GpuPlugin(const TFLiteSettings& tflite_settings) {
options_ = {0};
const auto* gpu_settings = tflite_settings.gpu_settings();
if (!gpu_settings) return;
options_.allow_precision_loss = gpu_settings->is_precision_loss_allowed();
options_.enable_quantization = gpu_settings->enable_quantized_inference();
}
#else
TfLiteDelegatePtr GpuPlugin::Create() {
return TfLiteDelegatePtr(nullptr, [](TfLiteDelegate*) {});
}
// In case GPU acceleration is not supported for this platform, we still need to
// construct an empty object so that Create() can later be called on it.
GpuPlugin::GpuPlugin(const TFLiteSettings& tflite_settings) {}
#endif
TFLITE_REGISTER_DELEGATE_FACTORY_FUNCTION(GpuPlugin, GpuPlugin::New);
} // namespace delegates
} // namespace tflite
@@ -0,0 +1,79 @@
/* Copyright 2021 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_ACCELERATION_CONFIGURATION_GPU_PLUGIN_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_GPU_PLUGIN_H_
// This file provides the GpuPlugin class, which implements the
// TFLite Delegate Plugin for the GPU Delegate.
#if defined(__ANDROID__) || defined(CL_DELEGATE_NO_GL)
#define TFLITE_SUPPORTS_GPU_DELEGATE 1
#endif
#include <string>
#if TFLITE_SUPPORTS_GPU_DELEGATE
#include "tensorflow/lite/delegates/gpu/delegate.h"
#elif defined(__APPLE__)
#include "TargetConditionals.h"
#if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) || \
(TARGET_OS_OSX && TARGET_CPU_ARM64)
// Only enable metal delegate when using a real iPhone device or Apple Silicon.
#define REAL_IPHONE_DEVICE
#include "tensorflow/lite/delegates/gpu/metal_delegate.h"
#endif
#endif
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/core/acceleration/configuration/delegate_registry.h"
namespace tflite {
namespace delegates {
// Note that if running on GPU is not supported for some reason (e.g., desktop
// machine with no OpenGL/CL), this library will still compile but calling
// Create() will return a nullptr.
class GpuPlugin : public DelegatePluginInterface {
public:
explicit GpuPlugin(const TFLiteSettings& tflite_settings);
static std::unique_ptr<DelegatePluginInterface> New(
const TFLiteSettings& acceleration);
TfLiteDelegatePtr Create() override;
int GetDelegateErrno(TfLiteDelegate* from_delegate) override;
#if TFLITE_SUPPORTS_GPU_DELEGATE
const TfLiteGpuDelegateOptionsV2& Options() { return options_; }
#elif defined(REAL_IPHONE_DEVICE)
const TFLGpuDelegateOptions& Options() { return options_; }
#endif
std::string GetCacheDir() const { return cache_dir_; }
std::string GetModelToken() const { return model_token_; }
private:
#if TFLITE_SUPPORTS_GPU_DELEGATE
TfLiteGpuDelegateOptionsV2 options_;
#elif defined(REAL_IPHONE_DEVICE)
TFLGpuDelegateOptions options_;
#endif
std::string cache_dir_;
std::string model_token_;
};
} // namespace delegates
} // namespace tflite
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_GPU_PLUGIN_H_
@@ -0,0 +1,209 @@
/* Copyright 2022 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/acceleration/configuration/gpu_plugin.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "flatbuffers/flatbuffers.h" // from @flatbuffers
#include "tensorflow/lite/acceleration/configuration/configuration.pb.h"
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/acceleration/configuration/proto_to_flatbuffer.h"
#include "tensorflow/lite/core/acceleration/configuration/delegate_registry.h"
namespace tflite {
namespace delegates {
namespace {
#if TFLITE_SUPPORTS_GPU_DELEGATE || defined(REAL_IPHONE_DEVICE)
// While we could easily move the preprocessor lines around the expect part, we
// prefer to have two separate tests so it's clear which test is being
// exercised.
TEST(GpuPluginTest, GpuIsSupported) {
flatbuffers::FlatBufferBuilder fbb;
tflite::proto::ComputeSettings compute_settings;
compute_settings.mutable_tflite_settings()->set_delegate(
tflite::proto::Delegate::GPU);
const tflite::ComputeSettings* compute_settings_fb =
tflite::ConvertFromProto(compute_settings, &fbb);
TfLiteDelegatePtr gpu_delegate =
DelegatePluginRegistry::CreateByName(
"GpuPlugin", *compute_settings_fb->tflite_settings())
->Create();
EXPECT_NE(gpu_delegate, nullptr);
}
TEST(GpuPluginTest, CachingFieldsMissing) {
flatbuffers::FlatBufferBuilder fbb;
tflite::proto::ComputeSettings compute_settings;
compute_settings.mutable_tflite_settings()->set_delegate(
tflite::proto::Delegate::GPU);
const tflite::ComputeSettings* compute_settings_fb =
tflite::ConvertFromProto(compute_settings, &fbb);
GpuPlugin gpu_plugin(*compute_settings_fb->tflite_settings());
EXPECT_TRUE(gpu_plugin.GetCacheDir().empty());
EXPECT_TRUE(gpu_plugin.GetModelToken().empty());
}
TEST(GpuPluginTest, CompilationCachingFieldsSourcedFromGpuSettings) {
flatbuffers::FlatBufferBuilder fbb;
auto gpu_settings_cache_dir = fbb.CreateString("gpu_settings_cache_dir");
auto gpu_settings_model_token = fbb.CreateString("gpu_settings_model_token");
GPUSettingsBuilder gpu_settings_builder(fbb);
gpu_settings_builder.add_cache_directory(gpu_settings_cache_dir);
gpu_settings_builder.add_model_token(gpu_settings_model_token);
auto gpu_settings = gpu_settings_builder.Finish();
TFLiteSettingsBuilder tflite_settings_builder(fbb);
tflite_settings_builder.add_gpu_settings(gpu_settings);
auto tflite_settings = tflite_settings_builder.Finish();
fbb.Finish(tflite_settings);
auto tflite_settings_root =
flatbuffers::GetRoot<TFLiteSettings>(fbb.GetBufferPointer());
GpuPlugin gpu_plugin(*tflite_settings_root);
EXPECT_STREQ("gpu_settings_cache_dir", gpu_plugin.GetCacheDir().c_str());
EXPECT_STREQ("gpu_settings_model_token", gpu_plugin.GetModelToken().c_str());
}
TEST(GpuPluginTest,
CacheDirFromCompilationSettingsAndModelTokenFromGpuSettings) {
flatbuffers::FlatBufferBuilder fbb;
auto gpu_settings_cache_dir = fbb.CreateString("gpu_settings_cache_dir");
auto gpu_settings_model_token = fbb.CreateString("gpu_settings_model_token");
GPUSettingsBuilder gpu_settings_builder(fbb);
gpu_settings_builder.add_cache_directory(gpu_settings_cache_dir);
gpu_settings_builder.add_model_token(gpu_settings_model_token);
auto gpu_settings = gpu_settings_builder.Finish();
auto compilation_caching_dir =
fbb.CreateString("top_level_compilation_caching_dir");
CompilationCachingSettingsBuilder compilation_caching_settings_builder(fbb);
compilation_caching_settings_builder.add_cache_dir(compilation_caching_dir);
auto compilation_caching_settings =
compilation_caching_settings_builder.Finish();
TFLiteSettingsBuilder tflite_settings_builder(fbb);
tflite_settings_builder.add_gpu_settings(gpu_settings);
tflite_settings_builder.add_compilation_caching_settings(
compilation_caching_settings);
auto tflite_settings = tflite_settings_builder.Finish();
fbb.Finish(tflite_settings);
auto tflite_settings_root =
flatbuffers::GetRoot<TFLiteSettings>(fbb.GetBufferPointer());
GpuPlugin gpu_plugin(*tflite_settings_root);
EXPECT_STREQ("top_level_compilation_caching_dir",
gpu_plugin.GetCacheDir().c_str());
EXPECT_STREQ("gpu_settings_model_token", gpu_plugin.GetModelToken().c_str());
}
TEST(GpuPluginTest,
ModelTokenFromCompilationSettingsAndCacheDirFromGpuSettings) {
flatbuffers::FlatBufferBuilder fbb;
auto gpu_settings_cache_dir = fbb.CreateString("gpu_settings_cache_dir");
auto gpu_settings_model_token = fbb.CreateString("gpu_settings_model_token");
GPUSettingsBuilder gpu_settings_builder(fbb);
gpu_settings_builder.add_cache_directory(gpu_settings_cache_dir);
gpu_settings_builder.add_model_token(gpu_settings_model_token);
auto gpu_settings = gpu_settings_builder.Finish();
auto top_level_compilation_model_token =
fbb.CreateString("top_level_compilation_model_token");
CompilationCachingSettingsBuilder compilation_caching_settings_builder(fbb);
compilation_caching_settings_builder.add_model_token(
top_level_compilation_model_token);
auto compilation_caching_settings =
compilation_caching_settings_builder.Finish();
TFLiteSettingsBuilder tflite_settings_builder(fbb);
tflite_settings_builder.add_gpu_settings(gpu_settings);
tflite_settings_builder.add_compilation_caching_settings(
compilation_caching_settings);
auto tflite_settings = tflite_settings_builder.Finish();
fbb.Finish(tflite_settings);
auto tflite_settings_root =
flatbuffers::GetRoot<TFLiteSettings>(fbb.GetBufferPointer());
GpuPlugin gpu_plugin(*tflite_settings_root);
EXPECT_STREQ("gpu_settings_cache_dir", gpu_plugin.GetCacheDir().c_str());
EXPECT_STREQ("top_level_compilation_model_token",
gpu_plugin.GetModelToken().c_str());
}
TEST(GpuPluginTest, CacheDirAndModelTokenCompilationSettings) {
flatbuffers::FlatBufferBuilder fbb;
auto gpu_settings_cache_dir = fbb.CreateString("gpu_settings_cache_dir");
auto gpu_settings_model_token = fbb.CreateString("gpu_settings_model_token");
GPUSettingsBuilder gpu_settings_builder(fbb);
gpu_settings_builder.add_cache_directory(gpu_settings_cache_dir);
gpu_settings_builder.add_model_token(gpu_settings_model_token);
auto gpu_settings = gpu_settings_builder.Finish();
auto top_level_compilation_model_token =
fbb.CreateString("top_level_compilation_model_token");
auto compilation_caching_dir =
fbb.CreateString("top_level_compilation_caching_dir");
CompilationCachingSettingsBuilder compilation_caching_settings_builder(fbb);
compilation_caching_settings_builder.add_cache_dir(compilation_caching_dir);
compilation_caching_settings_builder.add_model_token(
top_level_compilation_model_token);
auto compilation_caching_settings =
compilation_caching_settings_builder.Finish();
TFLiteSettingsBuilder tflite_settings_builder(fbb);
tflite_settings_builder.add_gpu_settings(gpu_settings);
tflite_settings_builder.add_compilation_caching_settings(
compilation_caching_settings);
auto tflite_settings = tflite_settings_builder.Finish();
fbb.Finish(tflite_settings);
auto tflite_settings_root =
flatbuffers::GetRoot<TFLiteSettings>(fbb.GetBufferPointer());
GpuPlugin gpu_plugin(*tflite_settings_root);
EXPECT_STREQ("top_level_compilation_caching_dir",
gpu_plugin.GetCacheDir().c_str());
EXPECT_STREQ("top_level_compilation_model_token",
gpu_plugin.GetModelToken().c_str());
}
#else
TEST(GpuPluginTest, GpuNotSupported) {
flatbuffers::FlatBufferBuilder fbb;
tflite::proto::ComputeSettings compute_settings;
compute_settings.mutable_tflite_settings()->set_delegate(
tflite::proto::Delegate::GPU);
const tflite::ComputeSettings* compute_settings_fb =
tflite::ConvertFromProto(compute_settings, &fbb);
TfLiteDelegatePtr gpu_delegate =
DelegatePluginRegistry::CreateByName(
"GpuPlugin", *compute_settings_fb->tflite_settings())
->Create();
EXPECT_EQ(gpu_delegate, nullptr);
}
#endif
} // namespace
} // namespace delegates
} // namespace tflite
@@ -0,0 +1,77 @@
/* 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/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/core/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 std::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();
if (tflite_settings.max_delegated_partitions() >= 0) {
options_.max_delegated_partitions =
tflite_settings.max_delegated_partitions();
}
}
#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,26 @@
#!/bin/bash
# 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.
set -o nounset
set -o errexit
readonly DIR_PREFIX="third_party/tensorflow/lite/acceleration/configuration"
readonly CURRENT_PROTO="$DIR_PREFIX/configuration.proto"
readonly PREV_PROTO="$DIR_PREFIX/testdata/configuration.proto_prev"
diff -u $PREV_PROTO $CURRENT_PROTO &&
die "Current proto should be different than prev proto"
echo "PASS"
@@ -0,0 +1,528 @@
/* 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/acceleration/configuration/proto_to_flatbuffer.h"
#include <cstdint>
#include <vector>
#include "flatbuffers/buffer.h" // from @flatbuffers
#include "flatbuffers/flatbuffers.h" // from @flatbuffers
#include "tensorflow/lite/acceleration/configuration/configuration.pb.h"
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/minimal_logging.h"
namespace tflite {
using ::flatbuffers::FlatBufferBuilder;
using ::flatbuffers::Offset;
using ::flatbuffers::String;
using ::flatbuffers::Vector;
ExecutionPreference ConvertExecutionPreference(
proto::ExecutionPreference preference) {
switch (preference) {
case proto::ExecutionPreference::ANY:
return ExecutionPreference_ANY;
case proto::ExecutionPreference::LOW_LATENCY:
return ExecutionPreference_LOW_LATENCY;
case proto::ExecutionPreference::LOW_POWER:
return ExecutionPreference_LOW_POWER;
case proto::ExecutionPreference::FORCE_CPU:
return ExecutionPreference_FORCE_CPU;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for ExecutionPreference: %d", preference);
return ExecutionPreference_ANY;
}
Delegate ConvertDelegate(proto::Delegate delegate) {
switch (delegate) {
case proto::Delegate::NONE:
return Delegate_NONE;
case proto::Delegate::NNAPI:
return Delegate_NNAPI;
case proto::Delegate::GPU:
return Delegate_GPU;
case proto::Delegate::HEXAGON:
return Delegate_HEXAGON;
case proto::Delegate::XNNPACK:
return Delegate_XNNPACK;
case proto::Delegate::EDGETPU:
return Delegate_EDGETPU;
case proto::Delegate::EDGETPU_CORAL:
return Delegate_EDGETPU_CORAL;
case proto::Delegate::CORE_ML:
return Delegate_CORE_ML;
case proto::Delegate::ARMNN:
return Delegate_ARMNN;
case proto::Delegate::MTK_NEURON:
return Delegate_MTK_NEURON;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Unexpected value for Delegate: %d",
delegate);
return Delegate_NONE;
}
NNAPIExecutionPreference ConvertNNAPIExecutionPreference(
proto::NNAPIExecutionPreference preference) {
switch (preference) {
case proto::NNAPIExecutionPreference::UNDEFINED:
return NNAPIExecutionPreference_UNDEFINED;
case proto::NNAPIExecutionPreference::NNAPI_LOW_POWER:
return NNAPIExecutionPreference_NNAPI_LOW_POWER;
case proto::NNAPIExecutionPreference::NNAPI_FAST_SINGLE_ANSWER:
return NNAPIExecutionPreference_NNAPI_FAST_SINGLE_ANSWER;
case proto::NNAPIExecutionPreference::NNAPI_SUSTAINED_SPEED:
return NNAPIExecutionPreference_NNAPI_SUSTAINED_SPEED;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for NNAPIExecutionPreference: %d",
preference);
return NNAPIExecutionPreference_UNDEFINED;
}
NNAPIExecutionPriority ConvertNNAPIExecutionPriority(
proto::NNAPIExecutionPriority priority) {
switch (priority) {
case proto::NNAPIExecutionPriority::NNAPI_PRIORITY_UNDEFINED:
return NNAPIExecutionPriority_NNAPI_PRIORITY_UNDEFINED;
case proto::NNAPIExecutionPriority::NNAPI_PRIORITY_LOW:
return NNAPIExecutionPriority_NNAPI_PRIORITY_LOW;
case proto::NNAPIExecutionPriority::NNAPI_PRIORITY_MEDIUM:
return NNAPIExecutionPriority_NNAPI_PRIORITY_MEDIUM;
case proto::NNAPIExecutionPriority::NNAPI_PRIORITY_HIGH:
return NNAPIExecutionPriority_NNAPI_PRIORITY_HIGH;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for NNAPIExecutionPriority: %d", priority);
return NNAPIExecutionPriority_NNAPI_PRIORITY_UNDEFINED;
}
GPUBackend ConvertGPUBackend(proto::GPUBackend backend) {
switch (backend) {
case proto::GPUBackend::UNSET:
return GPUBackend_UNSET;
case proto::GPUBackend::OPENCL:
return GPUBackend_OPENCL;
case proto::GPUBackend::OPENGL:
return GPUBackend_OPENGL;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Unexpected value for GPUBackend: %d",
backend);
return GPUBackend_UNSET;
}
GPUInferenceUsage ConvertGPUInferenceUsage(
proto::GPUInferenceUsage preference) {
switch (preference) {
case proto::GPUInferenceUsage::GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER:
return GPUInferenceUsage_GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER;
case proto::GPUInferenceUsage::GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED:
return GPUInferenceUsage_GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for GPUInferenceUsage: %d", preference);
return GPUInferenceUsage_GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER;
}
GPUInferencePriority ConvertGPUInferencePriority(
proto::GPUInferencePriority priority) {
switch (priority) {
case proto::GPUInferencePriority::GPU_PRIORITY_AUTO:
return GPUInferencePriority_GPU_PRIORITY_AUTO;
case proto::GPUInferencePriority::GPU_PRIORITY_MAX_PRECISION:
return GPUInferencePriority_GPU_PRIORITY_MAX_PRECISION;
case proto::GPUInferencePriority::GPU_PRIORITY_MIN_LATENCY:
return GPUInferencePriority_GPU_PRIORITY_MIN_LATENCY;
case proto::GPUInferencePriority::GPU_PRIORITY_MIN_MEMORY_USAGE:
return GPUInferencePriority_GPU_PRIORITY_MIN_MEMORY_USAGE;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for GPUInferencePriority: %d", priority);
return GPUInferencePriority_GPU_PRIORITY_AUTO;
}
EdgeTpuPowerState ConvertEdgeTpuPowerState(proto::EdgeTpuPowerState state) {
switch (state) {
case proto::EdgeTpuPowerState::UNDEFINED_POWERSTATE:
return EdgeTpuPowerState_UNDEFINED_POWERSTATE;
case proto::EdgeTpuPowerState::TPU_CORE_OFF:
return EdgeTpuPowerState_TPU_CORE_OFF;
case proto::EdgeTpuPowerState::READY:
return EdgeTpuPowerState_READY;
case proto::EdgeTpuPowerState::ACTIVE_MIN_POWER:
return EdgeTpuPowerState_ACTIVE_MIN_POWER;
case proto::EdgeTpuPowerState::ACTIVE_VERY_LOW_POWER:
return EdgeTpuPowerState_ACTIVE_VERY_LOW_POWER;
case proto::EdgeTpuPowerState::ACTIVE_LOW_POWER:
return EdgeTpuPowerState_ACTIVE_LOW_POWER;
case proto::EdgeTpuPowerState::ACTIVE:
return EdgeTpuPowerState_ACTIVE;
case proto::EdgeTpuPowerState::OVER_DRIVE:
return EdgeTpuPowerState_OVER_DRIVE;
}
TFLITE_LOG_PROD(TFLITE_LOG_ERROR,
"Unexpected value for EdgeTpuSettings::PowerState: %d",
state);
return EdgeTpuPowerState_UNDEFINED_POWERSTATE;
}
Offset<FallbackSettings> ConvertFallbackSettings(
const proto::FallbackSettings& settings, FlatBufferBuilder& builder) {
return CreateFallbackSettings(
builder, /*allow_automatic_fallback_on_compilation_error=*/
settings.allow_automatic_fallback_on_compilation_error(),
/*allow_automatic_fallback_on_execution_error=*/
settings.allow_automatic_fallback_on_execution_error());
}
Offset<NNAPISettings> ConvertNNAPISettings(const proto::NNAPISettings& settings,
FlatBufferBuilder& builder) {
return CreateNNAPISettings(
builder,
/*accelerator_name=*/builder.CreateString(settings.accelerator_name()),
/*cache_directory=*/builder.CreateString(settings.cache_directory()),
/*model_token=*/builder.CreateString(settings.model_token()),
ConvertNNAPIExecutionPreference(settings.execution_preference()),
/*no_of_nnapi_instances_to_cache=*/
settings.no_of_nnapi_instances_to_cache(),
ConvertFallbackSettings(settings.fallback_settings(), builder),
/*allow_nnapi_cpu_on_android_10_plus=*/
settings.allow_nnapi_cpu_on_android_10_plus(),
ConvertNNAPIExecutionPriority(settings.execution_priority()),
/*allow_dynamic_dimensions=*/
settings.allow_dynamic_dimensions(),
/*allow_fp16_precision_for_fp32=*/
settings.allow_fp16_precision_for_fp32(),
/*use_burst_computation=*/
settings.use_burst_computation(),
/*support_library_handle=*/
settings.support_library_handle());
}
Offset<GPUSettings> ConvertGPUSettings(const proto::GPUSettings& settings,
FlatBufferBuilder& builder) {
return CreateGPUSettings(
builder,
/*is_precision_loss_allowed=*/settings.is_precision_loss_allowed(),
/*enable_quantized_inference=*/settings.enable_quantized_inference(),
ConvertGPUBackend(settings.force_backend()),
ConvertGPUInferencePriority(settings.inference_priority1()),
ConvertGPUInferencePriority(settings.inference_priority2()),
ConvertGPUInferencePriority(settings.inference_priority3()),
ConvertGPUInferenceUsage(settings.inference_preference()),
/*cache_directory=*/builder.CreateString(settings.cache_directory()),
/*model_token=*/builder.CreateString(settings.model_token()));
}
Offset<HexagonSettings> ConvertHexagonSettings(
const proto::HexagonSettings& settings, FlatBufferBuilder& builder) {
return CreateHexagonSettings(
builder,
/*debug_level=*/settings.debug_level(),
/*powersave_level=*/settings.powersave_level(),
/*print_graph_profile=*/settings.print_graph_profile(),
/*print_graph_debug=*/settings.print_graph_debug());
}
Offset<XNNPackSettings> ConvertXNNPackSettings(
const proto::XNNPackSettings& settings, FlatBufferBuilder& builder) {
return CreateXNNPackSettings(
builder,
/*num_threads=*/settings.num_threads(),
/*flags=*/tflite::XNNPackFlags(settings.flags()));
}
Offset<CoreMLSettings> ConvertCoreMLSettings(
const proto::CoreMLSettings& settings, FlatBufferBuilder& builder) {
tflite::CoreMLSettings_::EnabledDevices enabled_devices =
tflite::CoreMLSettings_::EnabledDevices_DEVICES_ALL;
switch (settings.enabled_devices()) {
case proto::CoreMLSettings::DEVICES_ALL:
enabled_devices = tflite::CoreMLSettings_::EnabledDevices_DEVICES_ALL;
break;
case proto::CoreMLSettings::DEVICES_WITH_NEURAL_ENGINE:
enabled_devices =
tflite::CoreMLSettings_::EnabledDevices_DEVICES_WITH_NEURAL_ENGINE;
break;
default:
TFLITE_LOG_PROD(TFLITE_LOG_ERROR, "Invalid devices enum: %d",
settings.enabled_devices());
}
return CreateCoreMLSettings(
builder, enabled_devices, settings.coreml_version(),
settings.max_delegated_partitions(), settings.min_nodes_per_partition());
}
Offset<StableDelegateLoaderSettings> ConvertStableDelegateLoaderSettings(
const proto::StableDelegateLoaderSettings& settings,
FlatBufferBuilder& builder) {
return CreateStableDelegateLoaderSettings(
builder, builder.CreateString(settings.delegate_path()),
builder.CreateString(settings.delegate_name()));
}
Offset<CPUSettings> ConvertCPUSettings(const proto::CPUSettings& settings,
FlatBufferBuilder& builder) {
return CreateCPUSettings(builder,
/*num_threads=*/settings.num_threads());
}
Offset<tflite::EdgeTpuDeviceSpec> ConvertEdgeTpuDeviceSpec(
FlatBufferBuilder& builder, const proto::EdgeTpuDeviceSpec& device_spec) {
Offset<Vector<Offset<String>>> device_paths_fb = 0;
if (device_spec.device_paths_size() > 0) {
std::vector<Offset<String>> device_paths;
for (const auto& device_path : device_spec.device_paths()) {
auto device_path_fb = builder.CreateString(device_path);
device_paths.push_back(device_path_fb);
}
device_paths_fb = builder.CreateVector(device_paths);
}
return tflite::CreateEdgeTpuDeviceSpec(
builder,
static_cast<tflite::EdgeTpuDeviceSpec_::PlatformType>(
device_spec.platform_type()),
device_spec.num_chips(), device_paths_fb, device_spec.chip_family());
}
Offset<GoogleEdgeTpuSettings> ConvertGoogleEdgeTpuSettings(
const proto::GoogleEdgeTpuSettings& settings, FlatBufferBuilder& builder) {
Offset<String> model_identifier = 0;
if (settings.has_model_identifier()) {
model_identifier = builder.CreateString(settings.model_identifier());
}
Offset<Vector<uint8_t>> extension_data = 0;
if (settings.has_extension_data()) {
extension_data = builder.CreateVector(
reinterpret_cast<const uint8_t*>(settings.extension_data().data()),
settings.extension_data().size());
}
GoogleEdgeTpuSettingsBuilder builder_(builder);
builder_.add_log_verbosity(settings.log_verbosity());
builder_.add_enable_tracing(settings.enable_tracing());
builder_.add_priority(static_cast<tflite::GoogleEdgeTpuSettings_::Priority>(
settings.priority()));
builder_.add_model_identifier(model_identifier);
builder_.add_use_async_api(settings.use_async_api());
builder_.add_delegate_should_manage_cache_for_inputs(
settings.delegate_should_manage_cache_for_inputs());
builder_.add_delegate_should_manage_cache_for_outputs(
settings.delegate_should_manage_cache_for_outputs());
builder_.add_prefer_cache_coherency_for_inputs(
static_cast<tflite::GoogleEdgeTpuSettings_::TriState>(
settings.prefer_cache_coherency_for_inputs()));
builder_.add_prefer_cache_coherency_for_outputs(
static_cast<tflite::GoogleEdgeTpuSettings_::TriState>(
settings.prefer_cache_coherency_for_outputs()));
builder_.add_allow_fp16_precision_for_fp32(
settings.allow_fp16_precision_for_fp32());
builder_.add_extension_data(extension_data);
return builder_.Finish();
}
Offset<EdgeTpuSettings> ConvertEdgeTpuSettings(
const proto::EdgeTpuSettings& settings, FlatBufferBuilder& builder) {
Offset<Vector<Offset<tflite::EdgeTpuInactivePowerConfig>>>
inactive_power_configs = 0;
// Uses std vector to first construct the list and creates the flatbuffer
// offset from it later.
std::vector<Offset<tflite::EdgeTpuInactivePowerConfig>>
inactive_power_configs_std;
if (settings.inactive_power_configs_size() > 0) {
for (const auto& config : settings.inactive_power_configs()) {
inactive_power_configs_std.push_back(
tflite::CreateEdgeTpuInactivePowerConfig(
builder,
static_cast<tflite::EdgeTpuPowerState>(
config.inactive_power_state()),
config.inactive_timeout_us()));
}
inactive_power_configs =
builder.CreateVector<Offset<tflite::EdgeTpuInactivePowerConfig>>(
inactive_power_configs_std);
}
Offset<tflite::EdgeTpuDeviceSpec> edgetpu_device_spec = 0;
if (settings.has_edgetpu_device_spec()) {
edgetpu_device_spec =
ConvertEdgeTpuDeviceSpec(builder, settings.edgetpu_device_spec());
}
Offset<String> model_token = 0;
if (settings.has_model_token()) {
model_token = builder.CreateString(settings.model_token());
}
// First convert to std::vector, then convert to flatbuffer.
std::vector<int32_t> hardware_cluster_ids_std{
settings.hardware_cluster_ids().begin(),
settings.hardware_cluster_ids().end()};
auto hardware_cluster_ids_fb =
builder.CreateVector<int32_t>(hardware_cluster_ids_std);
Offset<String> public_model_id = 0;
if (settings.has_public_model_id()) {
public_model_id = builder.CreateString(settings.public_model_id());
}
return CreateEdgeTpuSettings(
builder, ConvertEdgeTpuPowerState(settings.inference_power_state()),
inactive_power_configs, settings.inference_priority(),
edgetpu_device_spec, model_token,
static_cast<tflite::EdgeTpuSettings_::FloatTruncationType>(
settings.float_truncation_type()),
static_cast<tflite::EdgeTpuSettings_::QosClass>(settings.qos_class()),
hardware_cluster_ids_fb, public_model_id,
static_cast<tflite::EdgeTpuSettings_::UseLayerIrTgcBackend>(
settings.use_layer_ir_tgc_backend()),
settings.use_tpu_server());
}
Offset<CompilationCachingSettings> ConvertCompilationCachingSettings(
const proto::CompilationCachingSettings& settings,
FlatBufferBuilder& builder) {
return CreateCompilationCachingSettings(
builder, builder.CreateString(settings.cache_dir()),
builder.CreateString(settings.model_token()));
}
Offset<ArmNNSettings> ConvertArmNNSettings(const proto::ArmNNSettings& settings,
FlatBufferBuilder& builder) {
return CreateArmNNSettings(
builder, builder.CreateString(settings.backends()), settings.fastmath(),
builder.CreateString(settings.additional_parameters()));
}
Offset<MtkNeuronSettings> ConvertMtkNeuronSettings(
const proto::MtkNeuronSettings& settings, FlatBufferBuilder& builder) {
return CreateMtkNeuronSettings(
builder,
static_cast<MtkNeuronSettings_::ExecutionPreference>(
settings.execution_preference()),
static_cast<MtkNeuronSettings_::ExecutionPriority>(
settings.execution_priority()),
builder.CreateVector(settings.optimization_hints().data(),
settings.optimization_hints().size()),
static_cast<MtkNeuronSettings_::OperationCheckMode>(
settings.operation_check_mode()),
settings.allow_fp16_precision_for_fp32(), settings.use_ahwb(),
settings.use_cacheable_buffer(),
builder.CreateVectorOfStrings(settings.compile_options().begin(),
settings.compile_options().end()),
builder.CreateVectorOfStrings(settings.accelerator_names().begin(),
settings.accelerator_names().end()),
builder.CreateString(settings.neuron_config_path()),
settings.inference_deadline_ms(), settings.inference_abort_time_ms());
}
Offset<CoralSettings> ConvertCoralSettings(const proto::CoralSettings& settings,
FlatBufferBuilder& builder) {
return CreateCoralSettings(
builder, builder.CreateString(settings.device()),
static_cast<tflite::CoralSettings_::Performance>(settings.performance()),
settings.usb_always_dfu(), settings.usb_max_bulk_in_queue_length());
}
Offset<TFLiteSettings> ConvertTfliteSettings(
const proto::TFLiteSettings& settings, FlatBufferBuilder& builder) {
return CreateTFLiteSettings(
builder, ConvertDelegate(settings.delegate()),
ConvertNNAPISettings(settings.nnapi_settings(), builder),
ConvertGPUSettings(settings.gpu_settings(), builder),
ConvertHexagonSettings(settings.hexagon_settings(), builder),
ConvertXNNPackSettings(settings.xnnpack_settings(), builder),
ConvertCoreMLSettings(settings.coreml_settings(), builder),
ConvertCPUSettings(settings.cpu_settings(), builder),
/*max_delegated_partitions=*/settings.max_delegated_partitions(),
ConvertEdgeTpuSettings(settings.edgetpu_settings(), builder),
ConvertCoralSettings(settings.coral_settings(), builder),
ConvertFallbackSettings(settings.fallback_settings(), builder),
settings.disable_default_delegates(),
ConvertStableDelegateLoaderSettings(
settings.stable_delegate_loader_settings(), builder),
ConvertGoogleEdgeTpuSettings(settings.google_edgetpu_settings(), builder),
ConvertCompilationCachingSettings(settings.compilation_caching_settings(),
builder),
ConvertArmNNSettings(settings.armnn_settings(), builder),
ConvertMtkNeuronSettings(settings.mtk_neuron_settings(), builder));
}
Offset<ModelFile> ConvertModelFile(const proto::ModelFile& model_file,
FlatBufferBuilder& builder) {
return CreateModelFile(builder, builder.CreateString(model_file.filename()),
model_file.fd(), model_file.offset(),
model_file.length());
}
Offset<BenchmarkStoragePaths> ConvertBenchmarkStoragePaths(
const proto::BenchmarkStoragePaths& storage_paths,
FlatBufferBuilder& builder) {
return CreateBenchmarkStoragePaths(
builder, builder.CreateString(storage_paths.storage_file_path()),
builder.CreateString(storage_paths.data_directory_path()));
}
Offset<MinibenchmarkSettings> ConvertMinibenchmarkSettings(
const proto::MinibenchmarkSettings& settings, FlatBufferBuilder& builder) {
Offset<Vector<Offset<TFLiteSettings>>> settings_to_test = 0;
std::vector<Offset<TFLiteSettings>> settings_to_test_vec;
if (settings.settings_to_test_size() > 0) {
for (const auto& one : settings.settings_to_test()) {
settings_to_test_vec.push_back(ConvertTfliteSettings(one, builder));
}
settings_to_test =
builder.CreateVector<Offset<TFLiteSettings>>(settings_to_test_vec);
}
return CreateMinibenchmarkSettings(
builder, settings_to_test,
ConvertModelFile(settings.model_file(), builder),
ConvertBenchmarkStoragePaths(settings.storage_paths(), builder));
}
const TFLiteSettings* ConvertFromProto(
const proto::TFLiteSettings& proto_settings, FlatBufferBuilder* builder) {
Offset<TFLiteSettings> settings =
ConvertTfliteSettings(proto_settings, *builder);
return flatbuffers::GetTemporaryPointer(*builder, settings);
}
const ComputeSettings* ConvertFromProto(
const proto::ComputeSettings& proto_settings, FlatBufferBuilder* builder) {
auto settings = CreateComputeSettings(
*builder, ConvertExecutionPreference(proto_settings.preference()),
ConvertTfliteSettings(proto_settings.tflite_settings(), *builder),
builder->CreateString(proto_settings.model_namespace_for_statistics()),
builder->CreateString(proto_settings.model_identifier_for_statistics()),
ConvertMinibenchmarkSettings(proto_settings.settings_to_test_locally(),
*builder));
return flatbuffers::GetTemporaryPointer(*builder, settings);
}
const MinibenchmarkSettings* ConvertFromProto(
const proto::MinibenchmarkSettings& proto_settings,
flatbuffers::FlatBufferBuilder* builder) {
auto settings = ConvertMinibenchmarkSettings(proto_settings, *builder);
return flatbuffers::GetTemporaryPointer(*builder, settings);
}
} // namespace tflite
@@ -0,0 +1,47 @@
/* 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_ACCELERATION_CONFIGURATION_PROTO_TO_FLATBUFFER_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_PROTO_TO_FLATBUFFER_H_
#include "flatbuffers/flatbuffers.h" // from @flatbuffers
#include "tensorflow/lite/acceleration/configuration/configuration.pb.h"
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
namespace tflite {
// Converts the provided TFLiteSettings from proto to flatbuffer format.
// The returned TFLiteSettings pointer is only valid until either the
// FlatBufferBuilder is modified or when the FlatBufferBuilder's lifetime ends.
const TFLiteSettings* ConvertFromProto(
const proto::TFLiteSettings& proto_settings,
flatbuffers::FlatBufferBuilder* builder);
// Converts the provided ComputeSettings from proto to flatbuffer format.
// The returned ComputeSettings pointer is only valid until either the
// FlatBufferBuilder is modified or when the FlatBufferBuilder's lifetime ends.
const ComputeSettings* ConvertFromProto(
const proto::ComputeSettings& proto_settings,
flatbuffers::FlatBufferBuilder* builder);
// Converts the provided MiniBenchmarkSettings from proto to flatbuffer format.
// The returned MinibenchmarkSettings pointer is only valid until either the
// FlatBufferBuilder is modified or when the FlatBufferBuilder's lifetime ends.
const MinibenchmarkSettings* ConvertFromProto(
const proto::MinibenchmarkSettings& proto_settings,
flatbuffers::FlatBufferBuilder* builder);
} // namespace tflite
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_PROTO_TO_FLATBUFFER_H_
@@ -0,0 +1,249 @@
/* 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/acceleration/configuration/proto_to_flatbuffer.h"
#include <cstdint>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "tensorflow/lite/acceleration/configuration/configuration.pb.h"
namespace tflite {
namespace {
// Tests converting EdgeTpuSettings from proto to flatbuffer format.
TEST(ConversionTest, EdgeTpuSettings) {
// Define the fields to be tested.
const std::vector<int32_t> kHardwareClusterIds{1};
const std::string kPublicModelId = "public_model_id";
const tflite::proto::EdgeTpuSettings_UseLayerIrTgcBackend
kUseLayerIrTgcBackend =
tflite::proto::EdgeTpuSettings::USE_LAYER_IR_TGC_BACKEND_YES;
const bool kUseTpuServer = true;
// Create the proto settings.
proto::ComputeSettings input_settings;
auto* edgetpu_settings =
input_settings.mutable_tflite_settings()->mutable_edgetpu_settings();
edgetpu_settings->set_public_model_id(kPublicModelId);
edgetpu_settings->set_use_layer_ir_tgc_backend(kUseLayerIrTgcBackend);
flatbuffers::FlatBufferBuilder flatbuffers_builder;
*edgetpu_settings->mutable_hardware_cluster_ids() = {
kHardwareClusterIds.begin(), kHardwareClusterIds.end()};
edgetpu_settings->set_use_tpu_server(kUseTpuServer);
// Convert.
auto output_settings = ConvertFromProto(input_settings, &flatbuffers_builder)
->tflite_settings()
->edgetpu_settings();
// Verify the conversion results.
EXPECT_EQ(output_settings->hardware_cluster_ids()->size(), 1);
EXPECT_EQ(output_settings->hardware_cluster_ids()->Get(0),
kHardwareClusterIds[0]);
EXPECT_EQ(output_settings->public_model_id()->str(), kPublicModelId);
EXPECT_EQ(output_settings->use_layer_ir_tgc_backend(),
tflite::EdgeTpuSettings_::
UseLayerIrTgcBackend_USE_LAYER_IR_TGC_BACKEND_YES);
EXPECT_EQ(output_settings->use_tpu_server(), kUseTpuServer);
}
// Tests converting TFLiteSettings from proto to flatbuffer format.
TEST(ConversionTest, TFLiteSettings) {
// Define the fields to be tested.
const std::vector<int32_t> kHardwareClusterIds{1};
const std::string kPublicModelId = "public_model_id";
const tflite::proto::EdgeTpuSettings_UseLayerIrTgcBackend
kUseLayerIrTgcBackend =
tflite::proto::EdgeTpuSettings::USE_LAYER_IR_TGC_BACKEND_YES;
// Create the proto settings.
proto::TFLiteSettings input_settings;
input_settings.set_delegate(::tflite::proto::EDGETPU);
auto* edgetpu_settings = input_settings.mutable_edgetpu_settings();
edgetpu_settings->set_public_model_id(kPublicModelId);
edgetpu_settings->set_use_layer_ir_tgc_backend(kUseLayerIrTgcBackend);
flatbuffers::FlatBufferBuilder flatbuffers_builder;
*edgetpu_settings->mutable_hardware_cluster_ids() = {
kHardwareClusterIds.begin(), kHardwareClusterIds.end()};
// Convert.
auto output_settings = ConvertFromProto(input_settings, &flatbuffers_builder);
// Verify the conversion results.
EXPECT_EQ(output_settings->delegate(), ::tflite::Delegate_EDGETPU);
const auto* output_edgetpu_settings = output_settings->edgetpu_settings();
EXPECT_EQ(output_edgetpu_settings->hardware_cluster_ids()->size(), 1);
EXPECT_EQ(output_edgetpu_settings->hardware_cluster_ids()->Get(0),
kHardwareClusterIds[0]);
EXPECT_EQ(output_edgetpu_settings->public_model_id()->str(), kPublicModelId);
EXPECT_EQ(output_edgetpu_settings->use_layer_ir_tgc_backend(),
tflite::EdgeTpuSettings_::
UseLayerIrTgcBackend_USE_LAYER_IR_TGC_BACKEND_YES);
}
TEST(ConversionTest, StableDelegateLoaderSettings) {
// Define the fields to be tested.
const std::string kDelegatePath = "TEST_DELEGATE_PATH";
const std::string kDelegateName = "TEST_DELEGATE_NAME";
// Create the proto settings.
proto::TFLiteSettings input_settings;
auto* stable_delegate_loader_settings =
input_settings.mutable_stable_delegate_loader_settings();
stable_delegate_loader_settings->set_delegate_path(kDelegatePath);
stable_delegate_loader_settings->set_delegate_name(kDelegateName);
flatbuffers::FlatBufferBuilder flatbuffers_builder;
// Convert.
auto output_settings = ConvertFromProto(input_settings, &flatbuffers_builder);
// Verify the conversion results.
const auto* output_stable_delegate_loader_settings =
output_settings->stable_delegate_loader_settings();
ASSERT_NE(output_stable_delegate_loader_settings, nullptr);
EXPECT_EQ(output_stable_delegate_loader_settings->delegate_path()->str(),
kDelegatePath);
EXPECT_EQ(output_stable_delegate_loader_settings->delegate_name()->str(),
kDelegateName);
}
TEST(ConversionTest, CompilationCachingSettings) {
// Define the fields to be tested.
const std::string kCacheDir = "TEST_CACHE_DIR";
const std::string kModelToken = "TEST_MODEL_TOKEN";
// Create the proto settings.
proto::TFLiteSettings input_settings;
auto* compilation_caching_settings =
input_settings.mutable_compilation_caching_settings();
compilation_caching_settings->set_cache_dir(kCacheDir);
compilation_caching_settings->set_model_token(kModelToken);
flatbuffers::FlatBufferBuilder flatbuffers_builder;
// Convert.
auto output_settings = ConvertFromProto(input_settings, &flatbuffers_builder);
// Verify the conversion results.
const auto* output_compilation_caching_settings =
output_settings->compilation_caching_settings();
ASSERT_NE(output_compilation_caching_settings, nullptr);
EXPECT_EQ(output_compilation_caching_settings->cache_dir()->str(), kCacheDir);
EXPECT_EQ(output_compilation_caching_settings->model_token()->str(),
kModelToken);
}
TEST(ConversionTest, ArmNNSettings) {
// Define the fields to be tested.
const std::string kBackends = "TEST_BACKENDS";
const bool kFastmath = true;
const std::string kAdditionalParameters = "TEST_ADDITIONAL_PARAMETERS";
// Create the proto settings.
proto::TFLiteSettings input_settings;
auto* armnn_settings = input_settings.mutable_armnn_settings();
armnn_settings->set_backends(kBackends);
armnn_settings->set_fastmath(kFastmath);
armnn_settings->set_additional_parameters(kAdditionalParameters);
flatbuffers::FlatBufferBuilder flatbuffers_builder;
// Convert.
auto output_settings = ConvertFromProto(input_settings, &flatbuffers_builder);
// Verify the conversion results.
const auto* output_armnn_settings = output_settings->armnn_settings();
ASSERT_NE(output_armnn_settings, nullptr);
EXPECT_EQ(output_armnn_settings->backends()->str(), kBackends);
EXPECT_EQ(output_armnn_settings->fastmath(), kFastmath);
EXPECT_EQ(output_armnn_settings->additional_parameters()->str(),
kAdditionalParameters);
}
TEST(ConversionTest, MtkNeuronSettings) {
// Define the fields to be tested.
const proto::MtkNeuronSettings_ExecutionPreference kExecutionPreference =
proto::MtkNeuronSettings::PREFERENCE_FAST_SINGLE_ANSWER;
const proto::MtkNeuronSettings_ExecutionPriority kExecutionPriority =
proto::MtkNeuronSettings::PRIORITY_MEDIUM;
const proto::MtkNeuronSettings_OptimizationHint kOptimizationHint =
proto::MtkNeuronSettings::OPTIMIZATION_LOW_LATENCY;
const proto::MtkNeuronSettings_OperationCheckMode kOperationCheckMode =
proto::MtkNeuronSettings::PER_NODE_OPERATION_CHECK;
const bool kAllowFp16 = true;
const bool kUseAhwb = false;
const bool kUseCacheableBuffer = true;
const std::string kCompileOptions = "TEST_COMPILE_OPTIONS";
const std::string kAcceleratorName = "TEST_ACCELERATOR_NAME";
const std::string kNeuronConfigPath = "TEST_NEURON_CONFIG_PATH";
const int32_t kInferenceDeadlineMs = 1337;
const int32_t kInferenceAbortTimeMs = 42;
// Create the proto settings.
proto::TFLiteSettings input_settings;
auto* mtk_neuron_settings = input_settings.mutable_mtk_neuron_settings();
mtk_neuron_settings->set_execution_preference(kExecutionPreference);
mtk_neuron_settings->set_execution_priority(kExecutionPriority);
mtk_neuron_settings->add_optimization_hints(kOptimizationHint);
mtk_neuron_settings->set_operation_check_mode(kOperationCheckMode);
mtk_neuron_settings->set_allow_fp16_precision_for_fp32(kAllowFp16);
mtk_neuron_settings->set_use_ahwb(kUseAhwb);
mtk_neuron_settings->set_use_cacheable_buffer(kUseCacheableBuffer);
mtk_neuron_settings->add_compile_options(kCompileOptions);
mtk_neuron_settings->add_accelerator_names(kAcceleratorName);
mtk_neuron_settings->set_neuron_config_path(kNeuronConfigPath);
mtk_neuron_settings->set_inference_deadline_ms(kInferenceDeadlineMs);
mtk_neuron_settings->set_inference_abort_time_ms(kInferenceAbortTimeMs);
flatbuffers::FlatBufferBuilder flatbuffers_builder;
// Convert.
auto output_settings = ConvertFromProto(input_settings, &flatbuffers_builder);
// Verify the conversion results.
const auto* output_mtk_neuron_settings =
output_settings->mtk_neuron_settings();
ASSERT_NE(output_mtk_neuron_settings, nullptr);
EXPECT_EQ(
output_mtk_neuron_settings->execution_preference(),
MtkNeuronSettings_::ExecutionPreference_PREFERENCE_FAST_SINGLE_ANSWER);
EXPECT_EQ(output_mtk_neuron_settings->execution_priority(),
MtkNeuronSettings_::ExecutionPriority_PRIORITY_MEDIUM);
EXPECT_EQ(output_mtk_neuron_settings->optimization_hints()->size(), 1);
EXPECT_EQ(output_mtk_neuron_settings->optimization_hints()->Get(0),
kOptimizationHint);
EXPECT_EQ(output_mtk_neuron_settings->operation_check_mode(),
MtkNeuronSettings_::OperationCheckMode_PER_NODE_OPERATION_CHECK);
EXPECT_EQ(output_mtk_neuron_settings->allow_fp16_precision_for_fp32(),
kAllowFp16);
EXPECT_EQ(output_mtk_neuron_settings->use_ahwb(), kUseAhwb);
EXPECT_EQ(output_mtk_neuron_settings->use_cacheable_buffer(),
kUseCacheableBuffer);
EXPECT_EQ(output_mtk_neuron_settings->compile_options()->size(), 1);
EXPECT_EQ(output_mtk_neuron_settings->compile_options()->Get(0)->str(),
kCompileOptions);
EXPECT_EQ(output_mtk_neuron_settings->accelerator_names()->size(), 1);
EXPECT_EQ(output_mtk_neuron_settings->accelerator_names()->Get(0)->str(),
kAcceleratorName);
EXPECT_EQ(output_mtk_neuron_settings->neuron_config_path()->str(),
kNeuronConfigPath);
EXPECT_EQ(output_mtk_neuron_settings->inference_deadline_ms(),
kInferenceDeadlineMs);
EXPECT_EQ(output_mtk_neuron_settings->inference_abort_time_ms(),
kInferenceAbortTimeMs);
}
} // namespace
} // namespace tflite
@@ -0,0 +1,27 @@
/* Copyright 2022 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 file implements the TFLite Delegate Plugin for the NNAPI Delegate.
#include "tensorflow/lite/acceleration/configuration/stable_delegate_plugin.h"
namespace tflite {
namespace delegates {
TFLITE_REGISTER_DELEGATE_FACTORY_FUNCTION(StableDelegatePlugin,
StableDelegatePlugin::New);
} // namespace delegates
} // namespace tflite
@@ -0,0 +1,114 @@
/* Copyright 2022 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_ACCELERATION_CONFIGURATION_STABLE_DELEGATE_PLUGIN_H_
#define TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_STABLE_DELEGATE_PLUGIN_H_
// This file provides the StableDelegatePlugin class, which implements the
// TFLite Delegate Plugin Interface for the stable delegates.
#include <memory>
#include <string>
#include "flatbuffers/flatbuffers.h"
#include "tensorflow/lite/acceleration/configuration/c/delegate_plugin.h"
#include "tensorflow/lite/acceleration/configuration/c/stable_delegate.h"
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/core/acceleration/configuration/delegate_registry.h"
#include "tensorflow/lite/delegates/utils/experimental/stable_delegate/delegate_loader.h"
#include "tensorflow/lite/tools/logging.h"
namespace tflite {
namespace delegates {
class StableDelegatePlugin : public DelegatePluginInterface {
public:
static std::unique_ptr<StableDelegatePlugin> New(
const TFLiteSettings& tflite_settings) {
return std::make_unique<StableDelegatePlugin>(tflite_settings);
}
explicit StableDelegatePlugin(const TFLiteSettings& tflite_settings) {
const StableDelegateLoaderSettings* stable_delegate_loader_settings =
tflite_settings.stable_delegate_loader_settings();
if (!stable_delegate_loader_settings ||
!stable_delegate_loader_settings->delegate_path() ||
stable_delegate_loader_settings->delegate_path()->size() == 0) {
TFLITE_LOG(ERROR) << "The delegate path field is not available from the "
"provided stable delegate loader settings.";
return;
}
// Creates a copy of TFLiteSettings within the stable delegate plugin.
TFLiteSettingsT tflite_settings_t;
tflite_settings.UnPackTo(&tflite_settings_t);
tflite_settings_builder_.Finish(
CreateTFLiteSettings(tflite_settings_builder_, &tflite_settings_t));
const TfLiteStableDelegate* stable_delegate =
utils::LoadDelegateFromSharedLibrary(
stable_delegate_loader_settings->delegate_path()->str());
if (!stable_delegate) {
TFLITE_LOG(ERROR)
<< "Failed to load stable delegate plugin symbol from "
<< stable_delegate_loader_settings->delegate_path()->str();
return;
}
if (!stable_delegate->delegate_plugin || !stable_delegate->delegate_name) {
TFLITE_LOG(ERROR)
<< "Invalid stable delegate struct loaded from "
<< stable_delegate_loader_settings->delegate_path()->str();
return;
}
stable_delegate_plugin_ = stable_delegate->delegate_plugin;
TFLITE_LOG(INFO)
<< "The stable delegate plugin has loaded delegate plugin for "
<< stable_delegate->delegate_name;
}
TfLiteDelegatePtr Create() override {
if (!stable_delegate_plugin_ || !stable_delegate_plugin_->create ||
!stable_delegate_plugin_->destroy) {
return TfLiteDelegatePtr(nullptr, [](TfLiteDelegate*) {});
}
return TfLiteDelegatePtr(
reinterpret_cast<TfLiteDelegate*>(
stable_delegate_plugin_->create(GetTFLiteSettings())),
reinterpret_cast<void (*)(TfLiteDelegate*)>(
stable_delegate_plugin_->destroy));
}
int GetDelegateErrno(TfLiteDelegate* from_delegate) override {
if (!stable_delegate_plugin_ ||
!stable_delegate_plugin_->get_delegate_errno) {
return 0;
}
return stable_delegate_plugin_->get_delegate_errno(
reinterpret_cast<TfLiteOpaqueDelegate*>(from_delegate));
}
private:
const TFLiteSettings* GetTFLiteSettings() const {
return flatbuffers::GetRoot<TFLiteSettings>(
tflite_settings_builder_.GetBufferPointer());
}
const TfLiteOpaqueDelegatePlugin* stable_delegate_plugin_ = nullptr;
flatbuffers::FlatBufferBuilder tflite_settings_builder_;
};
} // namespace delegates
} // namespace tflite
#endif // TENSORFLOW_LITE_ACCELERATION_CONFIGURATION_STABLE_DELEGATE_PLUGIN_H_
@@ -0,0 +1,159 @@
/* Copyright 2022 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.
==============================================================================*/
// Some very simple unit tests of the Stable Delegate Plugin.
#include "tensorflow/lite/acceleration/configuration/stable_delegate_plugin.h"
#include <memory>
#include <string>
#include "flatbuffers/flatbuffers.h"
#include <gtest/gtest.h>
#include "pthreadpool.h" // from @pthreadpool
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/core/acceleration/configuration/delegate_registry.h"
#include "tensorflow/lite/delegates/xnnpack/xnnpack_delegate.h"
namespace tflite {
class StableDelegatePluginTest : public testing::Test {
public:
static constexpr int kNumThreadsForTest = 7;
static constexpr XNNPackFlags kFlagsForTest =
XNNPackFlags_TFLITE_XNNPACK_DELEGATE_FLAG_QS8_QU8;
static constexpr char kDelegateBinaryPath[] =
"tensorflow/lite/delegates/utils/experimental/"
"stable_delegate/libtensorflowlite_stable_xnnpack_delegate.so";
void SetUp() override {
// Construct a FlatBuffer that contains
// TFLiteSettings {
// delegate: Delegate.XNNPACK,
// XNNPackSettings { num_threads: kNumThreadsForTest
// flags: TFLITE_XNNPACK_DELEGATE_FLAG_QS8 |
// TFLITE_XNNPACK_DELEGATE_FLAG_QU8
// },
// StableDelegateLoaderSettings { delegate_path: kDelegateBinaryPath }
// }.
// We use the stable XNNPack delegate binary for testing stable delegate
// provider.
flatbuffers::Offset<flatbuffers::String> stable_delegate_path_offset =
flatbuffer_builder_.CreateString(kDelegateBinaryPath);
StableDelegateLoaderSettingsBuilder stable_delegate_loader_settings_builder(
flatbuffer_builder_);
stable_delegate_loader_settings_builder.add_delegate_path(
stable_delegate_path_offset);
flatbuffers::Offset<StableDelegateLoaderSettings>
stable_delegate_loader_settings =
stable_delegate_loader_settings_builder.Finish();
XNNPackSettingsBuilder xnnpack_settings_builder(flatbuffer_builder_);
xnnpack_settings_builder.add_num_threads(kNumThreadsForTest);
xnnpack_settings_builder.add_flags(kFlagsForTest);
flatbuffers::Offset<XNNPackSettings> xnnpack_settings =
xnnpack_settings_builder.Finish();
TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder_);
tflite_settings_builder.add_stable_delegate_loader_settings(
stable_delegate_loader_settings);
tflite_settings_builder.add_xnnpack_settings(xnnpack_settings);
// Stable delegate plugin doesn't rely on the delegate specified in the
// TFLiteSettings provided.
tflite_settings_builder.add_delegate(Delegate_XNNPACK);
flatbuffers::Offset<TFLiteSettings> tflite_settings =
tflite_settings_builder.Finish();
flatbuffer_builder_.Finish(tflite_settings);
tflite_settings_ = flatbuffers::GetRoot<TFLiteSettings>(
flatbuffer_builder_.GetBufferPointer());
// Create a stable delegate plugin for an XNNPack delegate using the
// settings from the flatbuffer.
delegate_plugin_ = delegates::DelegatePluginRegistry::CreateByName(
"StableDelegatePlugin", *tflite_settings_);
ASSERT_NE(delegate_plugin_, nullptr);
}
protected:
// tflite_settings_ points into storage owned by flatbuffer_builder_.
flatbuffers::FlatBufferBuilder flatbuffer_builder_;
const TFLiteSettings* tflite_settings_;
std::unique_ptr<delegates::DelegatePluginInterface> delegate_plugin_;
};
TEST_F(StableDelegatePluginTest, CanCreateAndDestroyDelegate) {
delegates::TfLiteDelegatePtr delegate = delegate_plugin_->Create();
EXPECT_NE(delegate, nullptr);
}
TEST_F(StableDelegatePluginTest, CanGetDelegateErrno) {
delegates::TfLiteDelegatePtr delegate = delegate_plugin_->Create();
ASSERT_NE(delegate, nullptr);
EXPECT_EQ(delegate_plugin_->GetDelegateErrno(delegate.get()), 0);
}
TEST_F(StableDelegatePluginTest, SetsCorrectThreadCount) {
delegates::TfLiteDelegatePtr delegate = delegate_plugin_->Create();
ASSERT_NE(delegate, nullptr);
pthreadpool_t threadpool = static_cast<pthreadpool_t>(
TfLiteXNNPackDelegateGetThreadPool(delegate.get()));
ASSERT_NE(threadpool, nullptr);
EXPECT_EQ(pthreadpool_get_threads_count(threadpool), kNumThreadsForTest);
}
static std::unique_ptr<delegates::DelegatePluginInterface>
CreatePluginWithDelegatePath(const std::string& delegate_path) {
flatbuffers::FlatBufferBuilder flatbuffer_builder;
flatbuffers::Offset<flatbuffers::String> stable_delegate_path_offset =
delegate_path.empty() ? 0
: flatbuffer_builder.CreateString(delegate_path);
StableDelegateLoaderSettingsBuilder stable_delegate_loader_settings_builder(
flatbuffer_builder);
if (stable_delegate_path_offset.o != 0) {
stable_delegate_loader_settings_builder.add_delegate_path(
stable_delegate_path_offset);
}
flatbuffers::Offset<StableDelegateLoaderSettings>
stable_delegate_loader_settings =
stable_delegate_loader_settings_builder.Finish();
TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder);
tflite_settings_builder.add_stable_delegate_loader_settings(
stable_delegate_loader_settings);
tflite_settings_builder.add_delegate(Delegate_XNNPACK);
flatbuffers::Offset<TFLiteSettings> tflite_settings =
tflite_settings_builder.Finish();
flatbuffer_builder.Finish(tflite_settings);
const TFLiteSettings* settings = flatbuffers::GetRoot<TFLiteSettings>(
flatbuffer_builder.GetBufferPointer());
return delegates::DelegatePluginRegistry::CreateByName("StableDelegatePlugin",
*settings);
}
TEST(StableDelegatePluginNullTest, MissingDelegatePath) {
std::unique_ptr<delegates::DelegatePluginInterface> delegate_plugin =
CreatePluginWithDelegatePath("");
ASSERT_NE(delegate_plugin, nullptr);
EXPECT_EQ(delegate_plugin->Create(), nullptr);
EXPECT_EQ(delegate_plugin->GetDelegateErrno(nullptr), 0);
}
TEST(StableDelegatePluginNullTest, InvalidDelegatePath) {
std::unique_ptr<delegates::DelegatePluginInterface> delegate_plugin =
CreatePluginWithDelegatePath("invalid_path.so");
ASSERT_NE(delegate_plugin, nullptr);
EXPECT_EQ(delegate_plugin->Create(), nullptr);
EXPECT_EQ(delegate_plugin->GetDelegateErrno(nullptr), 0);
}
} // namespace tflite
@@ -0,0 +1,355 @@
// Copyright 2022 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.
// Generated from configuration.proto
namespace tflite;
enum ExecutionPreference : int {
ANY = 0,
LOW_LATENCY = 1,
LOW_POWER = 2,
FORCE_CPU = 3,
}
enum Delegate : int {
NONE = 0,
NNAPI = 1,
GPU = 2,
HEXAGON = 3,
XNNPACK = 4,
EDGETPU = 5,
EDGETPU_CORAL = 6,
CORE_ML = 7,
}
enum NNAPIExecutionPreference : int {
UNDEFINED = 0,
NNAPI_LOW_POWER = 1,
NNAPI_FAST_SINGLE_ANSWER = 2,
NNAPI_SUSTAINED_SPEED = 3,
}
enum NNAPIExecutionPriority : int {
NNAPI_PRIORITY_UNDEFINED = 0,
NNAPI_PRIORITY_LOW = 1,
NNAPI_PRIORITY_MEDIUM = 2,
NNAPI_PRIORITY_HIGH = 3,
}
enum GPUBackend : int {
UNSET = 0,
OPENCL = 1,
OPENGL = 2,
}
enum GPUInferencePriority : int {
GPU_PRIORITY_AUTO = 0,
GPU_PRIORITY_MAX_PRECISION = 1,
GPU_PRIORITY_MIN_LATENCY = 2,
GPU_PRIORITY_MIN_MEMORY_USAGE = 3,
}
enum GPUInferenceUsage : int {
GPU_INFERENCE_PREFERENCE_FAST_SINGLE_ANSWER = 0,
GPU_INFERENCE_PREFERENCE_SUSTAINED_SPEED = 1,
}
enum XNNPackFlags : int {
TFLITE_XNNPACK_DELEGATE_NO_FLAGS = 0,
TFLITE_XNNPACK_DELEGATE_FLAG_QS8 = 1,
TFLITE_XNNPACK_DELEGATE_FLAG_QU8 = 2,
TFLITE_XNNPACK_DELEGATE_FLAG_QS8_QU8 = 3,
TFLITE_XNNPACK_DELEGATE_FLAG_FORCE_FP16 = 4,
}
namespace tflite.CoreMLSettings_;
enum EnabledDevices : int {
DEVICES_ALL = 0,
DEVICES_WITH_NEURAL_ENGINE = 1,
}
namespace tflite.EdgeTpuDeviceSpec_;
enum PlatformType : int {
MMIO = 0,
REFERENCE = 1,
SIMULATOR = 2,
REMOTE_SIMULATOR = 3,
}
namespace tflite;
enum EdgeTpuPowerState : int {
UNDEFINED_POWERSTATE = 0,
TPU_CORE_OFF = 1,
READY = 2,
ACTIVE_MIN_POWER = 3,
ACTIVE_VERY_LOW_POWER = 4,
ACTIVE_LOW_POWER = 5,
ACTIVE = 6,
OVER_DRIVE = 7,
}
namespace tflite.EdgeTpuSettings_;
enum FloatTruncationType : int {
UNSPECIFIED = 0,
NO_TRUNCATION = 1,
BFLOAT16 = 2,
HALF = 3,
}
enum QosClass : int {
QOS_UNDEFINED = 0,
BEST_EFFORT = 1,
REALTIME = 2,
}
namespace tflite.CoralSettings_;
enum Performance : int {
UNDEFINED = 0,
MAXIMUM = 1,
HIGH = 2,
MEDIUM = 3,
LOW = 4,
}
namespace tflite;
enum BenchmarkEventType : int {
UNDEFINED_BENCHMARK_EVENT_TYPE = 0,
START = 1,
END = 2,
ERROR = 3,
LOGGED = 4,
RECOVERED_ERROR = 5,
}
enum BenchmarkStage : int {
UNKNOWN = 0,
INITIALIZATION = 1,
INFERENCE = 2,
}
table ComputeSettings {
preference:tflite.ExecutionPreference;
tflite_settings:tflite.TFLiteSettings;
model_namespace_for_statistics:string;
model_identifier_for_statistics:string;
settings_to_test_locally:tflite.MinibenchmarkSettings;
}
table NNAPISettings {
accelerator_name:string;
cache_directory:string;
model_token:string;
execution_preference:tflite.NNAPIExecutionPreference;
no_of_nnapi_instances_to_cache:int;
fallback_settings:tflite.FallbackSettings;
allow_nnapi_cpu_on_android_10_plus:bool;
execution_priority:tflite.NNAPIExecutionPriority;
allow_dynamic_dimensions:bool;
allow_fp16_precision_for_fp32:bool;
use_burst_computation:bool;
support_library_handle:long;
}
table GPUSettings {
is_precision_loss_allowed:bool;
enable_quantized_inference:bool = true;
force_backend:tflite.GPUBackend;
inference_priority1:tflite.GPUInferencePriority;
inference_priority2:tflite.GPUInferencePriority;
inference_priority3:tflite.GPUInferencePriority;
inference_preference:tflite.GPUInferenceUsage;
cache_directory:string;
model_token:string;
}
table HexagonSettings {
debug_level:int;
powersave_level:int;
print_graph_profile:bool;
print_graph_debug:bool;
}
table XNNPackSettings {
num_threads:int;
flags:tflite.XNNPackFlags;
}
table CoreMLSettings {
enabled_devices:tflite.CoreMLSettings_.EnabledDevices;
coreml_version:int;
max_delegated_partitions:int;
min_nodes_per_partition:int = 2;
}
table StableDelegateLoaderSettings {
delegate_path:string;
}
table EdgeTpuDeviceSpec {
platform_type:tflite.EdgeTpuDeviceSpec_.PlatformType;
num_chips:int;
device_paths:[string];
chip_family:int;
}
table EdgeTpuInactivePowerConfig {
inactive_power_state:tflite.EdgeTpuPowerState;
inactive_timeout_us:long;
}
table EdgeTpuSettings {
inference_power_state:tflite.EdgeTpuPowerState;
inactive_power_configs:[tflite.EdgeTpuInactivePowerConfig];
inference_priority:int = -1;
edgetpu_device_spec:tflite.EdgeTpuDeviceSpec;
model_token:string;
float_truncation_type:tflite.EdgeTpuSettings_.FloatTruncationType;
qos_class:tflite.EdgeTpuSettings_.QosClass;
}
table CoralSettings {
device:string;
performance:tflite.CoralSettings_.Performance;
usb_always_dfu:bool;
usb_max_bulk_in_queue_length:int;
}
table CPUSettings {
num_threads:int = -1;
}
table TFLiteSettings {
delegate:tflite.Delegate;
nnapi_settings:tflite.NNAPISettings;
gpu_settings:tflite.GPUSettings;
hexagon_settings:tflite.HexagonSettings;
xnnpack_settings:tflite.XNNPackSettings;
coreml_settings:tflite.CoreMLSettings;
cpu_settings:tflite.CPUSettings;
max_delegated_partitions:int;
edgetpu_settings:tflite.EdgeTpuSettings;
coral_settings:tflite.CoralSettings;
fallback_settings:tflite.FallbackSettings;
disable_default_delegates:bool;
stable_delegate_loader_settings:tflite.StableDelegateLoaderSettings;
}
table FallbackSettings {
allow_automatic_fallback_on_compilation_error:bool;
allow_automatic_fallback_on_execution_error:bool;
}
table BenchmarkMetric {
name:string;
values:[float];
}
table BenchmarkResult {
initialization_time_us:[long];
inference_time_us:[long];
max_memory_kb:int;
ok:bool;
metrics:[tflite.BenchmarkMetric];
actual_output:[tflite.BenchmarkResult_.InferenceOutput];
}
namespace tflite.BenchmarkResult_;
table InferenceOutput {
value:[ubyte];
}
namespace tflite;
table ErrorCode {
source:tflite.Delegate;
tflite_error:int;
underlying_api_error:long;
}
table BenchmarkError {
stage:tflite.BenchmarkStage;
exit_code:int;
signal:int;
error_code:[tflite.ErrorCode];
mini_benchmark_error_code:int;
}
table BenchmarkEvent {
tflite_settings:tflite.TFLiteSettings;
event_type:tflite.BenchmarkEventType;
result:tflite.BenchmarkResult;
error:tflite.BenchmarkError;
boottime_us:long;
wallclock_us:long;
}
table BestAccelerationDecision {
number_of_source_events:int;
min_latency_event:tflite.BenchmarkEvent;
min_inference_time_us:long;
}
table BenchmarkInitializationFailure {
initialization_status:int;
}
table MiniBenchmarkEvent {
is_log_flushing_event:bool;
best_acceleration_decision:tflite.BestAccelerationDecision;
initialization_failure:tflite.BenchmarkInitializationFailure;
benchmark_event:tflite.BenchmarkEvent;
}
table ModelFile {
filename:string;
fd:long;
offset:long;
length:long;
model_id_group:tflite.ModelIdGroup;
}
table ModelIdGroup {
model_namespace:string;
model_id:string;
}
table BenchmarkStoragePaths {
storage_file_path:string;
data_directory_path:string;
}
table ValidationSettings {
per_test_timeout_ms:long;
}
table MinibenchmarkSettings {
settings_to_test:[tflite.TFLiteSettings];
model_file:tflite.ModelFile;
storage_paths:tflite.BenchmarkStoragePaths;
validation_settings:tflite.ValidationSettings;
}
table BenchmarkEventStorage {
model_id_group:tflite.ModelIdGroup;
benchmark_event:tflite.BenchmarkEvent;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,84 @@
/* Copyright 2021 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.
==============================================================================*/
// Some very simple unit tests of the (C++) XNNPack Delegate Plugin.
#include <memory>
#include <gtest/gtest.h>
#include "flatbuffers/flatbuffers.h" // from @flatbuffers
#include "pthreadpool.h" // from @pthreadpool
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/acceleration/configuration/delegate_registry.h"
#include "tensorflow/lite/test_util.h"
namespace tflite {
class XnnpackPluginTest : public tflite::testing::Test {
public:
static constexpr int kNumThreadsForTest = 7;
static constexpr tflite::XNNPackFlags kFlagsForTest =
tflite::XNNPackFlags::XNNPackFlags_TFLITE_XNNPACK_DELEGATE_FLAG_QS8_QU8;
void SetUp() override {
// Construct a FlatBuffer that contains
// TFLiteSettings {
// delegate: Delegate.XNNPACK,
// XNNPackSettings { num_threads: kNumThreadsForTest
// flags: TFLITE_XNNPACK_DELEGATE_FLAG_QS8 |
// TFLITE_XNNPACK_DELEGATE_FLAG_QU8
// }
// }.
XNNPackSettingsBuilder xnnpack_settings_builder(flatbuffer_builder_);
xnnpack_settings_builder.add_num_threads(kNumThreadsForTest);
xnnpack_settings_builder.add_flags(kFlagsForTest);
flatbuffers::Offset<XNNPackSettings> xnnpack_settings =
xnnpack_settings_builder.Finish();
TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder_);
tflite_settings_builder.add_xnnpack_settings(xnnpack_settings);
tflite_settings_builder.add_delegate(Delegate_XNNPACK);
flatbuffers::Offset<TFLiteSettings> tflite_settings =
tflite_settings_builder.Finish();
flatbuffer_builder_.Finish(tflite_settings);
tflite_settings_ = flatbuffers::GetRoot<TFLiteSettings>(
flatbuffer_builder_.GetBufferPointer());
// Create an XNNPack delegate plugin using the settings from the flatbuffer.
delegate_plugin_ = delegates::DelegatePluginRegistry::CreateByName(
"XNNPackPlugin", *tflite_settings_);
ASSERT_NE(delegate_plugin_, nullptr);
}
void TearDown() override { delegate_plugin_.reset(); }
~XnnpackPluginTest() override {}
protected:
// settings_ points into storage owned by flatbuffer_builder_.
flatbuffers::FlatBufferBuilder flatbuffer_builder_;
const TFLiteSettings *tflite_settings_;
std::unique_ptr<delegates::DelegatePluginInterface> delegate_plugin_;
};
constexpr int XnnpackPluginTest::kNumThreadsForTest;
TEST_F(XnnpackPluginTest, CanCreateAndDestroyDelegate) {
delegates::TfLiteOpaqueDelegatePtr delegate = delegate_plugin_->Create();
EXPECT_NE(delegate, nullptr);
}
TEST_F(XnnpackPluginTest, CanGetDelegateErrno) {
delegates::TfLiteOpaqueDelegatePtr delegate = delegate_plugin_->Create();
int error_number = delegate_plugin_->GetDelegateErrno(delegate.get());
EXPECT_EQ(error_number, 0);
}
} // namespace tflite
+23
View File
@@ -0,0 +1,23 @@
/* Copyright 2017 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.
==============================================================================*/
/// \file
///
/// Memory management for TF Lite.
#ifndef TENSORFLOW_LITE_ALLOCATION_H_
#define TENSORFLOW_LITE_ALLOCATION_H_
#include "tensorflow/compiler/mlir/lite/allocation.h"
#endif // TENSORFLOW_LITE_ALLOCATION_H_
+150
View File
@@ -0,0 +1,150 @@
/* 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/compiler/mlir/lite/allocation.h"
#include <cstddef>
#include <cstdint>
#if defined(__linux__)
#include <fcntl.h>
#endif
#include <sys/stat.h>
#include <gtest/gtest.h>
#include "tensorflow/lite/testing/util.h"
namespace tflite {
TEST(MMAPAllocation, TestInvalidFile) {
if (!MMAPAllocation::IsSupported()) {
return;
}
TestErrorReporter error_reporter;
MMAPAllocation allocation("/tmp/tflite_model_1234", &error_reporter);
EXPECT_FALSE(allocation.valid());
}
TEST(MMAPAllocation, TestValidFile) {
if (!MMAPAllocation::IsSupported()) {
return;
}
TestErrorReporter error_reporter;
MMAPAllocation allocation(
"tensorflow/lite/testdata/empty_model.bin", &error_reporter);
ASSERT_TRUE(allocation.valid());
EXPECT_GT(allocation.fd(), 0);
EXPECT_GT(allocation.bytes(), 0);
EXPECT_NE(allocation.base(), nullptr);
}
#if defined(__linux__)
TEST(MMAPAllocation, TestInvalidFileDescriptor) {
if (!MMAPAllocation::IsSupported()) {
return;
}
TestErrorReporter error_reporter;
MMAPAllocation allocation(-1, &error_reporter);
EXPECT_FALSE(allocation.valid());
}
TEST(MMAPAllocation, TestInvalidSizeAndOffset) {
if (!MMAPAllocation::IsSupported()) {
return;
}
int fd =
open("tensorflow/lite/testdata/empty_model.bin", O_RDONLY);
ASSERT_GT(fd, 0);
struct stat fd_stat;
ASSERT_EQ(fstat(fd, &fd_stat), 0);
size_t file_size = fd_stat.st_size;
TestErrorReporter error_reporter;
MMAPAllocation allocation_invalid_offset(fd, /*offset=*/file_size + 100,
/*length=*/1, &error_reporter);
EXPECT_FALSE(allocation_invalid_offset.valid());
MMAPAllocation allocation_invalid_length(fd, /*offset=*/0, /*length=*/0,
&error_reporter);
EXPECT_FALSE(allocation_invalid_length.valid());
MMAPAllocation allocation_excessive_length(fd, /*offset=*/0,
/*length=*/file_size + 1,
&error_reporter);
EXPECT_FALSE(allocation_excessive_length.valid());
MMAPAllocation allocation_excessive_length_with_offset(
fd, /*offset=*/10, /*length=*/file_size, &error_reporter);
EXPECT_FALSE(allocation_excessive_length_with_offset.valid());
MMAPAllocation allocation_integer_overflow(
fd, /*offset=*/10, /*length=*/SIZE_MAX - 5, &error_reporter);
EXPECT_FALSE(allocation_integer_overflow.valid());
close(fd);
}
TEST(MMAPAllocation, TestValidFileDescriptor) {
if (!MMAPAllocation::IsSupported()) {
return;
}
int fd =
open("tensorflow/lite/testdata/empty_model.bin", O_RDONLY);
ASSERT_GT(fd, 0);
TestErrorReporter error_reporter;
MMAPAllocation allocation(fd, &error_reporter);
EXPECT_TRUE(allocation.valid());
EXPECT_GT(allocation.fd(), 0);
EXPECT_GT(allocation.bytes(), 0);
EXPECT_NE(allocation.base(), nullptr);
close(fd);
}
TEST(MMAPAllocation, TestValidFileDescriptorWithOffset) {
if (!MMAPAllocation::IsSupported()) {
return;
}
int fd =
open("tensorflow/lite/testdata/empty_model.bin", O_RDONLY);
ASSERT_GT(fd, 0);
struct stat fd_stat;
ASSERT_EQ(fstat(fd, &fd_stat), 0);
size_t file_size = fd_stat.st_size;
TestErrorReporter error_reporter;
MMAPAllocation allocation(fd, /*offset=*/10, /*length=*/file_size - 10,
&error_reporter);
EXPECT_TRUE(allocation.valid());
EXPECT_GT(allocation.fd(), 0);
EXPECT_GT(allocation.bytes(), 0);
EXPECT_NE(allocation.base(), nullptr);
close(fd);
}
#endif // defined(__linux__)
} // namespace tflite
+9
View File
@@ -0,0 +1,9 @@
"""Visibility list for TFLite framework targets in OSS.
This file defines public visibility for TFLite framework targets when exported
to Open Source.
"""
TFLITE_FRAMEWORK_VISIBILITY = [
"//visibility:public",
]
+614
View File
@@ -0,0 +1,614 @@
/* Copyright 2017 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/arena_planner.h"
#include <stddef.h>
#include <algorithm>
#include <cstdint>
#include <limits>
#include <memory>
#include <utility>
#include <vector>
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/graph_info.h"
#include "tensorflow/lite/simple_memory_arena.h"
namespace tflite {
constexpr int32_t kLastActiveNodeUndefined =
std::numeric_limits<int32_t>::max();
constexpr int32_t kNodeNotAssigned = std::numeric_limits<int32_t>::max();
constexpr int32_t kScalarTensorBytes = 4;
ArenaPlanner::ArenaPlanner(TfLiteContext* context,
std::unique_ptr<GraphInfo> graph_info,
bool preserve_all_tensors, int tensor_alignment,
int subgraph_index)
: context_(context),
graph_info_(std::move(graph_info)),
arena_(kDefaultArenaAlignment, subgraph_index),
has_nonpersistent_memory_(false),
persistent_arena_(kDefaultArenaAlignment, subgraph_index),
preserve_all_tensors_(preserve_all_tensors),
tensor_alignment_(tensor_alignment),
last_active_node_(kLastActiveNodeUndefined) {}
ArenaPlanner::~ArenaPlanner() {
arena_.ReleaseBuffer();
persistent_arena_.ReleaseBuffer();
}
std::intptr_t ArenaPlanner::BasePointer(TfLiteAllocationType type) {
if (type == kTfLiteArenaRwPersistent) {
return persistent_arena_.BasePointer();
}
if (type == kTfLiteArenaRw) {
return arena_.BasePointer();
}
return 0;
}
TfLiteStatus ArenaPlanner::ResetAllocations() {
TF_LITE_ENSURE_STATUS(arena_.ClearPlan());
TF_LITE_ENSURE_STATUS(persistent_arena_.ClearPlan());
allocs_.clear();
allocs_.resize(graph_info_->num_tensors());
// NOMUTANTS -- Setting last_active_node_ to kLastActiveNodeUndefined causes
// all allocs to be cleared. if this is not set, the slow path is taken
// (Purge) which inspects each alloc. Both paths give the exact same result.
last_active_node_ = kLastActiveNodeUndefined;
return kTfLiteOk;
}
TfLiteStatus ArenaPlanner::ResetAllocationsAfter(int node) {
TfLiteTensor* tensors = graph_info_->tensors();
for (int i = 0; i < static_cast<int>(allocs_.size()); ++i) {
if (allocs_[i].first_node > node && allocs_[i].size > 0) {
TfLiteTensor& tensor = tensors[i];
if (tensor.allocation_type == kTfLiteArenaRw) {
allocs_[i].reset();
tensor.data.raw = nullptr;
}
}
}
if (last_active_node_ > node) {
arena_.CalculateActiveAllocs(allocs_, node);
} else {
arena_.PurgeAfter(node);
}
last_active_node_ = node;
return kTfLiteOk;
}
int ArenaPlanner::FindSharedTensor(int tensor_index) {
auto actual_tensor_it = actual_tensor_id_.find(tensor_index);
if (actual_tensor_it != actual_tensor_id_.end()) {
tensor_index = actual_tensor_it->second;
}
return tensor_index;
}
bool ArenaPlanner::InputTensorCanBeShared(const TfLiteTensor& input_tensor,
const TfLiteTensor& output_tensor,
int input_id, int output_id,
bool tensor_changed) {
// Both tensors must be the same size.
// Often a small tensor indicates that `ResizeInputTensor` has not yet been
// called, the form of a broadcast may change so sharing may no longer be
// possible. This is to prevent false detection of sharing which causes
// the shared tensor to live longer than it otherwise would, potentially
// increasing memory usage.
// The input and output are always the same size for ops which don't modify
// the tensor.
if (tensor_changed) {
if (input_tensor.bytes != output_tensor.bytes ||
input_tensor.bytes <= kScalarTensorBytes) {
return false;
}
// If there is more than one reference to the input tensor, we cannot
// share. TODO(b/254230751): The last consumer can share.
if (refcounts_[input_id] > 1) {
return false;
}
}
for (int input : graph_info_->inputs()) {
if (input == input_id) {
return false;
}
}
for (int output : graph_info_->outputs()) {
if (output == output_id) {
return false;
}
}
TfLiteAllocationType input_allocation_type = input_tensor.allocation_type;
TfLiteAllocationType output_allocation_type = output_tensor.allocation_type;
if (input_allocation_type != output_allocation_type &&
input_allocation_type != kTfLiteArenaRw) {
return false;
}
if (preserve_all_tensors_) {
return false;
}
return true;
}
// An op can reuse one of the input tensors if:
// The sizes are equal (broadcast is an example where this may not be true)
// The tensors are allocated within the same arena.
// The number of references to the shared input is one in the case of ops which
// modify the contents.
// Subgraph inputs and outputs cannot be shared.
void ArenaPlanner::IdentifyInPlaceTensors() {
actual_tensor_id_.clear();
const int num_execution_nodes = graph_info_->num_execution_nodes();
TfLiteTensor* tensors = graph_info_->tensors();
for (int i = 0; i < num_execution_nodes; ++i) {
const TfLiteRegistration& registration = graph_info_->registration(i);
const TfLiteNode& node = graph_info_->node(i);
if (node.outputs->size < 1) continue;
bool tensor_changed =
!(registration.inplace_operator & kTfLiteInplaceOpDataUnmodified);
if (registration.inplace_operator == kTfLiteInplaceOpNone) {
continue;
}
int32_t input_id = -1;
int32_t output_id = node.outputs->data[0];
const TfLiteTensor& output_tensor = tensors[output_id];
const int loop_end =
std::min(kTfLiteMaxSharableOpInputs, node.inputs->size);
for (int i = 0; i < loop_end; ++i) {
if (node.inputs->data[i] == kTfLiteOptionalTensor) {
continue;
}
const bool input_shareable =
registration.inplace_operator & (kTfLiteInplaceOpInput0Shared << i);
if (input_shareable) {
const TfLiteTensor& input_tensor = tensors[node.inputs->data[i]];
if (InputTensorCanBeShared(input_tensor, output_tensor,
node.inputs->data[i], output_id,
tensor_changed)) {
input_id = node.inputs->data[i];
break;
}
}
}
if (input_id == -1) {
continue;
}
int32_t actual_output_tensor_id = FindSharedTensor(input_id);
if (tensor_changed) {
if (refcounts_[actual_output_tensor_id] > 1) {
continue;
}
}
actual_tensor_id_[output_id] = actual_output_tensor_id;
}
}
TfLiteStatus ArenaPlanner::PlanAllocations() {
// Invalidate any existing data.
const size_t num_tensors = graph_info_->num_tensors();
TF_LITE_ENSURE_STATUS(ResetAllocations());
// Maybe other verb instead of 'Assigned'
alloc_node_.assign(num_tensors, kNodeNotAssigned);
dealloc_node_.assign(num_tensors, kNodeNotAssigned);
nodes_to_tensors_.clear();
nodes_to_tensors_.resize(
std::max(graph_info_->num_execution_nodes(), (size_t)1), {});
// Keeps track of references to each tensor.
refcounts_.assign(num_tensors, 0);
auto allocate = [this](int node, int tensor) -> TfLiteStatus {
if (alloc_node_[tensor] != kNodeNotAssigned) {
// Tensor has already been allocated.
return kTfLiteOk;
}
TF_LITE_ENSURE(context_, dealloc_node_[tensor] == kNodeNotAssigned);
alloc_node_[tensor] = node;
return kTfLiteOk;
};
auto deallocate = [this](int node, int tensor) -> TfLiteStatus {
if (alloc_node_[tensor] == kNodeNotAssigned) {
// We don't need to deallocate the tensor, that is never allocated.
// This happened with the constant tensors.
return kTfLiteOk;
}
TF_LITE_ENSURE(context_, dealloc_node_[tensor] == kNodeNotAssigned);
dealloc_node_[tensor] = node;
return kTfLiteOk;
};
// We must make sure the output tensors are never overwritten. We do that by
// artificially adding one to their ref-counts so they are never selected
// for deallocation.
for (int tensor_index : graph_info_->outputs()) {
if (tensor_index != kTfLiteOptionalTensor) {
++refcounts_[tensor_index];
}
}
// Variable tensors also should be ensured to be never overwritten and need to
// be alive all the time.
for (int tensor_index : graph_info_->variables()) {
// Increase the reference count for variable tensors by one, so it will
// never be deallocated.
++refcounts_[tensor_index];
// `variables` is a subgraph-level list and it should never be
// kTfLiteOptionalTensor.
TF_LITE_ENSURE(context_, tensor_index != kTfLiteOptionalTensor);
// Variable tensor should be allocated at the very beginning.
TF_LITE_ENSURE_STATUS(allocate(0, tensor_index));
nodes_to_tensors_[0].insert(tensor_index);
}
// Queue all graph inputs for allocation and make sure they are never
// overwritten.
for (int tensor_index : graph_info_->inputs()) {
if (tensor_index != kTfLiteOptionalTensor) {
++refcounts_[tensor_index];
TF_LITE_ENSURE_STATUS(allocate(0, tensor_index));
nodes_to_tensors_[0].insert(tensor_index);
}
}
// Copy reference counts before sharing tensors so that the correct values are
// used to determine if a tensor may be shared or not.
std::vector<int> refcounts = refcounts_;
// Count references to node input tensors.
const int num_execution_nodes = graph_info_->num_execution_nodes();
for (size_t i = 0; i < num_execution_nodes; ++i) {
const TfLiteNode& node = graph_info_->node(i);
TfLiteIntArray* node_inputs = node.inputs;
for (int j = 0; j < node_inputs->size; ++j) {
int tensor_index = node_inputs->data[j];
if (tensor_index != kTfLiteOptionalTensor) {
++refcounts_[tensor_index];
}
}
}
IdentifyInPlaceTensors();
// Use the new reference counts to determine when tensors memory can safely be
// reused.
for (size_t i = 0; i < num_execution_nodes; ++i) {
const TfLiteNode& node = graph_info_->node(i);
TfLiteIntArray* node_inputs = node.inputs;
for (int j = 0; j < node_inputs->size; ++j) {
int tensor_index = node_inputs->data[j];
if (tensor_index != kTfLiteOptionalTensor) {
// Correctly count references for shared buffers.
tensor_index = FindSharedTensor(tensor_index);
++refcounts[tensor_index];
}
}
}
// Go through the graph in execution order.
for (size_t i = 0; i < num_execution_nodes; ++i) {
const TfLiteNode& node = graph_info_->node(i);
// First queue output tensors for allocation.
TfLiteIntArray* node_outputs = node.outputs;
for (int j = 0; j < node_outputs->size; ++j) {
int tensor_index = node_outputs->data[j];
if (tensor_index == kTfLiteOptionalTensor) continue;
// Don't allocate output tensors here for shared memory parts.
nodes_to_tensors_[i].insert(tensor_index);
TF_LITE_ENSURE_STATUS(allocate(i, tensor_index));
}
// Then update the ref-counts of the node's inputs, and if necessary queue
// them for deallocation.
if (!preserve_all_tensors_) {
TfLiteIntArray* node_inputs = node.inputs;
for (int j = 0; j < node_inputs->size; ++j) {
// If the tensor is a ref we decrement the original tensor.
int tensor_index = node_inputs->data[j];
if (tensor_index != kTfLiteOptionalTensor) {
// Correctly count references for shared buffers.
tensor_index = FindSharedTensor(tensor_index);
--refcounts[tensor_index];
if (refcounts[tensor_index] == 0) {
TF_LITE_ENSURE_STATUS(deallocate(i, tensor_index));
}
}
}
}
}
// Note that graph outputs will never be scheduled for deallocation. We
// could do that here for completeness, but it won't have any effect.
return kTfLiteOk;
}
TfLiteStatus ArenaPlanner::ExecuteAllocations(int first_node, int last_node) {
// Grow the size of `allocs_` if necessary. This allows allocating temporary
// tensors in op's `prepare` function.
const size_t num_tensors = graph_info_->num_tensors();
TF_LITE_ENSURE(context_, num_tensors >= allocs_.size());
alloc_node_.resize(num_tensors, kNodeNotAssigned);
dealloc_node_.resize(num_tensors, kNodeNotAssigned);
allocs_.resize(num_tensors);
// Set allocation and deallocation for temporary tensors.
const int num_execution_nodes = graph_info_->num_execution_nodes();
for (size_t i = first_node;
i <= static_cast<size_t>(last_node) && i < num_execution_nodes; ++i) {
const TfLiteNode& node = graph_info_->node(i);
TfLiteIntArray* node_temporaries = node.temporaries;
for (int j = 0; j < node_temporaries->size; ++j) {
int tensor_index = node_temporaries->data[j];
alloc_node_[tensor_index] = i;
nodes_to_tensors_[i].insert(tensor_index);
if (!preserve_all_tensors_) {
dealloc_node_[tensor_index] = i;
}
}
}
std::vector<int32_t> tensors_allocated;
TF_LITE_ENSURE_STATUS(
CalculateAllocations(first_node, last_node, &tensors_allocated));
bool arena_reallocated = false;
TF_LITE_ENSURE_STATUS(Commit(&arena_reallocated));
TfLiteTensor* tensors = graph_info_->tensors();
if (arena_reallocated) {
for (int i = 0; i < static_cast<int>(num_tensors); ++i) {
TF_LITE_ENSURE_STATUS(ResolveTensorAllocation(i, tensors));
}
} else {
for (int i = 0; i < static_cast<int>(tensors_allocated.size()); ++i) {
TF_LITE_ENSURE_STATUS(
ResolveTensorAllocation(tensors_allocated[i], tensors));
}
}
return kTfLiteOk;
}
TfLiteStatus ArenaPlanner::ReleaseNonPersistentMemory() {
// Clear non-persistent arena's buffer.
TF_LITE_ENSURE_STATUS(arena_.ReleaseBuffer());
has_nonpersistent_memory_ = false;
// Set data pointers for all non-persistent tensors to nullptr.
TfLiteTensor* tensors = graph_info_->tensors();
for (int i = 0; i < static_cast<int>(graph_info_->num_tensors()); ++i) {
TfLiteTensor& tensor = tensors[i];
if (tensor.allocation_type == kTfLiteArenaRw) {
tensor.data.raw = nullptr;
}
}
return kTfLiteOk;
}
TfLiteStatus ArenaPlanner::AcquireNonPersistentMemory() {
// First commit arena_ to allocate underlying buffer.
bool reallocated;
TF_LITE_ENSURE_STATUS(arena_.Commit(&reallocated));
has_nonpersistent_memory_ = true;
// Resolve allocations for all tensors not on the persistent arena.
TfLiteTensor* tensors = graph_info_->tensors();
for (int i = 0; i < static_cast<int>(graph_info_->num_tensors()); ++i) {
TfLiteTensor& tensor = tensors[i];
if (tensor.allocation_type == kTfLiteArenaRw) {
TF_LITE_ENSURE_STATUS(ResolveTensorAllocation(i, tensors));
}
}
return kTfLiteOk;
}
bool ArenaPlanner::HasNonPersistentMemory() {
return has_nonpersistent_memory_;
}
void ArenaPlanner::DumpDebugInfo(const std::vector<int>& execution_plan) const {
arena_.DumpDebugInfo("kTfLiteArenaRw Dump:", execution_plan);
persistent_arena_.DumpDebugInfo("kTfLiteArenaRwPersistent Dump:",
execution_plan);
}
void ArenaPlanner::GetAllocInfo(size_t* arena_size,
size_t* arena_persist_size) const {
*arena_size = arena_.GetBufferSize();
*arena_persist_size = persistent_arena_.GetBufferSize();
}
TfLiteStatus ArenaPlanner::Commit(bool* reallocated) {
bool arena_reallocated, persistent_arena_reallocated;
TF_LITE_ENSURE_STATUS(arena_.Commit(&arena_reallocated));
has_nonpersistent_memory_ = true;
TF_LITE_ENSURE_STATUS(
persistent_arena_.Commit(&persistent_arena_reallocated));
*reallocated = arena_reallocated;
*reallocated |= persistent_arena_reallocated;
return kTfLiteOk;
}
void ArenaPlanner::CreateTensorAllocationVector(
std::vector<int32_t>* tensors_to_allocate) {
const TfLiteTensor* tensors = this->graph_info_->tensors();
auto tensor_compare = [&](int idx1, int idx2) {
// Tensors that have lifespan through the whole model inference time are
// allocated at the beginning of memory slice. Their respective order
// doesn't matter in fact, so here they are sorted by index.
if (alloc_node_[idx1] == 0 && dealloc_node_[idx1] == kNodeNotAssigned) {
if (alloc_node_[idx2] == 0 && dealloc_node_[idx2] == kNodeNotAssigned) {
return idx1 < idx2;
}
return true;
}
if (alloc_node_[idx2] == 0 && dealloc_node_[idx2] == kNodeNotAssigned) {
return false;
}
// All other tensors are sorted in non-increasing order of their size.
auto size1 = tensors[idx1].bytes;
auto size2 = tensors[idx2].bytes;
if (size1 != size2) {
return size1 > size2;
}
// Tensors with equal size are sorted in order of their allocation time.
return alloc_node_[idx1] < alloc_node_[idx2];
};
// Indices of tensors in order their allocation offsets will be calculated.
std::sort(tensors_to_allocate->begin(), tensors_to_allocate->end(),
tensor_compare);
}
std::vector<int32_t> ArenaPlanner::GetTensorsToAllocate(int first_node,
int last_node) {
int num_tensors = static_cast<int>(graph_info_->num_tensors());
std::vector<int32_t> tensors_to_allocate;
tensors_to_allocate.reserve(num_tensors);
for (int i = first_node; i <= last_node; ++i) {
tensors_to_allocate.insert(tensors_to_allocate.end(),
nodes_to_tensors_[i].begin(),
nodes_to_tensors_[i].end());
}
return tensors_to_allocate;
}
TfLiteStatus ArenaPlanner::CalculateAllocations(
int first_node, int last_node, std::vector<int32_t>* tensors_allocated) {
// Indices of tensors in order their allocation offsets will be calculated.
const std::vector<int32_t> tensors_to_allocate =
GetTensorsToAllocate(first_node, last_node);
tensors_allocated->reserve(tensors_to_allocate.size());
// Deallocate if the tensor was already allocated.
TfLiteTensor* tensors = graph_info_->tensors();
for (const auto& tensor_index : tensors_to_allocate) {
TfLiteTensor& tensor = tensors[tensor_index];
// Only arena allocated tensors are allocated here.
if (tensor.allocation_type == kTfLiteArenaRw) {
if (allocs_[tensor_index].size < tensor.bytes) {
tensors_allocated->push_back(tensor_index);
}
} else if (tensor.allocation_type == kTfLiteArenaRwPersistent) {
tensors_allocated->push_back(tensor_index);
}
}
if (tensors_allocated->empty()) {
last_active_node_ = last_node;
return kTfLiteOk;
}
if (first_node < last_active_node_) {
arena_.ResetAllocs();
last_active_node_ = first_node;
} else {
// NOMUTANTS -- This function has no impact on the results, it only makes
// exection faster.
arena_.PurgeActiveAllocs(first_node);
}
CreateTensorAllocationVector(tensors_allocated);
// Vector of ids of already allocated tensors, ordered by offset.
for (const auto& tensor_index : *tensors_allocated) {
TfLiteTensor& tensor = tensors[tensor_index];
// Only allocate ArenaRw tensors which own their buffer.
auto it = actual_tensor_id_.find(tensor_index);
if (it != actual_tensor_id_.end()) {
// A tensor whose buffer is shared may have had its allocation type
// changed to kTfLiteCustom or kTfLiteDynamic after `PlanAllocations` was
// called. This means that the buffer is no longer shareable so remove its
// index from `actual_tensor_id_`.
// A call to `ResizeInputTensor` may cause the form of a broadcast op
// meaning that tensor sharing is no longer valid.
TfLiteAllocationType allocation_type =
tensors[it->second].allocation_type;
if (allocation_type != kTfLiteArenaRw ||
tensors[it->second].bytes != tensors[it->first].bytes) {
actual_tensor_id_.erase(it);
} else {
// Don't allocate the tensor, it can safely share the input buffer.
continue;
}
}
if (tensor.allocation_type == kTfLiteArenaRw) {
TF_LITE_ENSURE_STATUS(
arena_.Allocate(context_, tensor_alignment_, tensor.bytes,
tensor_index, alloc_node_[tensor_index],
dealloc_node_[tensor_index], &allocs_[tensor_index]));
}
// Check allocs_[].size to prevent from reallocation of persistent tensors.
// Only allocate ArenaRwPersistent tensors which own their buffer.
if (tensor.allocation_type == kTfLiteArenaRwPersistent &&
allocs_[tensor_index].size == 0) {
if (allocs_[tensor_index].size < tensor.bytes) {
TF_LITE_ENSURE_STATUS(persistent_arena_.Allocate(
context_, tensor_alignment_, tensor.bytes, tensor_index,
/*first_node=*/alloc_node_[tensor_index],
/*last_node=*/std::numeric_limits<int32_t>::max(),
&allocs_[tensor_index]));
}
}
}
last_active_node_ = last_node;
return kTfLiteOk;
}
bool AreTensorsAllocatedInSameArena(int32_t root_tensor_index,
int32_t tensor_index,
const TfLiteTensor* tensors) {
if (tensors[root_tensor_index].allocation_type == kTfLiteArenaRw &&
tensors[tensor_index].allocation_type == kTfLiteArenaRw) {
return true;
}
if (tensors[root_tensor_index].allocation_type == kTfLiteArenaRwPersistent &&
tensors[tensor_index].allocation_type == kTfLiteArenaRwPersistent) {
return true;
}
return false;
}
TfLiteStatus ArenaPlanner::ResolveTensorAllocation(int32_t tensor_index,
TfLiteTensor* tensors) {
// Resolve allocation for tensors which share buffers.
auto actual_tensor_it = actual_tensor_id_.find(tensor_index);
TfLiteTensor& tensor = tensors[tensor_index];
int32_t root_tensor_index = actual_tensor_it == actual_tensor_id_.end()
? tensor_index
: actual_tensor_it->second;
const TfLiteTensor& root_tensor = tensors[root_tensor_index];
if (root_tensor_index != tensor_index) {
if (AreTensorsAllocatedInSameArena(root_tensor_index, tensor_index,
tensors)) {
// Make sure that the input tensor has already been allocated.
ResolveTensorAllocation(root_tensor_index, tensors);
tensor.data.data = root_tensor.data.data;
return kTfLiteOk;
}
}
if (tensor.allocation_type == kTfLiteArenaRw) {
// Skip resolution if the size of the tensor is zero, leaving it as a
// nullptr.
if (allocs_[tensor_index].size != 0) {
return arena_.ResolveAlloc(context_, allocs_[tensor_index],
&tensor.data.raw);
}
}
if (tensor.allocation_type == kTfLiteArenaRwPersistent) {
return persistent_arena_.ResolveAlloc(context_, allocs_[tensor_index],
&tensor.data.raw);
}
return kTfLiteOk;
}
} // namespace tflite
+173
View File
@@ -0,0 +1,173 @@
/* Copyright 2017 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_ARENA_PLANNER_H_
#define TENSORFLOW_LITE_ARENA_PLANNER_H_
#include <cstddef>
#include <cstdint>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/graph_info.h"
#include "tensorflow/lite/memory_planner.h"
#include "tensorflow/lite/simple_memory_arena.h"
#include "tensorflow/lite/util.h"
namespace tflite {
constexpr const int kDefaultArenaAlignment = 64;
// A memory planner that makes all the allocations using arenas.
//
// Before a model is executed by the interpreter, this class determines when
// each tensor needs to be allocated and deallocated, and preallocates all the
// necessary memory (the PlanAllocations phase). It then assigns portions of
// this memory buffer to each tensor (the ExecuteAllocations phase). Tensors may
// share some of the buffer if a tensor B is to be allocated after another
// tensor A has been deallocated.
//
// If dynamic tensors are used the planning steps can be repeated during model
// execution. Since dynamic tensors don't have sizes until after the
// corresponding operation is executed, this class supports incremental
// planning.
class ArenaPlanner : public MemoryPlanner {
public:
// Ownership of 'context' is not taken and it must remain util the
// ArenaPlanner is destroyed. The inputs to the graph will not share
// memory with any other tensor, effectively preserving them until the end
// of inference.
ArenaPlanner(TfLiteContext* context, std::unique_ptr<GraphInfo> graph_info,
bool preserve_all_tensors, int tensor_alignment,
int subgraph_index = 0);
~ArenaPlanner() override;
ArenaPlanner(const ArenaPlanner&) = delete;
ArenaPlanner& operator=(const ArenaPlanner&) = delete;
TfLiteStatus ResetAllocations() override;
TfLiteStatus ResetAllocationsAfter(int node) override;
TfLiteStatus PlanAllocations() override;
TfLiteStatus ExecuteAllocations(int first_node, int last_node) override;
TfLiteStatus ReleaseNonPersistentMemory() override;
TfLiteStatus AcquireNonPersistentMemory() override;
bool HasNonPersistentMemory() override;
void DumpDebugInfo(const std::vector<int>& execution_plan) const override;
void GetAllocInfo(size_t* arena_size,
size_t* arena_persist_size) const override;
// Returns the base arena location for a given allocation type.
std::intptr_t BasePointer(TfLiteAllocationType type);
private:
// Check whether the input tensor's memory may be shared the output tensor.
// tensor_changed: true if the output tensor modifies the tensor data. For
// example, `Reshape` doesn't modify data but Add does.
bool InputTensorCanBeShared(const TfLiteTensor& input,
const TfLiteTensor& output, int input_id,
int output_id, bool tensor_changed);
// Identify tensors which can share memory with another.
void IdentifyInPlaceTensors();
// Make sure all the arenas have reserved enough memory to store all their
// tensors.
TfLiteStatus Commit(bool* arena_reallocated);
// Sorts tensors_to_allocate` using by the following ordering:
// - Tensors that have lifespan through the whole model inference time go
// first;
// - Other tensors (e.g. intermediate and temporary ones) are sorted from
// largest to smallest. For equal sized tensors, the tensor which is used
// first goes first.
void CreateTensorAllocationVector(std::vector<int32_t>* tensors_to_allocate);
// Returns vector containing the indices of all tensors allocated between
// `first_node` and `last_node`.
std::vector<int32_t> GetTensorsToAllocate(int first_node, int last_node);
// Traverse the allocation queue and reserve space in the appropriate arena
// for all tensors affected by ops in the interval [first_node, last_node].
TfLiteStatus CalculateAllocations(int first_node, int last_node,
std::vector<int32_t>* tensors_allocated);
// Assign absolute memory location to a tensor, based on its relative
// position inside the corresponding arena buffer.
TfLiteStatus ResolveTensorAllocation(int32_t tensor_index,
TfLiteTensor* tensors);
// Register an allocation for all internal (temporary) tensors of
// 'node_index'.
TfLiteStatus CalculateAllocationOfInternalTensors(int node_index);
// Register a deallocation for all internal (temporary) tensors of
// 'node_index'.
TfLiteStatus CalculateDeallocationOfInternalTensors(int node_index);
// Return the index of the tensor owing `tensor_index's` buffer.
int FindSharedTensor(int tensor_index);
TfLiteContext* context_;
std::unique_ptr<GraphInfo> graph_info_;
// Stores allocation data for all tensors.
std::vector<ArenaAllocWithUsageInterval> allocs_;
// Map of Tensors allocated by each node.
// NOLINTNEXTLINE - absl::flat_hash_set increases binary size by 106kB.
std::vector<std::unordered_set<int32_t>> nodes_to_tensors_;
// First node, that uses the tensor. It needs to be allocated before
// execution of the node's operation.
std::vector<int32_t> alloc_node_;
// Last node, that uses the tensor. It can be deallocated after execution of
// the node's operation.
std::vector<int32_t> dealloc_node_;
// Raw memory buffer that is allocated for all temporary and graph outputs
// that are declared kTfLiteArenaRw.
SimpleMemoryArena arena_;
// True when the arena_ has allocated memory (Commit was called).
bool has_nonpersistent_memory_;
// Raw memory buffer that is allocated for persistent tensors that are
// declared as kTfLiteArenaRwPersistent.
SimpleMemoryArena persistent_arena_;
// If true, then no overlapping of memory areas is done, meaning intermediate
// tensors and temporary tensors can be queried after running.
// (modulo running delegates)
bool preserve_all_tensors_;
// Number of bytes that tensor buffers should be aligned to.
int tensor_alignment_;
// Index of the last node whose tensors were allocated.
int last_active_node_;
// Holds index of original tensor if the tensor is sharing underlined
// data with another tensor.
// NOLINTNEXTLINE - absl::flat_hash_map increases binary size by 106kB.
std::unordered_map<int32_t, int32_t> actual_tensor_id_;
// Store number of references to each tensor.
std::vector<int> refcounts_;
};
} // namespace tflite
#endif // TENSORFLOW_LITE_ARENA_PLANNER_H_
@@ -0,0 +1,160 @@
/* Copyright 2017 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 <vector>
#include <gtest/gtest.h>
#include "tensorflow/lite/c/c_api_types.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/kernels/subgraph_test_util.h"
namespace tflite {
namespace {
TEST(ArenaPlannerSubgraphTest, TestSubgraphInputsAndOutputsNotShared) {
Interpreter interpreter;
subgraph_test_util::SubgraphBuilder builder;
builder.BuildInplaceOpSubgraph(&interpreter.primary_subgraph());
ASSERT_EQ(interpreter.ResizeInputTensor(interpreter.inputs()[0], {2}),
kTfLiteOk);
ASSERT_EQ(interpreter.ResizeInputTensor(interpreter.inputs()[1], {2}),
kTfLiteOk);
ASSERT_EQ(interpreter.AllocateTensors(), kTfLiteOk);
const TfLiteTensor* add_input0 = interpreter.tensor(interpreter.inputs()[0]);
const TfLiteTensor* add_input1 = interpreter.tensor(interpreter.inputs()[1]);
const int kIntermediateTensor0 = 2;
const int kIntermediateTensor1 = 3;
const TfLiteTensor* add_output = interpreter.tensor(kIntermediateTensor0);
const TfLiteTensor* reshape_output = interpreter.tensor(kIntermediateTensor1);
const TfLiteTensor* subgraph_output =
interpreter.tensor(interpreter.outputs()[0]);
// Neither input to ADD may be shared since they are subgraph inputs.
EXPECT_NE(add_input0->data.data, add_output->data.data);
EXPECT_NE(add_input1->data.data, add_output->data.data);
// The output of ADD may be shared with the output of RESHAPE.
EXPECT_EQ(add_output->data.data, reshape_output->data.data);
// RESHAPE's output can't be shared as the output of the following op is a
// subgraph output.
EXPECT_NE(reshape_output->data.data, subgraph_output->data.data);
}
TEST(ArenaPlannerSubgraphTest, TestSharingBroadcastOps) {
Interpreter interpreter;
subgraph_test_util::SubgraphBuilder builder;
builder.BuildBroadcastingSubgraph(&interpreter.primary_subgraph());
ASSERT_EQ(interpreter.ResizeInputTensor(interpreter.inputs()[0], {1}),
kTfLiteOk);
ASSERT_EQ(interpreter.ResizeInputTensor(interpreter.inputs()[1], {2}),
kTfLiteOk);
ASSERT_EQ(interpreter.AllocateTensors(), kTfLiteOk);
TfLiteTensor* subgraph_input0 = interpreter.tensor(interpreter.inputs()[0]);
TfLiteTensor* subgraph_input1 = interpreter.tensor(interpreter.inputs()[1]);
const int kIntermediateTensor0 = 2;
const int kIntermediateTensor1 = 3;
const int kIntermediateTensor2 = 4;
const int kIntermediateTensor3 = 5;
const TfLiteTensor* intermediate_tensor0 =
interpreter.tensor(kIntermediateTensor0);
const TfLiteTensor* intermediate_tensor1 =
interpreter.tensor(kIntermediateTensor1);
const TfLiteTensor* intermediate_tensor2 =
interpreter.tensor(kIntermediateTensor2);
const TfLiteTensor* intermediate_tensor3 =
interpreter.tensor(kIntermediateTensor3);
subgraph_test_util::FillIntTensor(subgraph_input0, {1});
subgraph_test_util::FillIntTensor(subgraph_input1, {2, 2});
const TfLiteTensor* subgraph_output =
interpreter.tensor(interpreter.outputs()[0]);
// Neither input to ADD may be shared since they are subgraph inputs.
EXPECT_NE(subgraph_input0->data.data, intermediate_tensor0->data.data);
EXPECT_NE(subgraph_input1->data.data, intermediate_tensor0->data.data);
// The 2nd ADD op consumes intermediate_tensor0 twice. Since there is more
// than one consumer, sharing is not possible.
EXPECT_NE(intermediate_tensor0->data.data, intermediate_tensor1->data.data);
// intermediate_tensor1 can be shared with intermediate_tensor2.
EXPECT_EQ(intermediate_tensor1->data.data, intermediate_tensor2->data.data);
// intermediate_tensor3 cannot be shared with a subgraph output.
EXPECT_NE(intermediate_tensor3->data.data, subgraph_output->data.data);
ASSERT_EQ(interpreter.Invoke(), kTfLiteOk);
subgraph_test_util::CheckIntTensor(subgraph_output, {2}, {9, 9});
}
TEST(ArenaPlannerSubgraphTest, TestOffsetAddSharing) {
Interpreter interpreter;
subgraph_test_util::SubgraphBuilder builder;
builder.BuildOffsetAddSharing(&interpreter.primary_subgraph());
ASSERT_EQ(interpreter.ResizeInputTensor(interpreter.inputs()[0], {1}),
kTfLiteOk);
ASSERT_EQ(interpreter.ResizeInputTensor(interpreter.inputs()[1], {3}),
kTfLiteOk);
ASSERT_EQ(interpreter.AllocateTensors(), kTfLiteOk);
TfLiteTensor* subgraph_input0 = interpreter.tensor(interpreter.inputs()[0]);
TfLiteTensor* subgraph_input1 = interpreter.tensor(interpreter.inputs()[1]);
const int kIntermediateTensor0 = 2;
const int kIntermediateTensor1 = 3;
const int kIntermediateTensor2 = 4;
const TfLiteTensor* intermediate_tensor0 =
interpreter.tensor(kIntermediateTensor0);
const TfLiteTensor* intermediate_tensor1 =
interpreter.tensor(kIntermediateTensor1);
const TfLiteTensor* intermediate_tensor2 =
interpreter.tensor(kIntermediateTensor2);
subgraph_test_util::FillIntTensor(subgraph_input0, {1});
subgraph_test_util::FillIntTensor(subgraph_input1, {3, 4, 5});
const TfLiteTensor* subgraph_output =
interpreter.tensor(interpreter.outputs()[0]);
// Neither input to ADD may be shared since they are subgraph inputs.
EXPECT_NE(subgraph_input0->data.data, intermediate_tensor0->data.data);
EXPECT_NE(subgraph_input1->data.data, intermediate_tensor1->data.data);
// ADD_OFFSET allows sharing of input1, but not input0.
EXPECT_EQ(intermediate_tensor1->data.data, intermediate_tensor2->data.data);
// intermediate_tensor2 cannot be shared with a subgraph output.
EXPECT_NE(intermediate_tensor2->data.data, subgraph_output->data.data);
ASSERT_EQ(interpreter.Invoke(), kTfLiteOk);
subgraph_test_util::CheckIntTensor(subgraph_output, {3}, {10, 12, 11});
}
TEST(ArenaPlannerSubgraphTest, HWTensor) {
Interpreter interpreter;
subgraph_test_util::SubgraphBuilder builder;
builder.BuildInplaceOpSubgraph(&interpreter.primary_subgraph());
ASSERT_EQ(interpreter.ResizeInputTensor(interpreter.inputs()[0], {2}),
kTfLiteOk);
ASSERT_EQ(interpreter.ResizeInputTensor(interpreter.inputs()[1], {2}),
kTfLiteOk);
TfLiteTensor* add_input0 = interpreter.tensor(interpreter.inputs()[0]);
const TfLiteTensor* add_input1 = interpreter.tensor(interpreter.inputs()[1]);
const int kIntermediateTensor0 = 2;
const int kIntermediateTensor1 = 3;
const TfLiteTensor* add_output = interpreter.tensor(kIntermediateTensor0);
const TfLiteTensor* reshape_output = interpreter.tensor(kIntermediateTensor1);
TfLiteTensor* subgraph_output = interpreter.tensor(interpreter.outputs()[0]);
add_input0->allocation_type = kTfLiteNonCpu;
subgraph_output->allocation_type = kTfLiteNonCpu;
ASSERT_EQ(interpreter.AllocateTensors(), kTfLiteOk);
// Non-CPU tensors shouldn't be allocated.
EXPECT_EQ(add_input0->data.data, nullptr);
EXPECT_EQ(subgraph_output->data.data, nullptr);
// CPU tensors should be allocated.
EXPECT_NE(add_input1->data.data, nullptr);
EXPECT_NE(add_output->data.data, nullptr);
EXPECT_NE(reshape_output->data.data, nullptr);
}
} // namespace
} // namespace tflite
File diff suppressed because it is too large Load Diff
+37
View File
@@ -0,0 +1,37 @@
/* Copyright 2023 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/array.h"
#include "tensorflow/lite/c/common.h"
namespace tflite {
namespace array_internal {
#ifndef TF_LITE_STATIC_MEMORY
void TfLiteArrayDeleter::operator()(TfLiteIntArray* a) {
if (a) {
TfLiteIntArrayFree(a);
}
}
void TfLiteArrayDeleter::operator()(TfLiteFloatArray* a) {
if (a) {
TfLiteFloatArrayFree(a);
}
}
#endif // TF_LITE_STATIC_MEMORY
} // namespace array_internal
} // namespace tflite
+158
View File
@@ -0,0 +1,158 @@
/* Copyright 2023 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_ARRAY_H_
#define TENSORFLOW_LITE_ARRAY_H_
#include <cstring>
#include <initializer_list>
#include <memory>
#include <type_traits>
#include <vector>
#include "tensorflow/lite/core/c/common.h"
namespace tflite {
/// TfLite*Array helpers
namespace array_internal {
// Function object used as a deleter for unique_ptr holding TFLite*Array
// objects.
struct TfLiteArrayDeleter {
void operator()(TfLiteIntArray* a);
void operator()(TfLiteFloatArray* a);
};
// Maps T to the corresponding TfLiteArray type.
template <class T>
struct TfLiteArrayInfo;
template <>
struct TfLiteArrayInfo<int> {
using Type = TfLiteIntArray;
};
template <>
struct TfLiteArrayInfo<float> {
using Type = TfLiteFloatArray;
};
} // namespace array_internal
template <class T>
using TfLiteArrayUniquePtr =
std::unique_ptr<typename array_internal::TfLiteArrayInfo<T>::Type,
array_internal::TfLiteArrayDeleter>;
// `unique_ptr` wrapper for `TfLiteIntArray`s.
using IntArrayUniquePtr = TfLiteArrayUniquePtr<int>;
// `unique_ptr` wrapper for `TfLiteFloatArray`s.
using FloatArrayUniquePtr = TfLiteArrayUniquePtr<float>;
// Allocates a TfLiteArray of given size using malloc.
//
// This builds an int array by default as this is the overwhelming part of the
// use cases.
template <class T = int>
TfLiteArrayUniquePtr<T> BuildTfLiteArray(int size);
#ifndef TF_LITE_STATIC_MEMORY
// Allocates a TfLiteIntArray of given size using malloc.
template <>
inline IntArrayUniquePtr BuildTfLiteArray<int>(const int size) {
return IntArrayUniquePtr(TfLiteIntArrayCreate(size));
}
// Allocates a TfLiteFloatArray of given size using malloc.
template <>
inline FloatArrayUniquePtr BuildTfLiteArray<float>(const int size) {
return FloatArrayUniquePtr(TfLiteFloatArrayCreate(size));
}
#endif // TF_LITE_STATIC_MEMORY
// Allocates a TFLiteArray of given size and initializes it with the given
// values.
//
// `values` is expected to holds `size` elements.
//
// If T is explicitely specified and the type of values is not the same as T,
// then a static_cast is performed.
template <class T = void, class U,
class Type = std::conditional_t<std::is_same<T, void>::value, U, T>>
TfLiteArrayUniquePtr<Type> BuildTfLiteArray(const int size,
const U* const values) {
TfLiteArrayUniquePtr<Type> array = BuildTfLiteArray<Type>(size);
// If size is 0, the array pointer may be null.
if (array && values) {
if (std::is_same<Type, U>::value) {
memcpy(array->data, values, size * sizeof(Type));
} else {
for (int i = 0; i < size; ++i) {
array->data[i] = static_cast<Type>(values[i]);
}
}
}
return array;
}
// Allocates a TFLiteArray and initializes it with the given array.
//
// `values` is expected to holds `size` elements.
template <class T, size_t N>
TfLiteArrayUniquePtr<T> BuildTfLiteArray(const T (&values)[N]) {
return BuildTfLiteArray<T>(static_cast<int>(N), values);
}
// Allocates a TFLiteArray and initializes it with the given values.
//
// This uses SFINAE to only be picked up by for types that implement `data()`
// and `size()` member functions. We cannot reuse detection facilities provided
// by Abseil in this code.
//
// To conform with the other overloads, we allow specifying the type of the
// array as well as deducing it from the container.
template <
class T = void, class Container,
class ElementType =
std::decay_t<decltype(*std::declval<Container>().data())>,
class SizeType = std::decay_t<decltype(std::declval<Container>().size())>,
class Type =
std::conditional_t<std::is_same<T, void>::value, ElementType, T>>
TfLiteArrayUniquePtr<Type> BuildTfLiteArray(const Container& values) {
return BuildTfLiteArray<Type>(static_cast<int>(values.size()), values.data());
}
// Allocates a TFLiteArray and initializes it with the given values.
template <class T>
TfLiteArrayUniquePtr<T> BuildTfLiteArray(
const std::initializer_list<T>& values) {
return BuildTfLiteArray(static_cast<int>(values.size()), values.begin());
}
// Allocates a TFLiteArray and initializes it with the given array.
inline IntArrayUniquePtr BuildTfLiteArray(const TfLiteIntArray& other) {
return BuildTfLiteArray(other.size, other.data);
}
// Allocates a TFLiteArray and initializes it with the given array.
inline FloatArrayUniquePtr BuildTfLiteArray(const TfLiteFloatArray& other) {
return BuildTfLiteArray(other.size, other.data);
}
} // namespace tflite
#endif // TENSORFLOW_LITE_ARRAY_H_
+136
View File
@@ -0,0 +1,136 @@
/* Copyright 2023 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/array.h"
#include <algorithm>
#include <cstddef>
#include <initializer_list>
#include <type_traits>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/types/span.h"
#include "tensorflow/lite/core/c/common.h"
using testing::ElementsAreArray;
using testing::Eq;
namespace tflite {
namespace {
absl::Span<int> GetSpan(TfLiteIntArray& array) {
return {array.data, static_cast<size_t>(array.size)};
}
absl::Span<float> GetSpan(TfLiteFloatArray& array) {
return {array.data, static_cast<size_t>(array.size)};
}
template <class T>
class TfLiteArrayTest : public testing::Test {
static_assert(
std::is_same_v<TfLiteIntArray, TfLiteArrayUniquePtr<int>::element_type>,
"TfLiteArrayUniquePtr<int>::element_type should be TfLiteIntArray");
static_assert(
std::is_same_v<TfLiteFloatArray,
TfLiteArrayUniquePtr<float>::element_type>,
"TfLiteArrayUniquePtr<float>::element_type should be TfLiteFloatArray");
};
using ArrayTypes = testing::Types<int, float>;
TYPED_TEST_SUITE(TfLiteArrayTest, ArrayTypes);
TYPED_TEST(TfLiteArrayTest, BuildArrayWithSize) {
constexpr int size = 3;
TfLiteArrayUniquePtr<TypeParam> array = BuildTfLiteArray<TypeParam>(size);
ASSERT_NE(array, nullptr);
EXPECT_THAT(array->size, Eq(size));
// Touch data to check that allocation is not too small.
std::fill_n(array->data, size, static_cast<TypeParam>(1));
}
TYPED_TEST(TfLiteArrayTest, BuildFromDynamicArray) {
constexpr int size = 4;
constexpr TypeParam values[size] = {1, 2, 3, 4};
TfLiteArrayUniquePtr<TypeParam> array = BuildTfLiteArray(size, values);
ASSERT_NE(array, nullptr);
EXPECT_THAT(array->size, Eq(size));
EXPECT_THAT(GetSpan(*array), ElementsAreArray(values));
}
TYPED_TEST(TfLiteArrayTest, BuildFromCArray) {
TypeParam values[] = {1, 2, 3, 4};
TfLiteArrayUniquePtr<TypeParam> array = BuildTfLiteArray(values);
ASSERT_NE(array, nullptr);
EXPECT_THAT(array->size, Eq(sizeof(values) / sizeof(TypeParam)));
EXPECT_THAT(GetSpan(*array), ElementsAreArray(values));
}
TYPED_TEST(TfLiteArrayTest, BuildFromVector) {
std::vector<TypeParam> values = {1, 2, 3, 4};
TfLiteArrayUniquePtr<TypeParam> array = BuildTfLiteArray(values);
ASSERT_NE(array, nullptr);
EXPECT_THAT(array->size, Eq(values.size()));
EXPECT_THAT(GetSpan(*array), ElementsAreArray(values));
}
TYPED_TEST(TfLiteArrayTest, BuildFromVectorForceType) {
using DifferentType =
std::conditional_t<std::is_same_v<TypeParam, int>, float, int>;
std::vector<DifferentType> values = {1, 2, 3, 4};
TfLiteArrayUniquePtr<TypeParam> array = BuildTfLiteArray<TypeParam>(values);
ASSERT_NE(array, nullptr);
EXPECT_THAT(array->size, Eq(values.size()));
EXPECT_THAT(GetSpan(*array), ElementsAreArray(values));
}
TYPED_TEST(TfLiteArrayTest, BuildFromSpan) {
std::vector<TypeParam> values = {1, 2, 3, 4};
TfLiteArrayUniquePtr<TypeParam> array =
BuildTfLiteArray(absl::Span<const TypeParam>(values));
ASSERT_NE(array, nullptr);
EXPECT_THAT(array->size, Eq(values.size()));
EXPECT_THAT(GetSpan(*array), ElementsAreArray(values));
}
TYPED_TEST(TfLiteArrayTest, BuildFromInitializerList) {
std::initializer_list<TypeParam> values{1, 2, 3, 4};
TfLiteArrayUniquePtr<TypeParam> array = BuildTfLiteArray(values);
ASSERT_NE(array, nullptr);
EXPECT_THAT(array->size, Eq(values.size()));
EXPECT_THAT(GetSpan(*array), ElementsAreArray(values));
}
TYPED_TEST(TfLiteArrayTest, BuildUsingSingleElementInitializerList) {
constexpr TypeParam value = 42;
TfLiteArrayUniquePtr<TypeParam> array = BuildTfLiteArray({value});
ASSERT_NE(array, nullptr);
EXPECT_THAT(array->size, Eq(1));
EXPECT_THAT(array->data[0], Eq(value));
}
TYPED_TEST(TfLiteArrayTest, BuildFromTfLiteArray) {
std::initializer_list<TypeParam> values{1, 2, 3, 4};
const auto ref = BuildTfLiteArray(values);
TfLiteArrayUniquePtr<TypeParam> array = BuildTfLiteArray(*ref);
ASSERT_NE(array, nullptr);
EXPECT_THAT(array->size, Eq(values.size()));
EXPECT_THAT(GetSpan(*array), ElementsAreArray(values));
}
} // namespace
} // namespace tflite
+41
View File
@@ -0,0 +1,41 @@
load("@rules_cc//cc:cc_test.bzl", "cc_test")
# Description:
#
# This package contains shim library targets for the Async C package.
load("//tensorflow/lite/core/shims:cc_library_with_tflite.bzl", "cc_library_with_tflite")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//visibility:private",
],
licenses = ["notice"],
)
cc_library_with_tflite(
name = "backend_async_kernel_interface",
srcs = ["backend_async_kernel_interface.cc"],
hdrs = ["backend_async_kernel_interface.h"],
tflite_deps = [
"//tensorflow/lite/async/c:async_kernel",
"//tensorflow/lite/async/c:types",
"//tensorflow/lite/c:c_api_types",
"//tensorflow/lite/c:common",
],
visibility = ["//visibility:public"],
)
cc_test(
name = "backend_async_kernel_interface_test",
srcs = ["backend_async_kernel_interface_test.cc"],
deps = [
":backend_async_kernel_interface",
"//tensorflow/lite/async/c:types",
"//tensorflow/lite/c:c_api_types",
"//tensorflow/lite/c:common",
"//tensorflow/lite/core/async:async_kernel_internal",
"//tensorflow/lite/core/async/testing:mock_async_kernel",
"@com_google_googletest//:gtest_main",
],
)
@@ -0,0 +1,198 @@
/* Copyright 2022 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/async/backend_async_kernel_interface.h"
#include <cstddef>
#include <vector>
#include "tensorflow/lite/async/c/async_kernel.h"
#include "tensorflow/lite/async/c/types.h"
namespace tflite {
namespace delegates {
namespace internal {
TfLiteStatus RegisterBuffer(TfLiteAsyncKernel* async_kernel,
TfLiteOpaqueContext* context, TfLiteIoType io_type,
const TfLiteBackendBuffer* buffer,
const TfLiteAttributeMap* attrs,
TfLiteBufferHandle handle) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->RegisterBuffer(context, io_type, buffer, attrs, handle);
}
// Registers a buffer slice from a previously registered memory.
// `attrs` contains the information of the memory, but also additional slice
// information.
TfLiteStatus RegisterBufferSlice(TfLiteAsyncKernel* async_kernel,
TfLiteOpaqueContext* context,
TfLiteBufferHandle buffer,
const TfLiteAttributeMap* attrs,
TfLiteBufferHandle handle) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->RegisterBufferSlice(context, buffer, attrs, handle);
}
// Unregisters a buffer or a buffer slice.
TfLiteStatus UnregisterBuffer(TfLiteAsyncKernel* async_kernel,
TfLiteOpaqueContext* context,
const TfLiteBufferHandle handle) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->UnregisterBuffer(context, handle);
}
// Reconciliations
// ===================
// Inspects the buffer / sync implementation types supported by the backend.
void SupportedBufferTypes(const TfLiteAsyncKernel* async_kernel,
TfLiteIoType io_type, const char* const** types,
size_t* n_types) {
if (types == nullptr || n_types == nullptr) return;
const auto& buf_types = reinterpret_cast<const BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->SupportedBufferTypes(io_type);
*types = buf_types.data();
*n_types = buf_types.size();
}
void SupportedSynchronizations(const TfLiteAsyncKernel* async_kernel,
TfLiteIoType io_type, const char* const** types,
size_t* n_types) {
if (types == nullptr || n_types == nullptr) return;
const auto& sync_types = reinterpret_cast<const BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->SupportedSynchronizations(io_type);
*types = sync_types.data();
*n_types = sync_types.size();
}
// Reconciles buffer or sync attributes for tensor at tensor_index.
// Fills `merged` with reconciled attributes.
// If `conflict` is provided, conflicting attributes will be provided there.
// Returns true if there's no conflict.
bool ReconcileRestrictions(const TfLiteAsyncKernel* async_kernel,
const TfLiteOpaqueContext* context,
const TfLiteOpaqueNode* node, int tensor_index,
const TfLiteAttributeMap* user_provided_attributes,
TfLiteAttributeMap* merged,
TfLiteAttributeMap* conflict) {
return reinterpret_cast<const BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->ReconcileRestrictions(context, node, tensor_index,
user_provided_attributes, merged, conflict);
}
// Sets the input / output buffer / sync attributes.
// Backend kernel will check the input attributes covers all the requirements.
// A typical workflow is for callers call Reconcile*Restrictions method
// above to have a merged attribute list, check all restrictions are met
// and set input / output attribute here.
// Returns TfLiteOk if provided `attrs` covers all requirements.
TfLiteStatus SetAttributes(TfLiteAsyncKernel* async_kernel,
TfLiteOpaqueContext* context, TfLiteOpaqueNode* node,
int tensor_index, const TfLiteAttributeMap* attrs) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->SetAttributes(context, node, tensor_index, attrs);
}
// Prepares the kernel using the information from Set[In|Out]putAttributes
// call above.
TfLiteStatus Prepare(TfLiteAsyncKernel* async_kernel,
TfLiteOpaqueContext* context, TfLiteOpaqueNode* node) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->Prepare(context, node);
}
// Execution methods
// =============================
// Schedules an execution with the information provided in task.
// The application is responsible for filling out buffer and sync mappings
// to tensors.
// Backend will set the sync ptr for related tensors if requested.
// i.e. SetOutputAttributes has sync implementation requested, and
// the TfLiteSynchronization is not null for the tensor in `task`.
// Returns TfLiteOk if the execution is successfully scheduled.
TfLiteStatus Eval(TfLiteAsyncKernel* async_kernel, TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node, TfLiteExecutionTask* task) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->Eval(context, node, task);
}
// Waits on the execution scheduled using the task to finish.
TfLiteStatus Wait(TfLiteAsyncKernel* async_kernel, TfLiteOpaqueContext* context,
TfLiteExecutionTask* task) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->Wait(context, task);
}
// Finishes the task and clean up allocated resources for the task.
TfLiteStatus Finish(TfLiteAsyncKernel* async_kernel,
TfLiteOpaqueContext* context, TfLiteExecutionTask* task) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->Finish(context, task);
}
TfLiteStatus SetBufferAttributes(TfLiteAsyncKernel* async_kernel,
const TfLiteBackendBuffer* buffer,
const TfLiteAttributeMap* attrs) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->SetBufferAttributes(buffer, attrs);
}
TfLiteStatus GetBufferAttributes(TfLiteAsyncKernel* async_kernel,
const TfLiteBackendBuffer* buffer,
TfLiteAttributeMap* attrs) {
return reinterpret_cast<BackendAsyncKernelInterface*>(
TfLiteAsyncKernelGetKernelData(async_kernel))
->GetBufferAttributes(buffer, attrs);
}
} // namespace internal
BackendAsyncKernelInterface::BackendAsyncKernelInterface() {
kernel_ = TfLiteAsyncKernelCreate(this);
TfLiteAsyncKernelSetRegisterBuffer(kernel_, internal::RegisterBuffer);
TfLiteAsyncKernelSetRegisterBufferSlice(kernel_,
internal::RegisterBufferSlice);
TfLiteAsyncKernelSetUnregisterBuffer(kernel_, internal::UnregisterBuffer);
TfLiteAsyncKernelSetSupportedBufferTypes(kernel_,
internal::SupportedBufferTypes);
TfLiteAsyncKernelSetSupportedSynchronizations(
kernel_, internal::SupportedSynchronizations);
TfLiteAsyncKernelSetReconcileRestrictions(kernel_,
internal::ReconcileRestrictions);
TfLiteAsyncKernelSetSetAttributes(kernel_, internal::SetAttributes);
TfLiteAsyncKernelSetSetBufferAttributes(kernel_,
internal::SetBufferAttributes);
TfLiteAsyncKernelSetGetBufferAttributes(kernel_,
internal::GetBufferAttributes);
TfLiteAsyncKernelSetPrepare(kernel_, internal::Prepare);
TfLiteAsyncKernelSetEval(kernel_, internal::Eval);
TfLiteAsyncKernelSetWait(kernel_, internal::Wait);
TfLiteAsyncKernelSetFinish(kernel_, internal::Finish);
}
} // namespace delegates
} // namespace tflite
@@ -0,0 +1,214 @@
/* Copyright 2022 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_ASYNC_BACKEND_ASYNC_KERNEL_INTERFACE_H_
#define TENSORFLOW_LITE_ASYNC_BACKEND_ASYNC_KERNEL_INTERFACE_H_
#include <vector>
#include "tensorflow/lite/async/c/async_kernel.h"
#include "tensorflow/lite/async/c/types.h"
#include "tensorflow/lite/c/c_api_types.h"
#include "tensorflow/lite/c/common.h"
namespace tflite {
namespace delegates {
// A C++ wrapper around TfLiteAsyncKernel C API that delegate developers
// can use to add support for asynchronous execution.
// The implementation of `BackendAsyncKernelInterface` must be thread safe.
class BackendAsyncKernelInterface {
public:
BackendAsyncKernelInterface();
virtual ~BackendAsyncKernelInterface() { TfLiteAsyncKernelDelete(kernel_); }
// Returns the TfLiteAsyncKernel instance.
// kernel_ will be filled with the implementation of the class.
virtual TfLiteAsyncKernel* kernel() { return kernel_; }
// The following methods should be implemented to support buffer interop
// and asynchronous execution.
// Buffer operations
// ======================
// Registers the TfLiteBackendBuffer to `handle`.
// `TfLiteBackendBuffer` is a wrapper around a platform-specific buffer
// object (e.g. AHardwareBuffer).
// `buffer` and `attrs` lifespan is not guaranteed after the function call.
// kernels should read the stored attributes instead of caching the
// attribute map.
// `io_type` specifies whether this buffer is used as an input buffer
// or an output buffer. If a buffer is both used as input and output,
// specify it as output. Not null.
// `attrs` describes the attributes of the buffer. It's guaranteed to be
// of kTfLiteAttrMapTypeBuffer type and not null.
// `handle` is the buffer handle assigned by TfLite runtime to recognize
// this piece of buffer.
// In `attrs`, the application must provide the type of the buffer.
// If additional attributes (e.g. padding, size) are provided, the backend
// is responsible for validating those attributes to be compatible.
// The backend will not own the actual buffer wrapped in `buffer`, but the
// backend can choose to increase the ref count if underlying implementation
// supports that.
virtual TfLiteStatus RegisterBuffer(TfLiteOpaqueContext* context,
TfLiteIoType io_type,
const TfLiteBackendBuffer* buffer,
const TfLiteAttributeMap* attrs,
TfLiteBufferHandle handle) = 0;
// Registers a buffer slice from a previously registered memory.
// `buffer` is the handle of the buffer pool previously registered.
// `attrs` contains the information of the buffer slice.
// `handle` is the buffer handle assigned by TfLite runtime to recognize
// this piece of buffer.
// NOTE: The backend is responsible to validate the slicing is "valid":
// * The slicing is not nested from another slice. (i.e. the `buffer_pool` is
// a handle returned by `RegisterBuffer`.)
// * The attributes of the slice (e.g. size, offset) is of valid values
// from the buffer pool.
// If the `handle` is not recognized, returns error.
virtual TfLiteStatus RegisterBufferSlice(TfLiteOpaqueContext* context,
TfLiteBufferHandle buffer_pool,
const TfLiteAttributeMap* attrs,
TfLiteBufferHandle handle) = 0;
// Unregisters a buffer or a buffer slice.
// `handle` is a buffer handle previously assigned via register_* calls.
// If the `handle` is not recognized, returns error.
// Unregistering the buffer does not mean deallocating the buffer. However
// the backend need to reduce the ref-count if ref counting is performed
// during `Register*` calls.
virtual TfLiteStatus UnregisterBuffer(TfLiteOpaqueContext* context,
TfLiteBufferHandle handle) = 0;
// Reconciliations
// ===================
// Inspects the buffer object types supported by the backend.
// `io_type` specify whether the call returns supported input or output
// buffer.
virtual const std::vector<const char*>& SupportedBufferTypes(
TfLiteIoType io_type) const = 0;
// Inspects the sync object types supported by the backend.
// `io_type` specify whether the call returns supported input or output
// sync object.
virtual const std::vector<const char*>& SupportedSynchronizations(
TfLiteIoType io_type) const = 0;
// Reconciles buffer or sync attributes for tensor at tensor_index.
// Fills `merged` with reconciled attributes.
// If `conflict` is provided, conflicting attributes will be provided there.
// If the type of the `user_provided_attributes` is not recognizable, returns
// error.
// If any of the attribute in the `user_provided_attributes` is not
// recognizable skip this attribute.
// Returns true if the attribute map type is recognizable and there's no
// conflicting attribute.
virtual bool ReconcileRestrictions(
const TfLiteOpaqueContext* context, const TfLiteOpaqueNode* node,
int tensor_index, const TfLiteAttributeMap* user_provided_attributes,
TfLiteAttributeMap* merged, TfLiteAttributeMap* conflict) const = 0;
// Sets the input / output buffer / sync attributes.
// Backend kernel will check the input attributes covers all the requirements.
// A typical workflow is for callers call Reconcile*Restrictions method
// above to have a merged attribute list, check all restrictions are met
// and set input / output attribute here.
// Returns TfLiteOk if provided `attrs` covers all requirements.
virtual TfLiteStatus SetAttributes(TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node, int tensor_index,
const TfLiteAttributeMap* attrs) = 0;
// Set buffer's attributes. Backend will check if the buffer has been
// registered. And return TfLiteOk if the `attrs` for the `buffer` could be
// set in the corresponding async kernel.
virtual TfLiteStatus SetBufferAttributes(const TfLiteBackendBuffer* buffer,
const TfLiteAttributeMap* attrs) = 0;
// Get buffer's attributes. Backend will check if the buffer has been
// registered. And return TfLiteOk if provided `attrs` for the `buffer` could
// be found in the registration pool in corresponding async kernel. If `attrs`
// is a non-empty map, it will be overwritten by the attributes of the
// `buffer`.
virtual TfLiteStatus GetBufferAttributes(const TfLiteBackendBuffer* buffer,
TfLiteAttributeMap* attrs) = 0;
// Prepares the kernel using the information from Set[In|Out]putAttributes
// call above.
virtual TfLiteStatus Prepare(TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node) = 0;
// Execution methods
// =============================
// Schedules an execution with the information provided in task.
// The application is responsible for filling out buffer and sync mappings
// to tensors.
// Backend will set the sync ptr for related tensors if requested.
// i.e. SetOutputAttributes has sync implementation requested, and
// the TfLiteSynchronization is not null for the tensor in `task`.
//
// TfLite runtime guarantees that the task is in ready state (i.e. no
// un-ended execution for this task).
//
// Input synchronizations:
// If the synchronization of a input tensor is `kTfLiteSyncTypeNoSyncObj`
// type or it's nullptr, it means the data is ready during Eval call.
// If not, data will be available when the synchronization signals and the
// backend is responsible for closing the underlying synchronization.
// The backend is responsible for dedupping the input sync.
//
// Output synchronizations:
// If the synchronization type is `kTfLiteSyncTypeNoSyncObj` or is nullptr,
// the backend does not need to provide synchronization objects to the user.
// Otherwise, the backend need to provide the sync according to the sync type
// provided. The underlying sync object will be closed by the app (or
// downstream components).
// If there are multiple non-nullptr kTfLiteSynchronization provided for
// different output tensors, the backend is responsible for duplicating the
// synchronization.
// TODO(b/191883048): What if the sync fence is not dup-able?
//
// Returns kTfLiteOk if the execution is successfully scheduled.
virtual TfLiteStatus Eval(TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node,
TfLiteExecutionTask* task) = 0;
// Waits on the execution scheduled using the task to finish.
// TfLite runtime guarantees that the task has an un-ended execution.
//
// Callers should be able to call `Wait` on the same task from multiple
// threads, and those calls should return the same status (i.e. if the backend
// failed to successfully wait on the task, all `Wait` to the task should
// return the same error before a new invocation is scheduled). Returns
// kTfLiteOk if the task is finished (w/ or w/o blocking).
virtual TfLiteStatus Wait(TfLiteOpaqueContext* context,
TfLiteExecutionTask* task) = 0;
// Finishes the task and clean up allocated resources for the task.
// May block if there's pending executions.
// This function will be called once and only once for individual task.
// Returns kTfLiteOk if there's no error. The backend is responsible to
// clean up task resources regardless there's error or not.
virtual TfLiteStatus Finish(TfLiteOpaqueContext* context,
TfLiteExecutionTask* task) = 0;
protected:
TfLiteAsyncKernel* kernel_ = nullptr;
};
} // namespace delegates
} // namespace tflite
#endif // TENSORFLOW_LITE_ASYNC_BACKEND_ASYNC_KERNEL_INTERFACE_H_
@@ -0,0 +1,63 @@
/* Copyright 2022 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/async/backend_async_kernel_interface.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "tensorflow/lite/async/c/types.h"
#include "tensorflow/lite/c/c_api_types.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/core/async/async_kernel_internal.h"
#include "tensorflow/lite/core/async/testing/mock_async_kernel.h"
using ::testing::_;
namespace tflite::delegates {
namespace {
TEST(BackendAsyncKernelInterfaceTest, BasicTest) {
testing::StrictMock<async::testing::MockAsyncKernel> kernel;
EXPECT_CALL(kernel, RegisterBuffer(_, _, _, _, _));
EXPECT_CALL(kernel, RegisterBufferSlice(_, _, _, _));
EXPECT_CALL(kernel, UnregisterBuffer(_, _));
EXPECT_CALL(kernel, ReconcileRestrictions(_, _, _, _, _, _));
EXPECT_CALL(kernel, SetAttributes(_, _, _, _));
EXPECT_CALL(kernel, SetBufferAttributes(_, _));
EXPECT_CALL(kernel, GetBufferAttributes(_, _));
EXPECT_CALL(kernel, Prepare(_, _));
EXPECT_CALL(kernel, Eval(_, _, _));
EXPECT_CALL(kernel, Wait(_, _));
EXPECT_CALL(kernel, Finish(_, _));
auto* tflite_kernel = kernel.kernel();
tflite_kernel->register_buffer(tflite_kernel, nullptr, kTfLiteIoTypeInput,
nullptr, nullptr, 0);
tflite_kernel->register_buffer_slice(tflite_kernel, nullptr, 0, nullptr, 0);
tflite_kernel->unregister_buffer(tflite_kernel, nullptr, 0);
tflite_kernel->reconcile_restrictions(tflite_kernel, nullptr, nullptr, 0,
nullptr, nullptr, nullptr);
tflite_kernel->set_attributes(tflite_kernel, nullptr, nullptr, 0, nullptr);
tflite_kernel->set_buffer_attributes(tflite_kernel, nullptr, nullptr);
tflite_kernel->get_buffer_attributes(tflite_kernel, nullptr, nullptr);
tflite_kernel->prepare(tflite_kernel, nullptr, nullptr);
tflite_kernel->eval(tflite_kernel, nullptr, nullptr, nullptr);
tflite_kernel->wait(tflite_kernel, nullptr, nullptr);
tflite_kernel->finish(tflite_kernel, nullptr, nullptr);
}
} // namespace
} // namespace tflite::delegates
+45
View File
@@ -0,0 +1,45 @@
# This package contains shim library targets for the Async C package,
# that forward to the TF Lite C and C++ API targets.
load("//tensorflow/lite:build_def.bzl", "tflite_copts", "tflite_copts_warnings")
load("//tensorflow/lite/core/shims:cc_library_with_tflite.bzl", "cc_library_with_tflite")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//visibility:private",
],
licenses = ["notice"],
)
cc_library_with_tflite(
name = "task",
hdrs = ["task.h"],
copts = tflite_copts() + tflite_copts_warnings(),
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/async/c:task"],
)
cc_library_with_tflite(
name = "types",
hdrs = ["types.h"],
copts = tflite_copts() + tflite_copts_warnings(),
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/async/c:types"],
)
cc_library_with_tflite(
name = "async_signature_runner",
hdrs = ["async_signature_runner.h"],
copts = tflite_copts() + tflite_copts_warnings(),
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/async/c:async_signature_runner"],
)
cc_library_with_tflite(
name = "async_kernel",
hdrs = ["async_kernel.h"],
copts = tflite_copts() + tflite_copts_warnings(),
visibility = ["//visibility:public"],
deps = ["//tensorflow/lite/core/async/c:async_kernel"],
)
+20
View File
@@ -0,0 +1,20 @@
/* Copyright 2023 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_ASYNC_C_ASYNC_KERNEL_H_
#define TENSORFLOW_LITE_ASYNC_C_ASYNC_KERNEL_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/async/c/async_kernel.h.
#include "tensorflow/lite/core/async/c/async_kernel.h" // IWYU pragma: export
#endif // TENSORFLOW_LITE_ASYNC_C_ASYNC_KERNEL_H_
@@ -0,0 +1,20 @@
/* Copyright 2023 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_ASYNC_C_ASYNC_SIGNATURE_RUNNER_H_
#define TENSORFLOW_LITE_ASYNC_C_ASYNC_SIGNATURE_RUNNER_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/async/c/async_signature_runner.h.
#include "tensorflow/lite/core/async/c/async_signature_runner.h" // IWYU pragma: export
#endif // TENSORFLOW_LITE_ASYNC_C_ASYNC_SIGNATURE_RUNNER_H_
+21
View File
@@ -0,0 +1,21 @@
/* Copyright 2023 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_ASYNC_C_TASK_H_
#define TENSORFLOW_LITE_ASYNC_C_TASK_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/async/c/task.h.
#include "tensorflow/lite/core/async/c/task.h" // IWYU pragma: export
#endif // TENSORFLOW_LITE_ASYNC_C_TASK_H_
+20
View File
@@ -0,0 +1,20 @@
/* Copyright 2023 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_ASYNC_C_TYPES_H_
#define TENSORFLOW_LITE_ASYNC_C_TYPES_H_
/// For documentation, see
/// tensorflow/lite/core/async/c/types.h.
#include "tensorflow/lite/core/async/c/types.h" // IWYU pragma: export
#endif // TENSORFLOW_LITE_ASYNC_C_TYPES_H_
+36
View File
@@ -0,0 +1,36 @@
# This package contains shim library targets for the Async interop package,
# that forward to the TF Lite C and C++ API targets.
load("//tensorflow/lite:build_def.bzl", "tflite_copts", "tflite_copts_warnings")
cc_library(
name = "attribute_map",
hdrs = ["attribute_map.h"],
copts = tflite_copts() + tflite_copts_warnings(),
visibility = [
"//visibility:public",
],
deps = ["//tensorflow/lite/core/async/interop/c:attribute_map"],
)
cc_library(
name = "types",
hdrs = ["types.h"],
copts = tflite_copts() + tflite_copts_warnings(),
visibility = [
"//visibility:public",
],
deps = ["//tensorflow/lite/core/async/interop/c:types"],
)
cc_library(
name = "constants",
hdrs = ["constants.h"],
copts = tflite_copts() + tflite_copts_warnings(),
visibility = [
"//visibility:public",
],
deps = [
"//tensorflow/lite/core/async/interop/c:constants",
],
)
@@ -0,0 +1,20 @@
/* Copyright 2023 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_ASYNC_INTEROP_C_ATTRIBUTE_MAP_H_
#define TENSORFLOW_LITE_ASYNC_INTEROP_C_ATTRIBUTE_MAP_H_
/// For documentation, see
/// tensorflow/lite/core/async/interop/c/attribute_map.h.
#include "tensorflow/lite/core/async/interop/c/attribute_map.h" // IWYU pragma: export
#endif // TENSORFLOW_LITE_ASYNC_INTEROP_C_ATTRIBUTE_MAP_H_
@@ -0,0 +1,20 @@
/* Copyright 2023 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_ASYNC_INTEROP_C_CONSTANTS_H_
#define TENSORFLOW_LITE_ASYNC_INTEROP_C_CONSTANTS_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/async/interop/c/constants.h
#include "tensorflow/lite/core/async/interop/c/constants.h" // IWYU pragma: export
#endif // TENSORFLOW_LITE_ASYNC_INTEROP_C_CONSTANTS_H_
+20
View File
@@ -0,0 +1,20 @@
/* Copyright 2023 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_ASYNC_INTEROP_C_TYPES_H_
#define TENSORFLOW_LITE_ASYNC_INTEROP_C_TYPES_H_
/// For documentation, see
/// tensorflow/lite/core/async/interop/c/types.h.
#include "tensorflow/lite/core/async/interop/c/types.h" // IWYU pragma: export
#endif // TENSORFLOW_LITE_ASYNC_INTEROP_C_TYPES_H_
+24
View File
@@ -0,0 +1,24 @@
# Test utilities for TFLite async execution.
load("//tensorflow/lite/core/shims:cc_library_with_tflite.bzl", "cc_library_with_tflite")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//visibility:private",
],
licenses = ["notice"],
)
cc_library_with_tflite(
name = "mock_async_kernel",
testonly = 1,
hdrs = ["mock_async_kernel.h"],
tflite_deps = [
"//tensorflow/lite/async:backend_async_kernel_interface",
"//tensorflow/lite/async/c:types",
],
visibility = ["//visibility:public"],
deps = [
"@com_google_googletest//:gtest",
],
)
@@ -0,0 +1,84 @@
/* Copyright 2022 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_ASYNC_TESTING_MOCK_ASYNC_KERNEL_H_
#define TENSORFLOW_LITE_ASYNC_TESTING_MOCK_ASYNC_KERNEL_H_
#include <vector>
#include <gmock/gmock.h>
#include "tensorflow/lite/async/backend_async_kernel_interface.h"
#include "tensorflow/lite/async/c/types.h"
namespace tflite {
namespace async {
namespace testing {
// A fully mocked out async kernel.
// Mocked TfLiteAsyncKernel can be retreived by `MockAsyncKernel::kernel()`.
class MockAsyncKernel : public delegates::BackendAsyncKernelInterface {
public:
MOCK_METHOD(TfLiteStatus, RegisterBuffer,
(TfLiteOpaqueContext*, TfLiteIoType, const TfLiteBackendBuffer*,
const TfLiteAttributeMap*, TfLiteBufferHandle),
(override));
MOCK_METHOD(TfLiteStatus, RegisterBufferSlice,
(TfLiteOpaqueContext*, TfLiteBufferHandle,
const TfLiteAttributeMap*, TfLiteBufferHandle),
(override));
MOCK_METHOD(TfLiteStatus, UnregisterBuffer,
(TfLiteOpaqueContext*, TfLiteBufferHandle), (override));
MOCK_METHOD(bool, ReconcileRestrictions,
(const TfLiteOpaqueContext*, const TfLiteOpaqueNode*, int,
const TfLiteAttributeMap*, TfLiteAttributeMap*,
TfLiteAttributeMap*),
(const, override));
MOCK_METHOD(TfLiteStatus, SetAttributes,
(TfLiteOpaqueContext*, TfLiteOpaqueNode*, int,
const TfLiteAttributeMap*),
(override));
MOCK_METHOD(TfLiteStatus, SetBufferAttributes,
(const TfLiteBackendBuffer*, const TfLiteAttributeMap*),
(override));
MOCK_METHOD(TfLiteStatus, GetBufferAttributes,
(const TfLiteBackendBuffer*, TfLiteAttributeMap*), (override));
MOCK_METHOD(TfLiteStatus, Prepare, (TfLiteOpaqueContext*, TfLiteOpaqueNode*),
(override));
MOCK_METHOD(TfLiteStatus, Eval,
(TfLiteOpaqueContext*, TfLiteOpaqueNode*, TfLiteExecutionTask*),
(override));
MOCK_METHOD(TfLiteStatus, Wait, (TfLiteOpaqueContext*, TfLiteExecutionTask*),
(override));
MOCK_METHOD(TfLiteStatus, Finish,
(TfLiteOpaqueContext*, TfLiteExecutionTask*), (override));
const std::vector<const char*>& SupportedBufferTypes(
TfLiteIoType io_type) const override {
return buffer_types_;
}
const std::vector<const char*>& SupportedSynchronizations(
TfLiteIoType io_type) const override {
return sync_types_;
}
private:
const std::vector<const char*> buffer_types_{"buffer_type"};
const std::vector<const char*> sync_types_{"sync_type"};
};
} // namespace testing
} // namespace async
} // namespace tflite
#endif // TENSORFLOW_LITE_ASYNC_TESTING_MOCK_ASYNC_KERNEL_H_
+961
View File
@@ -0,0 +1,961 @@
"""Build macros for TF Lite."""
load("@xla//third_party/rules_python/python:py_test.bzl", "py_test")
load("//tensorflow:tensorflow.bzl", "if_oss", "tf_binary_additional_srcs", "tf_cc_shared_object")
load("//tensorflow/lite:special_rules.bzl", "tflite_copts_extra")
load("//tensorflow/lite/java:aar_with_jni.bzl", "aar_with_jni")
load("@build_bazel_rules_android//android:rules.bzl", "android_library")
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
# buildifier: disable=out-of-order-load
def register_extension_info(**kwargs):
pass
def clean_dep(target):
"""Returns string to 'target' in @litert repository.
Use this function when referring to targets in the @litert
repository from macros that may be called from external repositories.
"""
# A repo-relative label is resolved relative to the file in which the
# Label() call appears, i.e. @tsl.
return str(Label(target))
def tflite_copts():
"""Defines common compile time flags for TFLite libraries."""
copts = [
"-DFARMHASH_NO_CXX_STRING",
"-DEIGEN_ALLOW_UNALIGNED_SCALARS", # TODO(b/296071640): Remove when underlying bugs are fixed.
] + select({
clean_dep("//tensorflow:android_arm"): [
"-mfpu=neon",
],
# copybara:uncomment_begin(google-only)
# clean_dep("//tensorflow:chromiumos_x86_64"): [],
# copybara:uncomment_end
clean_dep("//tensorflow:ios_x86_64"): [
"-msse4.1",
],
clean_dep("//tensorflow:linux_x86_64"): [
"-msse4.2",
],
clean_dep("//tensorflow:linux_x86_64_no_sse"): [],
clean_dep("//tensorflow:windows"): [
# copybara:uncomment_begin(no MSVC flags in google)
# "-DTFL_COMPILE_LIBRARY",
# "-Wno-sign-compare",
# copybara:uncomment_end_and_comment_begin
"/DTFL_COMPILE_LIBRARY",
"/wd4018", # -Wno-sign-compare
# copybara:comment_end
],
"//conditions:default": [
"-Wno-sign-compare",
],
}) + select({
clean_dep("//tensorflow:optimized"): ["-O3"],
"//conditions:default": [],
}) + select({
clean_dep("//tensorflow:android"): [
"-ffunction-sections", # Helps trim binary size.
"-fdata-sections", # Helps trim binary size.
],
"//conditions:default": [],
}) + select({
clean_dep("//tensorflow:windows"): [],
"//conditions:default": [
"-fno-exceptions", # Exceptions are unused in TFLite.
],
}) + select({
clean_dep("//tensorflow/lite:tflite_with_xnnpack_explicit_false"): ["-DTFLITE_WITHOUT_XNNPACK"],
"//conditions:default": [],
}) + select({
clean_dep("//tensorflow/lite:tensorflow_profiler_config"): ["-DTF_LITE_TENSORFLOW_PROFILER"],
"//conditions:default": [],
}) + select({
clean_dep("//tensorflow/lite/delegates:tflite_debug_delegate"): ["-DTFLITE_DEBUG_DELEGATE"],
"//conditions:default": [],
}) + select({
clean_dep("//tensorflow/lite:tflite_mmap_disabled"): ["-DTFLITE_MMAP_DISABLED"],
"//conditions:default": [],
})
return copts + tflite_copts_extra()
def tflite_copts_warnings():
"""Defines common warning flags used primarily by internal TFLite libraries."""
# TODO(b/155906820): Include with `tflite_copts()` after validating clients.
return select({
clean_dep("//tensorflow:windows"): [
# We run into trouble on Windows toolchains with warning flags,
# as mentioned in the comments below on each flag.
# We could be more aggressive in enabling supported warnings on each
# Windows toolchain, but we compromise with keeping BUILD files simple
# by limiting the number of config_setting's.
],
"//conditions:default": [
"-Wall",
],
})
EXPORTED_SYMBOLS = clean_dep("//tensorflow/lite/java/src/main/native:exported_symbols.lds")
LINKER_SCRIPT = clean_dep("//tensorflow/lite/java/src/main/native:version_script.lds")
def tflite_linkopts_unstripped():
"""Defines linker flags to reduce size of TFLite binary.
These are useful when trying to investigate the relative size of the
symbols in TFLite.
Returns:
a select object with proper linkopts
"""
# In case you wonder why there's no --icf is because the gains were
# negligible, and created potential compatibility problems.
return select({
clean_dep("//tensorflow:android"): [
"-latomic", # Required for some uses of ISO C++11 <atomic> in x86.
"-Wl,--no-export-dynamic", # Only inc syms referenced by dynamic obj.
"-Wl,--gc-sections", # Eliminate unused code and data.
"-Wl,--as-needed", # Don't link unused libs.
],
"//conditions:default": [],
})
def tflite_jni_linkopts_unstripped():
"""Defines linker flags to reduce size of TFLite binary with JNI.
These are useful when trying to investigate the relative size of the
symbols in TFLite.
Returns:
a select object with proper linkopts
"""
# In case you wonder why there's no --icf is because the gains were
# negligible, and created potential compatibility problems.
return select({
clean_dep("//tensorflow:android"): [
"-latomic", # Required for some uses of ISO C++11 <atomic> in x86.
"-Wl,--gc-sections", # Eliminate unused code and data.
"-Wl,--as-needed", # Don't link unused libs.
],
"//conditions:default": [],
})
def tflite_symbol_opts():
"""Defines linker flags whether to include symbols or not."""
return select({
clean_dep("//tensorflow:debug"): [],
clean_dep("//tensorflow/lite:tflite_keep_symbols"): [],
"//conditions:default": [
# Omit symbol table, for all non debug builds
"-Wl,-s",
],
})
def tflite_linkopts_no_undefined():
"""Defines linker flags to enable errors for undefined symbols.
This enables link-time errors for undefined symbols even when linking
shared libraries, where the default behaviour on many systems is to only
report errors for undefined symbols at runtime.
"""
return if_oss(
select({
# macOS/iOS linker uses "--undefined error" instead of "--no-undefined".
"//tensorflow:ios": [
"-Wl,-undefined,error",
],
"//tensorflow:macos": [
"-Wl,-undefined,error",
],
"//conditions:default": ["-Wl,--no-undefined"],
}),
select({
# Can't enable errors for undefined symbols for asan/msan/tsan mode,
# since undefined symbols in shared libraries (references to symbols
# that will be defined in the main executable) are normal and
# expected in those cases.
"//tools/cpp:sanitizer_build": [],
"//tensorflow:ios": [
"-Wl,-undefined,error",
],
"//tensorflow:macos": [
"-Wl,-undefined,error",
],
"//conditions:default": ["-Wl,--no-undefined"],
}),
)
def tflite_pagesize_linkopts():
"""Defines linker flags for setting the page size."""
return select({
clean_dep("//tensorflow:android"): [
"-Wl,-z,max-page-size=16384",
],
"//conditions:default": [],
})
def tflite_linkopts():
"""Defines linker flags for linking TFLite binary."""
return tflite_linkopts_unstripped() + tflite_symbol_opts() + tflite_pagesize_linkopts()
def tflite_jni_linkopts():
"""Defines linker flags for linking TFLite binary with JNI."""
return tflite_jni_linkopts_unstripped() + tflite_symbol_opts() + tflite_pagesize_linkopts()
def tflite_jni_binary(
name,
copts = tflite_copts(),
linkopts = tflite_jni_linkopts(),
linkscript = LINKER_SCRIPT,
exported_symbols = EXPORTED_SYMBOLS,
stamp = -1,
linkshared = 1,
linkstatic = 1,
testonly = 0,
deps = [],
tags = [],
srcs = [],
visibility = None, # 'None' means use the default visibility.
local_defines = [],
exec_properties = {}):
"""Builds a jni binary for TFLite."""
linkopts = linkopts + select({
clean_dep("//tensorflow:macos"): [
"-Wl,-exported_symbols_list,$(location {})".format(exported_symbols),
"-Wl,-install_name,@rpath/" + name,
],
clean_dep("//tensorflow:windows"): [],
"//conditions:default": [
"-Wl,--version-script,$(location {})".format(linkscript),
"-Wl,--undefined-version",
"-Wl,-soname," + name,
],
})
cc_binary(
name = name,
copts = copts,
linkshared = linkshared,
linkstatic = linkstatic,
stamp = stamp,
deps = deps + [linkscript, exported_symbols],
srcs = srcs,
tags = tags,
linkopts = linkopts,
testonly = testonly,
visibility = visibility,
local_defines = local_defines,
exec_properties = exec_properties,
)
def tflite_cc_shared_object(
name,
copts = tflite_copts(),
linkopts = [],
linkstatic = 1,
per_os_targets = False,
**kwargs):
"""Builds a shared object for TFLite."""
tf_cc_shared_object(
name = name,
copts = copts,
linkstatic = linkstatic,
linkopts = linkopts + tflite_jni_linkopts(),
framework_so = [],
per_os_targets = per_os_targets,
**kwargs
)
def tf_to_tflite(name, src, options, out):
"""Convert a frozen tensorflow graphdef to TF Lite's flatbuffer.
Args:
name: Name of rule.
src: name of the input graphdef file.
options: options passed to TFLite Converter.
out: name of the output flatbuffer file.
"""
toco_cmdline = " ".join([
"$(location //tensorflow/lite/python:tflite_convert)",
"--enable_v1_converter",
("--graph_def_file=$(location %s)" % src),
("--output_file=$(location %s)" % out),
] + options)
native.genrule(
name = name,
srcs = [src],
outs = [out],
cmd = toco_cmdline,
tools = ["//tensorflow/lite/python:tflite_convert"] + tf_binary_additional_srcs(),
)
def DEPRECATED_tf_to_tflite(name, src, options, out):
"""DEPRECATED Convert a frozen tensorflow graphdef to TF Lite's flatbuffer, using toco.
Please use tf_to_tflite instead.
TODO(b/138396996): Migrate away from this deprecated rule.
Args:
name: Name of rule.
src: name of the input graphdef file.
options: options passed to TOCO.
out: name of the output flatbuffer file.
"""
toco_cmdline = " ".join([
"$(location //tensorflow/lite/toco:toco)",
"--input_format=TENSORFLOW_GRAPHDEF",
"--output_format=TFLITE",
("--input_file=$(location %s)" % src),
("--output_file=$(location %s)" % out),
] + options)
native.genrule(
name = name,
srcs = [src],
outs = [out],
cmd = toco_cmdline,
tools = ["//tensorflow/lite/toco:toco"] + tf_binary_additional_srcs(),
)
def tflite_to_json(name, src, out):
"""Convert a TF Lite flatbuffer to JSON.
Args:
name: Name of rule.
src: name of the input flatbuffer file.
out: name of the output JSON file.
"""
flatc = "@flatbuffers//:flatc"
schema = "//tensorflow/lite/schema:schema.fbs"
native.genrule(
name = name,
srcs = [schema, src],
outs = [out],
cmd = ("TMP=`mktemp`; cp $(location %s) $${TMP}.bin &&" +
"$(location %s) --raw-binary --strict-json -t" +
" -o /tmp $(location %s) -- $${TMP}.bin &&" +
"cp $${TMP}.json $(location %s)") %
(src, flatc, schema, out),
tools = [flatc],
)
def json_to_tflite(name, src, out):
"""Convert a JSON file to TF Lite's flatbuffer.
Args:
name: Name of rule.
src: name of the input JSON file.
out: name of the output flatbuffer file.
"""
flatc = "@flatbuffers//:flatc"
schema = "//tensorflow/lite/schema:schema_fbs"
native.genrule(
name = name,
srcs = [schema, src],
outs = [out],
cmd = ("TMP=`mktemp`; cp $(location %s) $${TMP}.json &&" +
"$(location %s) --raw-binary --unknown-json --allow-non-utf8 -b" +
" -o /tmp $(location %s) $${TMP}.json &&" +
"cp $${TMP}.bin $(location %s)") %
(src, flatc, schema, out),
tools = [flatc],
)
def _gen_selected_ops_impl(ctx):
args = ctx.actions.args()
args.add(ctx.attr.namespace, format = "--namespace=%s")
args.add(ctx.outputs.output, format = "--output_registration=%s")
tflite_path = "//tensorflow/lite"
args.add("--tflite_path=%s" % tflite_path[2:])
args.add_joined(
ctx.files.models,
join_with = ",",
format_joined = "--input_models=%s",
)
ctx.actions.run(
outputs = [ctx.outputs.output],
inputs = ctx.files.models,
arguments = [args],
executable = ctx.executable._generate_op_registrations,
mnemonic = "OpRegistration",
progress_message = "gen_selected_ops",
use_default_shell_env = True,
)
gen_selected_ops_rule = rule(
implementation = _gen_selected_ops_impl,
attrs = {
"models": attr.label_list(default = [], allow_files = True),
"namespace": attr.string(default = ""),
"output": attr.output(),
"_generate_op_registrations": attr.label(
executable = True,
default = Label(clean_dep(
"//tensorflow/lite/tools:generate_op_registrations",
)),
cfg = "exec",
),
},
)
def gen_selected_ops(name, model, namespace = "", **kwargs):
"""Generate the source file that includes only used ops.
Args:
name: Prefix of the generated source file.
model: TFLite models to interpret, expect a list in case of multiple models.
namespace: Namespace in which to put RegisterSelectedOps.
**kwargs: Additional kwargs to pass to genrule.
"""
# If there's only one model provided as a string.
if type(model) == type(""):
model = [model]
gen_selected_ops_rule(
name = name,
models = model,
namespace = namespace,
output = name + "_registration.cc",
**kwargs
)
def flex_dep(target_op_sets):
if "SELECT_TF_OPS" in target_op_sets:
return ["//tensorflow/lite/delegates/flex:delegate"]
else:
return []
def gen_model_coverage_test(
src,
name,
data,
failure_type,
tags,
size = "medium",
extra_deps = None):
"""Generates Python test targets for testing TFLite models.
Args:
src: Main source file.
name: Name of the model to test (must be also listed in the 'data'
dependencies)
data: List of BUILD targets linking the data.
failure_type: List of failure types (none, toco, crash, inference, evaluation)
expected for the corresponding combinations of op sets
("TFLITE_BUILTINS", "TFLITE_BUILTINS,SELECT_TF_OPS", "SELECT_TF_OPS").
tags: List of strings of additional tags.
size: String determining test size for filtering and resource allocation.
extra_deps: List of dependencies needed only by the specific src as opposed to the generic
dependencies listed below.
"""
i = 0
for target_op_sets in ["TFLITE_BUILTINS", "TFLITE_BUILTINS,SELECT_TF_OPS", "SELECT_TF_OPS"]:
args = []
if failure_type[i] != "none":
args.append("--failure_type=%s" % failure_type[i])
i = i + 1
# Construct list of dependencies
full_deps = [
"//third_party/py/tensorflow",
"//tensorflow/lite/testing/model_coverage:model_coverage_lib",
"//tensorflow/lite/python:lite",
"//tensorflow/python/framework:errors",
"//tensorflow/python/platform:client_testlib",
] + flex_dep(target_op_sets)
if extra_deps:
full_deps += extra_deps
# Avoid coverage timeouts for large/enormous tests.
coverage_tags = ["nozapfhahn"] if size in ["large", "enormous"] else []
py_test(
name = "model_coverage_test_%s_%s" % (name, target_op_sets.lower().replace(",", "_")),
srcs = [src],
main = src,
size = size,
args = [
"--model_name=%s" % name,
"--target_ops=%s" % target_op_sets,
] + args,
data = data,
srcs_version = "PY3",
python_version = "PY3",
tags = [
"no_gpu", # Executing with TF GPU configurations is redundant.
"no_oss",
"no_windows",
# Disable sanitizer runs as models can be huge and can timeout.
"noasan",
"nomsan",
"notsan",
] + tags + coverage_tags,
deps = full_deps,
)
def tflite_custom_cc_library(
name,
models = [],
srcs = [],
deps = [],
visibility = ["//visibility:private"],
experimental = False,
**kwargs):
"""Generates a tflite cc library, stripping off unused operators.
This library includes the TfLite runtime as well as all operators needed for the given models.
Op resolver can be retrieved using tflite::CreateOpResolver method.
Args:
name: Str, name of the target.
models: List of models. This TFLite build will only include
operators used in these models. If the list is empty, all builtin
operators are included.
srcs: List of files implementing custom operators if any.
deps: Additional dependencies to build all the custom operators.
visibility: Visibility setting for the generated target. Default to private.
experimental: Whether to include experimental APIs or not.
**kwargs: Additional arguments for cc_library.
"""
real_srcs = []
real_srcs.extend(srcs)
real_deps = []
real_deps.extend(deps)
if models:
gen_selected_ops(
name = "%s_registration" % name,
model = models,
testonly = kwargs.get("testonly", False),
)
real_srcs.append(":%s_registration" % name)
real_srcs.append("//tensorflow/lite:create_op_resolver_with_selected_ops.cc")
else:
# Support all operators if `models` not specified.
real_deps.append("//tensorflow/lite:create_op_resolver_with_builtin_ops")
if experimental:
framework = "//tensorflow/lite:framework_experimental"
else:
framework = "//tensorflow/lite:framework_stable"
cc_library(
name = name,
srcs = real_srcs,
hdrs = [
"//tensorflow/lite:create_op_resolver.h",
],
copts = tflite_copts(),
linkopts = select({
"//tensorflow:windows": [],
"//conditions:default": ["-lm", "-ldl"],
}),
deps = depset([
framework,
"//tensorflow/lite/kernels:builtin_ops",
"//tensorflow/lite/core:private_create_op_resolver_header",
] + real_deps),
visibility = visibility,
**kwargs
)
def tflite_custom_android_library(
name,
models = [],
srcs = [],
deps = [],
custom_package = "org.tensorflow.lite",
visibility = ["//visibility:private"],
include_xnnpack_delegate = True,
include_nnapi_delegate = True,
experimental = False):
"""Generates a tflite Android library, stripping off unused operators.
Note that due to a limitation in the JNI Java wrapper, the compiled TfLite shared binary
has to be named as tensorflowlite_jni.so so please make sure that there is no naming conflict.
i.e. you can't call this rule multiple times in the same build file.
Args:
name: Name of the target.
models: List of models to be supported. This TFLite build will only include
operators used in these models. If the list is empty, all builtin
operators are included.
srcs: List of files implementing custom operators if any.
deps: Additional dependencies to build all the custom operators.
custom_package: Name of the Java package. It is required by android_library in case
the Java source file can't be inferred from the directory where this rule is used.
visibility: Visibility setting for the generated target. Default to private.
include_xnnpack_delegate: Whether to include the XNNPACK delegate or not.
include_nnapi_delegate: Whether to include the NNAPI delegate or not.
experimental: Whether to include experimental APIs or not.
"""
tflite_custom_cc_library(name = "%s_cc" % name, models = models, srcs = srcs, deps = deps, visibility = visibility)
delegate_deps = []
if include_nnapi_delegate:
delegate_deps.append("//tensorflow/lite/delegates/nnapi/java/src/main/native")
if include_xnnpack_delegate:
delegate_deps.append("//tensorflow/lite/delegates/xnnpack:xnnpack_delegate")
if experimental:
native_framework_only = "//tensorflow/lite/java/src/main/native:native_experimental_framework_only"
else:
native_framework_only = "//tensorflow/lite/java/src/main/native:native_stable_framework_only"
# JNI wrapper expects a binary file called `libtensorflowlite_jni.so` in java path.
tflite_jni_binary(
name = "libtensorflowlite_jni.so",
linkscript = "//tensorflow/lite/java:tflite_version_script.lds",
# Do not sort: "native_framework_only" must come before custom tflite library.
deps = [
native_framework_only,
":%s_cc" % name,
] + delegate_deps,
)
cc_library(
name = "%s_jni" % name,
srcs = ["libtensorflowlite_jni.so"],
visibility = visibility,
)
if experimental:
java_srcs = "//tensorflow/lite/java:java_srcs"
else:
java_srcs = "//tensorflow/lite/java:java_stable_srcs"
android_library(
name = name,
manifest = "//tensorflow/lite/java:AndroidManifest.xml",
srcs = [java_srcs],
deps = [
":%s_jni" % name,
"@org_checkerframework_qual",
],
custom_package = custom_package,
visibility = visibility,
)
aar_with_jni(
name = "%s_aar" % name,
android_library = name,
)
def tflite_custom_c_library(
name,
models = [],
experimental = False,
**kwargs):
"""Generates a tflite C library, stripping off unused operators.
This library includes the C API and the op kernels used in the given models.
Args:
name: Str, name of the target.
models: List of models. This TFLite build will only include
operators used in these models. If the list is empty, all builtin
operators are included.
experimental: Whether to include experimental APIs or not.
**kwargs: custom c_api cc_library kwargs.
"""
op_resolver_deps = "//tensorflow/lite:create_op_resolver_with_builtin_ops"
if models:
gen_selected_ops(
name = "%s_registration" % name,
model = models,
testonly = kwargs.get("testonly", False),
)
if experimental:
framework = "//tensorflow/lite:framework_experimental"
else:
framework = "//tensorflow/lite:framework_stable"
cc_library(
name = "%s_create_op_resolver" % name,
srcs = [
":%s_registration" % name,
],
hdrs = ["//tensorflow/lite:create_op_resolver.h"],
copts = tflite_copts(),
deps = [
"//tensorflow/lite/core:private_create_op_resolver_header",
"//tensorflow/lite:create_op_resolver_with_selected_ops",
"//tensorflow/lite:op_resolver",
framework,
"//tensorflow/lite/kernels:builtin_ops",
],
# Using alwayslink here is needed, I believe, to avoid warnings about
# backwards references when linking create_op_resolver_with_selected_ops,
# which has a reference to the RegisterSelectedOps function defined by
# '":%s_registration" % name' (the code generated by the call to
# gen_selected_ops above).
alwayslink = True,
**kwargs
)
op_resolver_deps = "%s_create_op_resolver" % name
if experimental:
hdrs = [
"//tensorflow/lite/c:c_api.h",
"//tensorflow/lite/c:c_api_experimental.h",
"//tensorflow/lite/c:c_api_opaque.h",
]
deps = [
"//tensorflow/lite/c:c_api_experimental_without_op_resolver_without_alwayslink",
"//tensorflow/lite/core/c:private_c_api_experimental_without_op_resolver_without_alwayslink",
"//tensorflow/lite/c:c_api_opaque_without_op_resolver_without_alwayslink",
"//tensorflow/lite/core/c:private_c_api_opaque_without_op_resolver_without_alwayslink",
]
else:
hdrs = [
"//tensorflow/lite/c:c_api.h",
"//tensorflow/lite/c:c_api_opaque.h",
]
deps = [
"//tensorflow/lite/c:c_api_opaque_without_op_resolver_without_alwayslink",
"//tensorflow/lite/core/c:private_c_api_opaque_without_op_resolver_without_alwayslink",
]
cc_library(
name = name,
hdrs = hdrs,
copts = tflite_copts(),
deps = [
op_resolver_deps,
"//tensorflow/lite:builtin_ops",
"//tensorflow/lite/c:c_api_without_op_resolver_without_alwayslink",
# TODO(bekzhan): Remove this dependency after we move c_api_opaque.h to tflite/core/.
"//tensorflow/lite/core/c:private_c_api_types",
"//tensorflow/lite/core/c:private_c_api_without_op_resolver_without_alwayslink",
"//tensorflow/lite/core/c:private_common",
"//tensorflow/lite/delegates/nnapi:nnapi_delegate",
] + deps,
**kwargs
)
def _is_bzlmod_enabled():
"""Check if with bzlmod enabled"""
return str(Label("@//:BUILD.bazel")).startswith("@@")
# TODO(b/254126721): Move tflite_combine_cc_tests macro to lite/testing/build_def.bzl.
def tflite_combine_cc_tests(
name,
deps_conditions,
build_test_tags = [],
generate_cc_library = False,
**kwargs):
"""Combine certain cc_tests into a single cc_test and a build_test.
This rule should normally be placed at the bottom of a package.
Any cc_test rules that appear after the call to this rule will not
be included in the combined cc_test rule, even if they meet the
other conditions.
Args:
name: the name of the combined cc_test.
deps_conditions: the list of deps that those cc_tests need to have in
order to be combined.
extra_cc_test_tags: the list of extra tags appended to the created
combined cc_test.
extra_build_test_tags: the list of extra tags appended to the created
corresponding build_test for the combined cc_test.
generate_cc_library: if set to True, additionally generates a combined
cc_library containing all kernel tests. The generated cc_library
will exclude all dependencies in `deps_conditions`, so that users
can plugin their own test driver and entry point.
**kwargs: kwargs to pass to the cc_test rule of the test suite.
"""
cc_test_args = dict(kwargs)
size = cc_test_args.pop("size", "large")
extra_deps = cc_test_args.pop("deps", [])
combined_test_srcs = {}
combined_test_deps = {}
for r in native.existing_rules().values():
# We only include cc_test.
if not r["kind"] == "cc_test":
continue
# Tests with data, args or special build option are not counted.
if r["data"] or r["args"] or r["copts"] or r["defines"] or \
r["includes"] or r["linkopts"] or r["additional_linker_inputs"]:
continue
# We only consider a single-src-file unit test.
if len(r["srcs"]) > 1:
continue
dep_attr = r["deps"]
if type(dep_attr) != type(()) and type(dep_attr) != type([]):
# Attributes based on select() is not supported for simplicity.
continue
# The test has to depend on :test_main
if not any([v in deps_conditions for v in dep_attr]):
continue
combined_test_srcs.update({s: True for s in r["srcs"]})
combined_test_deps.update({d: True for d in r["deps"]})
if combined_test_srcs:
# Using native.existing_rule to combine cc_test's deps duplicates link_extra_lib. Remove it.
if _is_bzlmod_enabled():
combined_test_deps.pop(str(Label("@rules_cc" + "//:link_extra_lib")), None)
else:
combined_test_deps.pop("@@rules_cc" + "//:link_extra_lib", None)
# Merge explicitly provided extra dependencies
for d in extra_deps:
combined_test_deps[d] = True
cc_test(
name = name,
size = size,
srcs = list(combined_test_srcs),
deps = list(combined_test_deps),
**cc_test_args
)
build_test(
name = "%s_build_test" % name,
targets = [":%s" % name],
tags = build_test_tags,
)
if generate_cc_library:
cc_library(
name = "%s_lib" % name,
srcs = list(combined_test_srcs),
deps = [d for d in combined_test_deps if d not in deps_conditions],
testonly = 1,
alwayslink = 1,
**kwargs
)
def tflite_self_contained_libs_test_suite(name):
"""Indicate that cc_library rules in this package *should* be self-contained.
This adds build tests for each cc_library rule that verify that the
library can be successfully linked with no undefined symbols. It also
adds a test_suite rule that contains all the generated build tests.
Place this rule at the bottom of a package. Any cc_library rules that
appear after the call to this rule will not be checked for undefined
symbols. Rules that are tagged with 'allow_undefined_symbols' in
their 'tags' attribute will also not be checked for undefined symbols.
Args:
name: the name to use for the test_suite rule that contains
the build tests generated by this macro.
"""
build_tests = []
for rule in native.existing_rules().values():
rule_name = rule["name"]
rule_kind = rule["kind"]
rule_tags = rule["tags"]
if rule_kind == "cc_library" and "allow_undefined_symbols" not in rule_tags:
tflite_cc_shared_object(
name = "%s_test_shared_lib" % rule_name,
testonly = True,
linkopts = tflite_linkopts_no_undefined(),
deps = [":%s" % rule_name],
)
build_test(
name = "%s_build_test" % rule_name,
targets = ["%s_test_shared_lib" % rule_name],
)
build_tests.append("%s_build_test" % rule_name)
native.test_suite(
name = name,
tests = build_tests,
)
def _label(target):
"""Return a Label <https://bazel.build/rules/lib/Label#Label> given a string.
Args:
target: (string) a relative or absolute build target.
"""
if target[0:2] == "//" or "@org_tensorflow//" in target:
return Label(target)
if target[0] == ":":
return Label("//" + native.package_name() + target)
return Label("//" + native.package_name() + ":" + target)
def tflite_cc_library_with_c_headers_test(name, hdrs, **kwargs):
"""Defines a C++ library with C-compatible header files.
This generates a cc_library rule, but also generates
build tests that verify that each of the 'hdrs'
can be successfully built in a C (not C++!) compilation unit
that directly includes only that header file.
Args:
name: (string) as per cc_library.
hdrs: (list of string) as per cc_library.
**kwargs: Additional kwargs to pass to cc_library.
"""
cc_library(name = name, hdrs = hdrs, **kwargs)
build_tests = []
for hdr in hdrs:
label = _label(hdr)
basename = "%s__test_self_contained_c__%s__%s" % (name, label.package, label.name)
compatible_with = kwargs.pop("compatible_with", [])
native.genrule(
name = "%s_gen" % basename,
outs = ["%s.c" % basename],
compatible_with = compatible_with,
cmd = "echo '#include \"%s/%s\"' > $@" % (label.package, label.name),
visibility = ["//visibility:private"],
testonly = True,
)
kwargs.pop("visibility", None)
kwargs.pop("deps", [])
kwargs.pop("srcs", [])
kwargs.pop("tags", [])
kwargs.pop("testonly", [])
cc_library(
name = "%s_lib" % basename,
srcs = ["%s.c" % basename],
deps = [":" + name],
compatible_with = compatible_with,
copts = kwargs.pop("copts", []),
visibility = ["//visibility:private"],
testonly = True,
tags = ["allow_undefined_symbols"],
**kwargs
)
build_test(
name = "%s_build_test" % basename,
visibility = ["//visibility:private"],
targets = ["%s_lib" % basename],
)
build_tests.append("%s_build_test" % basename)
native.test_suite(
name = name + "_self_contained_c_build_tests",
tests = build_tests,
)
register_extension_info(
extension = tflite_cc_library_with_c_headers_test,
label_regex_for_dep = "{extension_name}",
)
# Workaround bug in Bazel before 8.0 where --cxxopt didn't apply to objc++ compilations.
CXX17_BAZEL_ONLY_COPTS = [
"-std=c++17", # copybara:comment
]
+22
View File
@@ -0,0 +1,22 @@
/* Copyright 2017 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.
==============================================================================*/
// Compatibility shim for new location of interface definitions.
#ifndef TENSORFLOW_LITE_BUILTIN_OP_DATA_H_
#define TENSORFLOW_LITE_BUILTIN_OP_DATA_H_
#include "tensorflow/lite/core/c/builtin_op_data.h"
#endif // TENSORFLOW_LITE_BUILTIN_OP_DATA_H_
+245
View File
@@ -0,0 +1,245 @@
/* Copyright 2018 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_BUILTIN_OPS_H_
#define TENSORFLOW_LITE_BUILTIN_OPS_H_
// DO NOT EDIT MANUALLY: This file is automatically generated by
// `schema/builtin_ops_header/generator.cc`.
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// The enum for builtin operators.
// Note: CUSTOM, DELEGATE, and PLACEHOLDER_FOR_GREATER_OP_CODES are 3 special
// ops which are not real built-in ops.
typedef enum {
kTfLiteBuiltinAdd = 0,
kTfLiteBuiltinAveragePool2d = 1,
kTfLiteBuiltinConcatenation = 2,
kTfLiteBuiltinConv2d = 3,
kTfLiteBuiltinDepthwiseConv2d = 4,
kTfLiteBuiltinDepthToSpace = 5,
kTfLiteBuiltinDequantize = 6,
kTfLiteBuiltinEmbeddingLookup = 7,
kTfLiteBuiltinFloor = 8,
kTfLiteBuiltinFullyConnected = 9,
kTfLiteBuiltinHashtableLookup = 10,
kTfLiteBuiltinL2Normalization = 11,
kTfLiteBuiltinL2Pool2d = 12,
kTfLiteBuiltinLocalResponseNormalization = 13,
kTfLiteBuiltinLogistic = 14,
kTfLiteBuiltinLshProjection = 15,
kTfLiteBuiltinLstm = 16,
kTfLiteBuiltinMaxPool2d = 17,
kTfLiteBuiltinMul = 18,
kTfLiteBuiltinRelu = 19,
kTfLiteBuiltinReluN1To1 = 20,
kTfLiteBuiltinRelu6 = 21,
kTfLiteBuiltinReshape = 22,
kTfLiteBuiltinResizeBilinear = 23,
kTfLiteBuiltinRnn = 24,
kTfLiteBuiltinSoftmax = 25,
kTfLiteBuiltinSpaceToDepth = 26,
kTfLiteBuiltinSvdf = 27,
kTfLiteBuiltinTanh = 28,
kTfLiteBuiltinConcatEmbeddings = 29,
kTfLiteBuiltinSkipGram = 30,
kTfLiteBuiltinCall = 31,
kTfLiteBuiltinCustom = 32,
kTfLiteBuiltinEmbeddingLookupSparse = 33,
kTfLiteBuiltinPad = 34,
kTfLiteBuiltinUnidirectionalSequenceRnn = 35,
kTfLiteBuiltinGather = 36,
kTfLiteBuiltinBatchToSpaceNd = 37,
kTfLiteBuiltinSpaceToBatchNd = 38,
kTfLiteBuiltinTranspose = 39,
kTfLiteBuiltinMean = 40,
kTfLiteBuiltinSub = 41,
kTfLiteBuiltinDiv = 42,
kTfLiteBuiltinSqueeze = 43,
kTfLiteBuiltinUnidirectionalSequenceLstm = 44,
kTfLiteBuiltinStridedSlice = 45,
kTfLiteBuiltinBidirectionalSequenceRnn = 46,
kTfLiteBuiltinExp = 47,
kTfLiteBuiltinTopkV2 = 48,
kTfLiteBuiltinSplit = 49,
kTfLiteBuiltinLogSoftmax = 50,
kTfLiteBuiltinDelegate = 51,
kTfLiteBuiltinBidirectionalSequenceLstm = 52,
kTfLiteBuiltinCast = 53,
kTfLiteBuiltinPrelu = 54,
kTfLiteBuiltinMaximum = 55,
kTfLiteBuiltinArgMax = 56,
kTfLiteBuiltinMinimum = 57,
kTfLiteBuiltinLess = 58,
kTfLiteBuiltinNeg = 59,
kTfLiteBuiltinPadv2 = 60,
kTfLiteBuiltinGreater = 61,
kTfLiteBuiltinGreaterEqual = 62,
kTfLiteBuiltinLessEqual = 63,
kTfLiteBuiltinSelect = 64,
kTfLiteBuiltinSlice = 65,
kTfLiteBuiltinSin = 66,
kTfLiteBuiltinTransposeConv = 67,
kTfLiteBuiltinSparseToDense = 68,
kTfLiteBuiltinTile = 69,
kTfLiteBuiltinExpandDims = 70,
kTfLiteBuiltinEqual = 71,
kTfLiteBuiltinNotEqual = 72,
kTfLiteBuiltinLog = 73,
kTfLiteBuiltinSum = 74,
kTfLiteBuiltinSqrt = 75,
kTfLiteBuiltinRsqrt = 76,
kTfLiteBuiltinShape = 77,
kTfLiteBuiltinPow = 78,
kTfLiteBuiltinArgMin = 79,
kTfLiteBuiltinFakeQuant = 80,
kTfLiteBuiltinReduceProd = 81,
kTfLiteBuiltinReduceMax = 82,
kTfLiteBuiltinPack = 83,
kTfLiteBuiltinLogicalOr = 84,
kTfLiteBuiltinOneHot = 85,
kTfLiteBuiltinLogicalAnd = 86,
kTfLiteBuiltinLogicalNot = 87,
kTfLiteBuiltinUnpack = 88,
kTfLiteBuiltinReduceMin = 89,
kTfLiteBuiltinFloorDiv = 90,
kTfLiteBuiltinReduceAny = 91,
kTfLiteBuiltinSquare = 92,
kTfLiteBuiltinZerosLike = 93,
kTfLiteBuiltinFill = 94,
kTfLiteBuiltinFloorMod = 95,
kTfLiteBuiltinRange = 96,
kTfLiteBuiltinResizeNearestNeighbor = 97,
kTfLiteBuiltinLeakyRelu = 98,
kTfLiteBuiltinSquaredDifference = 99,
kTfLiteBuiltinMirrorPad = 100,
kTfLiteBuiltinAbs = 101,
kTfLiteBuiltinSplitV = 102,
kTfLiteBuiltinUnique = 103,
kTfLiteBuiltinCeil = 104,
kTfLiteBuiltinReverseV2 = 105,
kTfLiteBuiltinAddN = 106,
kTfLiteBuiltinGatherNd = 107,
kTfLiteBuiltinCos = 108,
kTfLiteBuiltinWhere = 109,
kTfLiteBuiltinRank = 110,
kTfLiteBuiltinElu = 111,
kTfLiteBuiltinReverseSequence = 112,
kTfLiteBuiltinMatrixDiag = 113,
kTfLiteBuiltinQuantize = 114,
kTfLiteBuiltinMatrixSetDiag = 115,
kTfLiteBuiltinRound = 116,
kTfLiteBuiltinHardSwish = 117,
kTfLiteBuiltinIf = 118,
kTfLiteBuiltinWhile = 119,
kTfLiteBuiltinNonMaxSuppressionV4 = 120,
kTfLiteBuiltinNonMaxSuppressionV5 = 121,
kTfLiteBuiltinScatterNd = 122,
kTfLiteBuiltinSelectV2 = 123,
kTfLiteBuiltinDensify = 124,
kTfLiteBuiltinSegmentSum = 125,
kTfLiteBuiltinBatchMatmul = 126,
kTfLiteBuiltinPlaceholderForGreaterOpCodes = 127,
kTfLiteBuiltinCumsum = 128,
kTfLiteBuiltinCallOnce = 129,
kTfLiteBuiltinBroadcastTo = 130,
kTfLiteBuiltinRfft2d = 131,
kTfLiteBuiltinConv3d = 132,
kTfLiteBuiltinImag = 133,
kTfLiteBuiltinReal = 134,
kTfLiteBuiltinComplexAbs = 135,
kTfLiteBuiltinHashtable = 136,
kTfLiteBuiltinHashtableFind = 137,
kTfLiteBuiltinHashtableImport = 138,
kTfLiteBuiltinHashtableSize = 139,
kTfLiteBuiltinReduceAll = 140,
kTfLiteBuiltinConv3dTranspose = 141,
kTfLiteBuiltinVarHandle = 142,
kTfLiteBuiltinReadVariable = 143,
kTfLiteBuiltinAssignVariable = 144,
kTfLiteBuiltinBroadcastArgs = 145,
kTfLiteBuiltinRandomStandardNormal = 146,
kTfLiteBuiltinBucketize = 147,
kTfLiteBuiltinRandomUniform = 148,
kTfLiteBuiltinMultinomial = 149,
kTfLiteBuiltinGelu = 150,
kTfLiteBuiltinDynamicUpdateSlice = 151,
kTfLiteBuiltinRelu0To1 = 152,
kTfLiteBuiltinUnsortedSegmentProd = 153,
kTfLiteBuiltinUnsortedSegmentMax = 154,
kTfLiteBuiltinUnsortedSegmentSum = 155,
kTfLiteBuiltinAtan2 = 156,
kTfLiteBuiltinUnsortedSegmentMin = 157,
kTfLiteBuiltinSign = 158,
kTfLiteBuiltinBitcast = 159,
kTfLiteBuiltinBitwiseXor = 160,
kTfLiteBuiltinRightShift = 161,
kTfLiteBuiltinStablehloLogistic = 162,
kTfLiteBuiltinStablehloAdd = 163,
kTfLiteBuiltinStablehloDivide = 164,
kTfLiteBuiltinStablehloMultiply = 165,
kTfLiteBuiltinStablehloMaximum = 166,
kTfLiteBuiltinStablehloReshape = 167,
kTfLiteBuiltinStablehloClamp = 168,
kTfLiteBuiltinStablehloConcatenate = 169,
kTfLiteBuiltinStablehloBroadcastInDim = 170,
kTfLiteBuiltinStablehloConvolution = 171,
kTfLiteBuiltinStablehloSlice = 172,
kTfLiteBuiltinStablehloCustomCall = 173,
kTfLiteBuiltinStablehloReduce = 174,
kTfLiteBuiltinStablehloAbs = 175,
kTfLiteBuiltinStablehloAnd = 176,
kTfLiteBuiltinStablehloCosine = 177,
kTfLiteBuiltinStablehloExponential = 178,
kTfLiteBuiltinStablehloFloor = 179,
kTfLiteBuiltinStablehloLog = 180,
kTfLiteBuiltinStablehloMinimum = 181,
kTfLiteBuiltinStablehloNegate = 182,
kTfLiteBuiltinStablehloOr = 183,
kTfLiteBuiltinStablehloPower = 184,
kTfLiteBuiltinStablehloRemainder = 185,
kTfLiteBuiltinStablehloRsqrt = 186,
kTfLiteBuiltinStablehloSelect = 187,
kTfLiteBuiltinStablehloSubtract = 188,
kTfLiteBuiltinStablehloTanh = 189,
kTfLiteBuiltinStablehloScatter = 190,
kTfLiteBuiltinStablehloCompare = 191,
kTfLiteBuiltinStablehloConvert = 192,
kTfLiteBuiltinStablehloDynamicSlice = 193,
kTfLiteBuiltinStablehloDynamicUpdateSlice = 194,
kTfLiteBuiltinStablehloPad = 195,
kTfLiteBuiltinStablehloIota = 196,
kTfLiteBuiltinStablehloDotGeneral = 197,
kTfLiteBuiltinStablehloReduceWindow = 198,
kTfLiteBuiltinStablehloSort = 199,
kTfLiteBuiltinStablehloWhile = 200,
kTfLiteBuiltinStablehloGather = 201,
kTfLiteBuiltinStablehloTranspose = 202,
kTfLiteBuiltinDilate = 203,
kTfLiteBuiltinStablehloRngBitGenerator = 204,
kTfLiteBuiltinReduceWindow = 205,
kTfLiteBuiltinStablehloComposite = 206,
kTfLiteBuiltinStablehloShiftLeft = 207,
kTfLiteBuiltinStablehloCbrt = 208,
kTfLiteBuiltinStablehloCase = 209,
} TfLiteBuiltinOperator;
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // TENSORFLOW_LITE_BUILTIN_OPS_H_
+483
View File
@@ -0,0 +1,483 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("//tensorflow:tensorflow.default.bzl", "get_compatible_with_portable")
load(
"//tensorflow/lite:build_def.bzl",
"tflite_cc_library_with_c_headers_test",
"tflite_cc_shared_object",
"tflite_copts",
"tflite_copts_warnings",
"tflite_custom_c_library",
"tflite_linkopts_no_undefined",
"tflite_self_contained_libs_test_suite",
)
load("//tensorflow/lite:special_rules.bzl", "c_api_opaque_internal_visibility_allowlist", "tflite_portable_test_suite")
load("//tensorflow/lite/core/shims:cc_library_with_tflite.bzl", "cc_library_with_tflite_with_c_headers_test")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = ["//visibility:public"],
licenses = ["notice"],
)
# Generates a platform-specific shared library containing the TensorFlow Lite C
# API implementation as define in `c_api.h`. The exact output library name
# is platform dependent:
# - Linux/Android: `libtensorflowlite_c.so`
# - Mac: `libtensorflowlite_c.dylib`
# - Windows: `tensorflowlite_c.dll`
tflite_cc_shared_object(
name = "tensorflowlite_c",
linkopts = tflite_linkopts_no_undefined() + select({
"//tensorflow:ios": [
"-Wl,-exported_symbols_list,$(location //tensorflow/lite/c:exported_symbols.lds)",
],
"//tensorflow:macos": [
"-Wl,-exported_symbols_list,$(location //tensorflow/lite/c:exported_symbols.lds)",
],
"//tensorflow:windows": [],
"//conditions:default": [
"-Wl,--version-script,$(location //tensorflow/lite/c:version_script.lds)",
],
}),
per_os_targets = True,
deps = [
":c_api",
":c_api_experimental",
":exported_symbols.lds",
":version_script.lds",
],
)
cc_library_with_tflite_with_c_headers_test(
name = "c_api",
hdrs = [
"c_api.h",
],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts(),
generate_opaque_delegate_target = True,
deps = [
":c_api_without_op_resolver",
"//tensorflow/lite/core/async/c:types",
"//tensorflow/lite/core/c:c_api",
],
)
tflite_cc_library_with_c_headers_test(
name = "c_api_for_testing",
testonly = True,
srcs = ["c_api_for_testing.cc"],
hdrs = ["c_api_for_testing.h"],
deps = [
":c_api",
":c_api_internal",
"//tensorflow/lite/core/c:c_api",
],
)
# TODO(b/248514738): Deprecate this target in favour
# of //third_party/tensorflow/lite/core/c:c_api_without_op_resolver after all known existing uses of
# those targets have been changed to instead refer to the new target.
# Same as ":c_api", but doesn't link in the default CreateOpResolver implementation.
cc_library_with_tflite_with_c_headers_test(
name = "c_api_without_op_resolver",
hdrs = ["c_api.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts(),
tags = ["allow_undefined_symbols"], # For tflite::CreateOpResolver().
deps = [
":c_api_types",
"//tensorflow/lite/core/c:c_api_without_op_resolver",
],
)
# TODO(b/248514738): Deprecate this target in favour
# of //third_party/tensorflow/lite/core/c:c_api_without_op_resolver_without_alwayslink after all
# known existing uses of those targets have been changed to instead refer to the new target.
# Same as ":c_api_without_op_resolver", but without alwayslink=1.
cc_library_with_tflite_with_c_headers_test(
name = "c_api_without_op_resolver_without_alwayslink",
hdrs = ["c_api.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts(),
tags = ["allow_undefined_symbols"], # For tflite::CreateOpResolver().
deps = ["//tensorflow/lite/core/c:c_api_without_op_resolver_without_alwayslink"],
)
cc_library_with_tflite_with_c_headers_test(
name = "c_api_experimental",
hdrs = [
"c_api_experimental.h",
# ':c_api_opaque' was promoted to the 'mostly stable' API.
# Please explicitly add a dependency on ':c_api_opaque' if your target
# needs both ':c_api_experimental' and ':c_api_opaque' dependencies.
# We plan to remove 'c_api_opaque.h' from the list of exposed headers and
# will remove the dependency from this target on ':c_api_opaque' in the future.
"c_api_opaque.h",
],
copts = tflite_copts() + tflite_copts_warnings(),
generate_opaque_delegate_target = True,
tflite_deps = [
":c_api",
],
deps = [
"//tensorflow/lite/core/c:c_api_experimental",
"//tensorflow/lite/core/c:c_api_opaque",
],
)
# Same as ":c_api_experimental", but without linking in the default CreateOpResolver implementation.
cc_library_with_tflite_with_c_headers_test(
name = "c_api_experimental_without_op_resolver",
hdrs = [
"c_api_experimental.h",
# DEPRECATED
# ':c_api_opaque_without_op_resolver' was promoted to the 'mostly stable' API.
# Please explicitly add a dependency on ':c_api_opaque_without_op_resolver' if your target
# needs both ':c_api_experimental_without_op_resolver' and ':c_api_opaque_without_op_resolver' dependencies.
# We plan to remove 'c_api_opaque.h' from the list of exposed headers and
# will remove the dependency from this target on ':c_api_opaque_without_op_resolver' in the future.
"c_api_opaque.h",
],
copts = tflite_copts() + tflite_copts_warnings(),
tags = ["allow_undefined_symbols"], # For tflite::CreateOpResolver().
tflite_deps = [
":c_api_without_op_resolver",
],
deps = [
"//tensorflow/lite/core/c:c_api_experimental_without_op_resolver",
"//tensorflow/lite/core/c:c_api_opaque_without_op_resolver",
],
)
# Same as ":c_api_experimental", but without linking in the default CreateOpResolver implementation,
# and without depending on targets that use alwayslink=1.
cc_library_with_tflite_with_c_headers_test(
name = "c_api_experimental_without_op_resolver_without_alwayslink",
hdrs = [
"c_api_experimental.h",
# DEPRECATED
# ':c_api_opaque_without_op_resolver_without_alwayslink' was promoted to the 'mostly stable' API.
# Please explicitly add a dependency on ':c_api_opaque_without_op_resolver_without_alwayslink'
# if your target needs both ':c_api_experimental_without_op_resolver_without_alwayslink' and
# ':c_api_opaque_without_op_resolver_without_alwayslink' dependencies.
# We plan to remove 'c_api_opaque.h' from the list of exposed headers and
# will remove the dependency from this target on
# ':c_api_opaque_without_op_resolver_without_alwayslink' in the future.
"c_api_opaque.h",
],
copts = tflite_copts() + tflite_copts_warnings(),
tags = ["allow_undefined_symbols"], # For tflite::CreateOpResolver().
tflite_deps = [":c_api_without_op_resolver_without_alwayslink"],
deps = [
"//tensorflow/lite/core/c:c_api_experimental_without_op_resolver_without_alwayslink",
"//tensorflow/lite/core/c:c_api_opaque_without_op_resolver_without_alwayslink",
],
)
cc_library_with_tflite_with_c_headers_test(
name = "c_api_opaque",
hdrs = [
"c_api_opaque.h",
],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
generate_opaque_delegate_target = True,
tflite_deps = [":c_api"],
deps = ["//tensorflow/lite/core/c:c_api_opaque"],
)
cc_library_with_tflite_with_c_headers_test(
name = "c_api_opaque_without_op_resolver",
hdrs = [
"c_api_opaque.h",
],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
tags = ["allow_undefined_symbols"], # For tflite::CreateOpResolver().
tflite_deps = [":c_api_without_op_resolver"],
deps = ["//tensorflow/lite/core/c:c_api_opaque_without_op_resolver"],
)
cc_library_with_tflite_with_c_headers_test(
name = "c_api_opaque_without_op_resolver_without_alwayslink",
hdrs = [
"c_api_opaque.h",
],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
tags = ["allow_undefined_symbols"], # For tflite::CreateOpResolver().
tflite_deps = [
":c_api_without_op_resolver_without_alwayslink",
],
deps = ["//tensorflow/lite/core/c:c_api_opaque_without_op_resolver_without_alwayslink"],
)
cc_library_with_tflite_with_c_headers_test(
name = "c_api_types",
hdrs = ["c_api_types.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
generate_opaque_delegate_target = True,
deps = ["//tensorflow/lite/core/c:c_api_types"],
)
cc_library(
name = "c_api_internal",
hdrs = ["c_api_internal.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts(),
visibility = [
"//tensorflow/lite/core/async/c:__subpackages__",
"//tensorflow/lite/core/c:__subpackages__",
],
deps = [
":common_internal",
"//tensorflow/lite:builtin_ops",
"//tensorflow/lite:framework",
"//tensorflow/lite/core:framework",
"//tensorflow/lite/core/api",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/profiling/telemetry/c:profiler",
],
)
filegroup(
name = "c_api_test_builtin_op_models",
testonly = 1,
srcs = [
"//tensorflow/lite:testdata/add.bin",
"//tensorflow/lite:testdata/add_quantized.bin",
],
)
# TODO(b/248514738): Deprecate this target in favour
# of //third_party/tensorflow/lite/core/c:c_api_test after all known existing uses of those targets
# have been changed to instead refer to the new target.
test_suite(
name = "c_api_test",
tests = [
"//tensorflow/lite/core/c:c_api_test",
],
)
tflite_custom_c_library(
name = "selectively_built_c_api_test_lib",
testonly = 1,
experimental = True,
models = [":c_api_test_builtin_op_models"],
visibility = [
"//tensorflow/lite/core/c:__subpackages__",
],
)
# TODO(b/248514738): Deprecate this target in favour
# of //third_party/tensorflow/lite/core/c:selectively_built_c_api_test after all known existing uses
# of those targets have been changed to instead refer to the new target.
test_suite(
name = "selectively_built_c_api_test",
tests = [
"//tensorflow/lite/core/c:selectively_built_c_api_test",
],
)
test_suite(
name = "c_api_experimental_test",
tests = [
"//tensorflow/lite/core/c:c_api_experimental_test",
],
)
cc_test(
name = "c_api_signature_runner_test",
size = "small",
srcs = ["c_api_signature_runner_test.cc"],
copts = tflite_copts(),
data = [
"//tensorflow/lite:testdata/multi_signatures.bin",
"//tensorflow/lite:testdata/no_signatures.bin",
],
deps = [
":c_api",
"//tensorflow/lite/core/c:c_api",
"//tensorflow/lite/core/c:common",
"@com_google_googletest//:gtest_main",
],
)
cc_library_with_tflite_with_c_headers_test(
name = "common",
hdrs = [
"builtin_op_data.h",
"common.h",
],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
generate_opaque_delegate_target = True,
tflite_deps = [
":c_api_types",
],
deps = [
"//tensorflow/lite:tflite_kernel_use_xnnpack_optional",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
] + select({
"//tensorflow/lite:tensorflow_profiler_config": [
"//tensorflow/lite:macros",
"//tensorflow/lite:tensorflow_profiler_logger_shim",
],
"//conditions:default": [],
}),
)
cc_library(
name = "common_internal",
srcs = ["common_internal.cc"],
hdrs = ["common_internal.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts(),
visibility = [
"//tensorflow/lite:__subpackages__",
],
deps = [
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
],
)
cc_library(
name = "c_api_opaque_internal",
srcs = ["c_api_opaque_internal.cc"],
hdrs = ["c_api_opaque_internal.h"],
compatible_with = get_compatible_with_portable(),
tags = ["allow_undefined_symbols"], # For tflite::CreateOpResolver().
visibility = [
"//tensorflow/lite:__subpackages__",
] + c_api_opaque_internal_visibility_allowlist(),
deps = [
":c_api_types",
"//tensorflow/lite:framework",
"//tensorflow/lite/c:c_api_internal",
"//tensorflow/lite/core/api:op_resolver",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/core/c:operator",
],
)
cc_test(
name = "c_api_opaque_internal_test",
srcs = ["c_api_opaque_internal_test.cc"],
data = [
"//tensorflow/lite:testdata/add.bin",
],
deps = [
":c_api_internal",
":c_api_opaque_internal",
"//tensorflow/lite:builtin_ops",
"//tensorflow/lite:framework",
"//tensorflow/lite/kernels:builtin_ops",
"@com_google_googletest//:gtest_main",
],
)
# Same as c_api_opaque_internal, but depends on the
# '_without_alwayslink' variant of ':c_api_without_op_resolver'.
cc_library(
name = "c_api_opaque_internal_without_alwayslink",
srcs = ["c_api_opaque_internal.cc"],
hdrs = ["c_api_opaque_internal.h"],
compatible_with = get_compatible_with_portable(),
tags = ["allow_undefined_symbols"], # For tflite::CreateOpResolver().
visibility = [
"//tensorflow/lite:__subpackages__",
],
deps = [
":c_api_types",
"//tensorflow/lite:framework",
"//tensorflow/lite/c:c_api_internal",
"//tensorflow/lite/core/api:op_resolver",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/core/c:operator_without_alwayslink",
],
)
# For use with library targets that can't use relative paths.
# LINT.IfChange(exported_headers)
exports_files([
"builtin_op_data.h",
"c_api.h",
"c_api_experimental.h",
"c_api_opaque.h",
"c_api_types.h",
"common.h",
])
filegroup(
name = "tensorflowlite_c_api_hdrs_filegroup",
srcs = [
"builtin_op_data.h",
"c_api.h",
"c_api_types.h",
"common.h",
],
)
alias(
name = "tensorflowlite_c_impl_hdrs_filegroup",
actual = "//tensorflow/lite/core/c:headers_filegroup",
)
# LINT.ThenChange(../java/BUILD:TFLITE_HEADERS)
# Test the C extension API code.
test_suite(
name = "common_test",
tests = [
"//tensorflow/lite/core/c:common_test",
],
)
test_suite(
name = "builtin_op_data_test",
tests = [
"//tensorflow/lite/core/c:builtin_op_data_test",
],
)
cc_test(
name = "c_test",
size = "small",
srcs = ["c_test.c"],
copts = tflite_copts(),
data = [
"//tensorflow/lite:testdata/add.bin",
"//tensorflow/lite:testdata/multi_signatures.bin",
],
tags = [
# Testing on Android uses "--gunit_output=xml:test.xml" runtime flag,
# but this test is C code, not C++, and hence doesn't use GUnit,
# so doesn't support that flag.
"tflite_not_portable_android",
],
deps = [
":c_api",
":c_api_experimental",
"//tensorflow/lite/core/c:c_api",
"//tensorflow/lite/core/c:c_api_experimental",
"//tensorflow/lite/core/c:c_api_opaque",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
],
)
cc_library_with_tflite_with_c_headers_test(
name = "test_util",
testonly = True,
srcs = ["test_util.cc"],
hdrs = ["test_util.h"],
generate_opaque_delegate_target = True,
)
tflite_self_contained_libs_test_suite(name = "self_contained_libs_test_suite")
tflite_portable_test_suite()
+92
View File
@@ -0,0 +1,92 @@
#
# Copyright 2021 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
#
# https://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.
cmake_minimum_required(VERSION 3.16)
project(tensorflow-lite-c C CXX)
option(TFLITE_C_BUILD_SHARED_LIBS "Build shared libraries" ON)
set(TF_SOURCE_DIR "" CACHE PATH
"Directory that contains the TensorFlow project"
)
if (NOT TF_SOURCE_DIR)
get_filename_component(TF_SOURCE_DIR
"${CMAKE_CURRENT_LIST_DIR}/../../../"
ABSOLUTE
)
endif()
set(TFLITE_SOURCE_DIR "${TF_SOURCE_DIR}/tensorflow/lite")
add_subdirectory(
"${TFLITE_SOURCE_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}/tensorflow-lite"
EXCLUDE_FROM_ALL
)
set(CMAKE_CXX_STANDARD 20)
if(CMAKE_SYSTEM_NAME MATCHES "Windows"
AND (MSVC AND (CMAKE_SIZEOF_VOID_P EQUAL 4)))
message("Disabling MSVC /O2 optimization for Win32")
set(CompFlags
CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_RELWITHDEBINFO
CMAKE_C_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELWITHDEBINFO
)
foreach (CompFlag ${CompFlags})
string(REGEX REPLACE "(\/Ob. )" "" ${CompFlag} "${${CompFlag}}")
string(REPLACE "/O2" "/O1" ${CompFlag} "${${CompFlag}}")
list(REMOVE_DUPLICATES ${CompFlag})
set(${CompFlag} "${${CompFlag}}" CACHE INTERNAL "")
endforeach()
endif()
set(TFLITE_C_LIBTYPE STATIC)
if (TFLITE_C_BUILD_SHARED_LIBS)
set(TFLITE_C_LIBTYPE SHARED)
endif()
add_library(tensorflowlite_c ${TFLITE_C_LIBTYPE}
${TFLITE_SOURCE_DIR}/core/c/c_api.cc
${TFLITE_SOURCE_DIR}/core/c/c_api_experimental.cc
${TFLITE_SOURCE_DIR}/core/c/common.cc
${TFLITE_SOURCE_DIR}/core/c/operator.cc
${TF_SOURCE_DIR}/tensorflow/compiler/mlir/lite/core/c/tflite_types.h
builtin_op_data.h
c_api.h
c_api_experimental.h
c_api_internal.h
c_api_types.h
common.h
)
if (TFLITE_C_BUILD_SHARED_LIBS)
if (WIN32)
target_compile_definitions(tensorflowlite_c PRIVATE TFL_COMPILE_LIBRARY)
target_compile_definitions(tensorflow-lite PRIVATE TFL_COMPILE_LIBRARY)
elseif (APPLE)
target_link_options(tensorflowlite_c PRIVATE "-Wl,-exported_symbols_list,${TFLITE_SOURCE_DIR}/c/exported_symbols.lds")
else ()
target_link_options(tensorflowlite_c PRIVATE "-Wl,--version-script,${TFLITE_SOURCE_DIR}/c/version_script.lds")
endif()
endif()
target_link_libraries(tensorflowlite_c
tensorflow-lite
)
+49
View File
@@ -0,0 +1,49 @@
# TensorFlow Lite C API
This directory contains C APIs for TensorFlow Lite. This includes C APIs
for common types, like kernels and delegates, as well as an explicit C API
for inference.
## Header summary
Each public C header contains types and methods for specific uses:
* `common.h` - Contains common C enums, types and methods used throughout
TensorFlow Lite. This includes everything from error codes, to the kernel
and delegate APIs.
* `builtin_op_data.h` - Contains op-specific data that is used for builtin
kernels. This should only be used when (re)implementing a builtin operator.
* `c_api.h` - Contains the TensorFlow Lite C API for inference. The
functionality here is largely equivalent (though a strict subset of) the
functionality provided by the C++ `Interpreter` API.
* `c_api_experimental.h` - Contains experimental C API methods for inference.
These methods are useful and usable, but aren't yet part of the stable API.
## Using the C API
See the [`c_api.h`](c_api.h) header for API usage details.
## Building the C API
A native shared library target that contains the C API for inference has been
provided. Assuming a working [bazel](https://bazel.build/versions/master/docs/install.html)
configuration, this can be built as follows:
```sh
bazel build -c opt //tensorflow/lite/c:tensorflowlite_c
```
and for Android (replace `android_arm` with `android_arm64` for 64-bit),
assuming you've
[configured your project for Android builds](../g3doc/android/lite_build.md):
```sh
bazel build -c opt --cxxopt=--std=c++11 --config=android_arm \
//tensorflow/lite/c:tensorflowlite_c
```
The generated shared library will be available in your
`bazel-bin/tensorflow/lite/c` directory. A target which packages the shared
library together with the necessary headers (`c_api.h`, `c_api_experimental.h`
and `common.h`) will be available soon, and will also be released as a prebuilt
archive (together with existing prebuilt packages for Android/iOS).
+23
View File
@@ -0,0 +1,23 @@
/* 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_C_BUILTIN_OP_DATA_H_
#define TENSORFLOW_LITE_C_BUILTIN_OP_DATA_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/c/builtin_op_data.h
#include "tensorflow/lite/core/c/builtin_op_data.h"
#endif // TENSORFLOW_LITE_C_BUILTIN_OP_DATA_H_
+58
View File
@@ -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.
==============================================================================*/
#ifndef TENSORFLOW_LITE_C_C_API_H_
#define TENSORFLOW_LITE_C_C_API_H_
/// \file
///
/// C API for TensorFlow Lite.
///
/// For documentation, see tensorflow/lite/core/c/c_api.h
#include "tensorflow/lite/core/c/c_api.h"
#ifndef DOYXGEN_SKIP
// For backwards compatibility.
// Deprecated. Use the names starting with TfLiteOperator instead.
#ifdef __cplusplus
using TfLiteRegistrationExternal = TfLiteOperator;
// NOLINTBEGIN
const auto TfLiteRegistrationExternalCreate = TfLiteOperatorCreate;
const auto TfLiteRegistrationExternalGetBuiltInCode =
TfLiteOperatorGetBuiltInCode;
const auto TfLiteRegistrationExternalGetVersion = TfLiteOperatorGetVersion;
const auto TfLiteRegistrationExternalDelete = TfLiteOperatorDelete;
const auto TfLiteRegistrationExternalSetInit = TfLiteOperatorSetInit;
const auto TfLiteRegistrationExternalSetFree = TfLiteOperatorSetFree;
const auto TfLiteRegistrationExternalSetPrepare = TfLiteOperatorSetPrepare;
const auto TfLiteRegistrationExternalSetInvoke = TfLiteOperatorSetInvoke;
const auto TfLiteRegistrationExternalGetCustomName =
TfLiteOperatorGetCustomName;
// NOLINTEND
#else
typedef TfLiteOperator TfLiteRegistrationExternal;
#define TfLiteRegistrationExternalCreate TfLiteOperatorCreate
#define TfLiteRegistrationExternalGetBuiltInCode TfLiteOperatorGetBuiltInCode
#define TfLiteRegistrationExternalGetVersion TfLiteOperatorGetVersion
#define TfLiteRegistrationExternalDelete TfLiteOperatorDelete
#define TfLiteRegistrationExternalSetInit TfLiteOperatorSetInit
#define TfLiteRegistrationExternalSetFree TfLiteOperatorSetFree
#define TfLiteRegistrationExternalSetPrepare TfLiteOperatorSetPrepare
#define TfLiteRegistrationExternalSetInvoke TfLiteOperatorSetInvoke
#define TfLiteRegistrationExternalGetCustomName TfLiteOperatorGetCustomName
#endif // __cplusplus
#endif // DOYXGEN_SKIP
#endif // TENSORFLOW_LITE_C_C_API_H_
+23
View File
@@ -0,0 +1,23 @@
/* 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_C_C_API_EXPERIMENTAL_H_
#define TENSORFLOW_LITE_C_C_API_EXPERIMENTAL_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/c/c_api_experimental.h
#include "tensorflow/lite/core/c/c_api_experimental.h"
#endif // TENSORFLOW_LITE_C_C_API_EXPERIMENTAL_H_
+28
View File
@@ -0,0 +1,28 @@
/* Copyright 2021 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/c/c_api_for_testing.h"
#include <cstdint>
#include "tensorflow/lite/c/c_api_internal.h"
extern "C" {
int32_t TfLiteInterpreterOptionsGetNumThreads(
TfLiteInterpreterOptions* options) {
return options->num_threads;
}
} // extern "C"
+32
View File
@@ -0,0 +1,32 @@
/* Copyright 2021 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_C_C_API_FOR_TESTING_H_
#define TENSORFLOW_LITE_C_C_API_FOR_TESTING_H_
#include "tensorflow/lite/core/c/c_api.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Gets the number of CPU threads to use for the interpreter.
TFL_CAPI_EXPORT extern int32_t TfLiteInterpreterOptionsGetNumThreads(
TfLiteInterpreterOptions* options);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // TENSORFLOW_LITE_C_C_API_FOR_TESTING_H_
+299
View File
@@ -0,0 +1,299 @@
/* Copyright 2018 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_C_C_API_INTERNAL_H_
#define TENSORFLOW_LITE_C_C_API_INTERNAL_H_
#include <stdarg.h>
#include <functional>
#include <memory>
#include <mutex> // NOLINT
#include <vector>
#include "tensorflow/lite/builtin_ops.h"
#include "tensorflow/lite/core/api/error_reporter.h"
#include "tensorflow/lite/core/api/op_resolver.h"
#include "tensorflow/lite/core/interpreter.h"
#include "tensorflow/lite/core/model_builder.h"
#include "tensorflow/lite/mutable_op_resolver.h"
#include "tensorflow/lite/profiling/telemetry/c/profiler.h"
#include "tensorflow/lite/signature_runner.h"
// Internal structures and subroutines used by the C API. These are likely to
// change and should not be depended on directly by any C API clients.
//
// NOTE: This header does not follow C conventions and does not define a C API.
// It is effectively an (internal) implementation detail of the C API.
struct TfLiteModel {
// Sharing is safe as FlatBufferModel is const.
std::shared_ptr<const tflite::impl::FlatBufferModel> impl;
};
// The `TfLiteOpResolver` struct is an abstract callback interface that
// contains function pointers for callbacks that return a
// `TfLiteRegistration` given an op code or custom op name. This mechanism is
// used to map ops referenced in the flatbuffer model to executable function
// pointers (`TfLiteRegistration`s).
// This struct mirrors the tflite::OpResolver C++ abstract base class.
struct TfLiteOpResolverCallbacks {
// Opaque data that gets passed down to the callback functions.
void* user_data = nullptr;
// Callback that finds the op registration for a builtin operator by enum
// code. The `user_data` parameter will be set to the
// `op_resolver_user_data` value that was passed to
// `TfLiteInterpreterOptionsSetOpResolver`.
std::function<const TfLiteRegistration*(
void* user_data, TfLiteBuiltinOperator op, int version)>
find_builtin_op;
// Callback that finds the op registration of a custom operator by op name.
// The `user_data` parameter will be set to the `op_resolver_user_data` value
// that was passed to `TfLiteInterpreterOptionsSetOpResolver`.
std::function<const TfLiteRegistration*(void* user_data, const char* op,
int version)>
find_custom_op;
// Variant of `find_builtin_op` which returns `TfLiteRegistration_V3`.
std::function<const TfLiteRegistration_V3*(
void* user_data, TfLiteBuiltinOperator op, int version)>
find_builtin_op_v3;
// Variant of `find_custom_op` which returns `TfLiteRegistration_V3`.
std::function<const TfLiteRegistration_V3*(void* user_data, const char* op,
int version)>
find_custom_op_v3;
// Variant of `find_builtin_op` which returns `TfLiteRegistration_V2`.
std::function<const TfLiteRegistration_V2*(
void* user_data, TfLiteBuiltinOperator op, int version)>
find_builtin_op_v2;
// Variant of `find_custom_op` which returns `TfLiteRegistration_V2`.
std::function<const TfLiteRegistration_V2*(void* user_data, const char* op,
int version)>
find_custom_op_v2;
// Varant of `find_builtin_op` which returns `TfLiteRegistration_V1`.
std::function<const TfLiteRegistration_V1*(
void* user_data, TfLiteBuiltinOperator op, int version)>
find_builtin_op_v1;
// Varant of `find_custom_op` which returns `TfLiteRegistration_V1`.
std::function<const TfLiteRegistration_V1*(void* user_data, const char* op,
int version)>
find_custom_op_v1;
// Variant of `find_builtin_op` which returns `TfLiteOperator`.
std::function<const TfLiteOperator*(void* user_data, TfLiteBuiltinOperator op,
int version)>
find_builtin_op_external;
// Variant of `find_custom_op` which returns `TfLiteOperator`.
std::function<const TfLiteOperator*(void* user_data, const char* op,
int version)>
find_custom_op_external;
};
// This struct mirrors the tflite::ErrorResolver C++ abstract base class.
struct TfLiteErrorReporterCallback {
// Opaque data that gets passed down to the callback function.
void* user_data = nullptr;
// Callback function that reports an error.
void (*error_reporter)(void* user_data, const char* format,
va_list args) = nullptr;
};
struct TfLiteInterpreterOptions {
enum {
kDefaultNumThreads = -1,
};
int num_threads = kDefaultNumThreads;
tflite::MutableOpResolver mutable_op_resolver;
TfLiteOpResolverCallbacks op_resolver_callbacks = {};
std::vector<TfLiteDelegate*> delegates;
TfLiteErrorReporterCallback error_reporter_callback;
bool use_nnapi = false;
// Determines whether to allow automatic fallback to CPU.
// If true, and if one or more delegates were set,
// then if Invoke with delegates fails, it will be
// automatically retried without delegates.
bool enable_delegate_fallback = false;
// TfLiteOperator objects owned by caller of
// `TfLiteInterpreterOptionsAddOperator` API.
std::vector<TfLiteOperator*> op_registrations;
// Determines whether to allow to cancel invocations with
// `Interpreter::Cancel` or `SignatureRunner::Cancel`.
bool enable_cancellation = false;
// If not nullptr, report telemetry metrics to profiler.
TfLiteTelemetryProfilerStruct* telemetry_profiler = nullptr;
};
struct TfLiteInterpreter {
// Taking a reference to the (const) model data avoids lifetime-related issues
// and complexity with the TfLiteModel's existence.
std::shared_ptr<const tflite::impl::FlatBufferModel> model;
// The interpreter does not take ownership of the provided ErrorReporter
// instance, so we ensure its validity here. Note that the interpreter may use
// the reporter in its destructor, so the reporter should be declared first.
std::unique_ptr<tflite::ErrorReporter> optional_error_reporter;
std::unique_ptr<tflite::Interpreter> impl;
bool enable_delegate_fallback;
};
struct TfLiteSignatureRunner {
// The tflite::SignatureRunner runner object that this points to is owned by
// the interpreter. So this pointer will become invalid when the interpreter
// is destroyed.
tflite::SignatureRunner* impl;
};
namespace tflite {
namespace internal {
/// `CallbackOpResolver` is a (C++) `tflite::OpResolver` that forwards the
/// methods to (C ABI) callback functions from a `TfLiteOpResolverCallbacks`
/// struct.
///
/// The SetCallbacks method must be called before calling any of the FindOp
/// methods.
class CallbackOpResolver : public ::tflite::OpResolver {
public:
CallbackOpResolver() = default;
void SetCallbacks(
const struct TfLiteOpResolverCallbacks& op_resolver_callbacks) {
op_resolver_callbacks_ = op_resolver_callbacks;
}
const TfLiteRegistration* FindOp(tflite::BuiltinOperator op,
int version) const override;
const TfLiteRegistration* FindOp(const char* op, int version) const override;
private:
CallbackOpResolver(const CallbackOpResolver&) = delete;
CallbackOpResolver& operator=(const CallbackOpResolver&) = delete;
// Builds a builtin op TfLiteRegistration from a legacy registration
// (e.g. TfLiteRegistration_V1).
// The legacy registration type must be a POD struct type whose field types
// must be a prefix of the field types in TfLiteRegistration, and offset of
// the first field in TfLiteRegistration that is not present in the legacy
// registration type must be greater than or equal to the size of the legacy
// registration type.
// `legacy_find_builtin_op` is a callback that finds the
// legacy registration for a builtin operator by enum code. The caller owns
// the returned registration.
template <class LegacyRegistrationT>
TfLiteRegistration* BuildBuiltinOpFromLegacyRegistration(
tflite::BuiltinOperator op, int version,
std::function<const LegacyRegistrationT*(
void* user_data, TfLiteBuiltinOperator op, int version)>
legacy_find_builtin_op) const {
if (legacy_find_builtin_op) {
// Get a deprecated Registration object to create a Registration.
const LegacyRegistrationT* legacy_registration = legacy_find_builtin_op(
op_resolver_callbacks_.user_data,
static_cast<TfLiteBuiltinOperator>(op), version);
if (legacy_registration) {
TfLiteRegistration* new_registration = new TfLiteRegistration();
memcpy(new_registration, legacy_registration,
sizeof(LegacyRegistrationT));
new_registration->registration_external = nullptr;
temporary_builtin_registrations_.push_back(
std::unique_ptr<TfLiteRegistration>(new_registration));
return new_registration;
}
}
return nullptr;
}
// Builds a custom op TfLiteRegistration from a legacy registration
// (e.g. TfLiteRegistration_V1).
// The legacy registration type must be a POD struct type whose field types
// must be a prefix of the field types in TfLiteRegistration, and offset of
// the first field in TfLiteRegistration that is not present in the legacy
// registration type must be greater than or equal to the size of the legacy
// registration type.
// `legacy_find_custom_op` is a callback that finds the legacy registration
// for a builtin operator by op name.
// The caller owns the returned registration.
template <class LegacyRegistrationT>
TfLiteRegistration* BuildCustomOpFromLegacyRegistration(
const char* op, int version,
std::function<const LegacyRegistrationT*(void* user_data, const char* op,
int version)>
legacy_find_custom_op) const {
if (legacy_find_custom_op) {
// Get a deprecated Registration object to create a Registration.
const LegacyRegistrationT* legacy_registration =
legacy_find_custom_op(op_resolver_callbacks_.user_data, op, version);
if (legacy_registration) {
TfLiteRegistration* new_registration = new TfLiteRegistration();
memcpy(new_registration, legacy_registration,
sizeof(LegacyRegistrationT));
new_registration->registration_external = nullptr;
temporary_custom_registrations_.push_back(
std::unique_ptr<TfLiteRegistration>(new_registration));
return new_registration;
}
}
return nullptr;
}
struct TfLiteOpResolverCallbacks op_resolver_callbacks_ = {};
// mutable objects to store temporary `TfLiteRegistration`.
mutable std::mutex mutex_;
mutable std::vector<std::unique_ptr<TfLiteRegistration>>
temporary_builtin_registrations_; // GUARDED_BY(mutex_)
mutable std::vector<std::unique_ptr<TfLiteRegistration>>
temporary_custom_registrations_; // GUARDED_BY(mutex_)
};
// This adds the builtin and/or custom operators specified in options in
// `optional_options` (if any) to `mutable_resolver`, and then returns a newly
// created TfLiteInterpreter using `mutable_op_resolver` as the default
// OpResolver, and using any other options in `optional_options`, and using
// the provided `model`.
//
// * `model` must be a valid model instance. The caller retains ownership of the
// object, and can destroy it immediately after creating the interpreter; the
// interpreter will maintain its own reference to the underlying model data.
// * `optional_options` may be null. The caller retains ownership of the object,
// and can safely destroy it immediately after creating the interpreter.
// * `mutable_resolver` must not be null. The caller retains ownership of the
// MutableOpResolver object, and can safely destroy it immediately after
// creating the interpreter.
//
// NOTE: The client *must* explicitly allocate tensors before attempting to
// access input tensor data or invoke the interpreter.
TfLiteInterpreter* InterpreterCreateWithOpResolver(
const TfLiteModel* model, const TfLiteInterpreterOptions* optional_options,
tflite::MutableOpResolver* mutable_resolver);
} // namespace internal
} // namespace tflite
#endif // TENSORFLOW_LITE_C_C_API_INTERNAL_H_
+23
View File
@@ -0,0 +1,23 @@
/* 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_C_C_API_OPAQUE_H_
#define TENSORFLOW_LITE_C_C_API_OPAQUE_H_
/// For documentation, see
/// third_party/tensorflow/lite/core/c/c_api_opaque.h
#include "tensorflow/lite/core/c/c_api_opaque.h"
#endif // TENSORFLOW_LITE_C_C_API_OPAQUE_H_
@@ -0,0 +1,78 @@
/* Copyright 2022 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/c/c_api_opaque_internal.h"
#include <memory>
#include <unordered_map>
#include <utility>
#include "tensorflow/lite/core/api/op_resolver.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/core/c/operator.h"
#include "tensorflow/lite/core/subgraph.h"
namespace tflite {
namespace internal {
namespace {
// Returns a dynamically allocated object; the caller is responsible for
// deallocating it using TfLiteOperatorDelete.
TfLiteOperator* MakeOperator(const TfLiteRegistration* registration,
int node_index) {
// We need to allocate a new TfLiteOperator object and then
// populate its state correctly, based on the contents in 'registration'.
auto* registration_external = TfLiteOperatorCreate(
static_cast<TfLiteBuiltinOperator>(registration->builtin_code),
registration->custom_name, registration->version,
/*user_data=*/nullptr);
registration_external->node_index = node_index;
return registration_external;
}
} // anonymous namespace
TfLiteOperator* CommonOpaqueConversionUtil::CachedObtainOperator(
OperatorsCache* registration_externals_cache,
const TfLiteRegistration* registration, int node_index) {
OpResolver::OpId op_id{registration->builtin_code, registration->custom_name,
registration->version};
auto it = registration_externals_cache->find(op_id);
if (it != registration_externals_cache->end()) {
return it->second.get();
}
auto* registration_external = MakeOperator(registration, node_index);
registration_externals_cache->insert(
it, std::make_pair(op_id, registration_external));
return registration_external;
}
TfLiteOperator* CommonOpaqueConversionUtil::ObtainOperator(
TfLiteContext* context, const TfLiteRegistration* registration,
int node_index) {
auto* subgraph = static_cast<tflite::Subgraph*>(context->impl_);
if (!subgraph->registration_externals_) {
subgraph->registration_externals_ = std::make_shared<OperatorsCache>();
}
return CachedObtainOperator(subgraph->registration_externals_.get(),
registration, node_index);
}
} // namespace internal
} // namespace tflite
+64
View File
@@ -0,0 +1,64 @@
/* Copyright 2022 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_C_C_API_OPAQUE_INTERNAL_H_
#define TENSORFLOW_LITE_C_C_API_OPAQUE_INTERNAL_H_
#include "tensorflow/lite/core/api/op_resolver.h"
#include "tensorflow/lite/core/c/common.h"
// Internal structures and subroutines used by the C API. These are likely to
// change and should not be depended on directly by any C API clients.
//
// NOTE: This header does not follow C conventions and does not define a C API.
// It is effectively an (internal) implementation detail of the C API.
namespace tflite {
namespace internal {
class CommonOpaqueConversionUtil {
public:
CommonOpaqueConversionUtil() = delete;
// Obtain (or create) a 'TfLiteOperator' object that corresponds
// to the provided 'registration' argument, and return the address of the
// external registration. We loosely define that a
// 'TfLiteOperator' object "corresponds" to a 'TfLiteRegistration'
// object when calling any function pointer (like 'prepare') on the
// 'TfLiteOperator' object calls into the corresponding function
// pointer of the 'TfLiteRegistration' object.
//
// The specified 'context' or 'op_resolver' object is used to store the
// 'TfLiteOperator*' pointers. The 'TfLiteOperator*'
// pointer will be deallocated when that object gets destroyed. I.e., the
// caller of this function should not deallocate the object pointed to by the
// return value of 'ObtainOperator'.
//
// We also need to provide the 'node_index' that the 'registration'
// corresponds to, so that the 'TfLiteOperator' can store that
// index within its fields. If the registration does not yet correspond
// to a specific node index, then 'node_index' should be -1.
static TfLiteOperator* ObtainOperator(TfLiteContext* context,
const TfLiteRegistration* registration,
int node_index);
private:
static TfLiteOperator* CachedObtainOperator(
::tflite::internal::OperatorsCache* registration_externals_cache,
const TfLiteRegistration* registration, int node_index);
};
} // namespace internal
} // namespace tflite
#endif // TENSORFLOW_LITE_C_C_API_OPAQUE_INTERNAL_H_
@@ -0,0 +1,73 @@
/* Copyright 2022 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/c/c_api_opaque_internal.h"
#include <memory>
#include <gtest/gtest.h>
#include "tensorflow/lite/builtin_ops.h"
#include "tensorflow/lite/core/subgraph.h"
#include "tensorflow/lite/interpreter.h"
#include "tensorflow/lite/interpreter_builder.h"
#include "tensorflow/lite/kernels/builtin_op_kernels.h"
#include "tensorflow/lite/kernels/register.h"
#include "tensorflow/lite/model_builder.h"
using tflite::FlatBufferModel;
using tflite::Interpreter;
using tflite::InterpreterBuilder;
using tflite::internal::CommonOpaqueConversionUtil;
using tflite::ops::builtin::BuiltinOpResolver;
TEST(ObtainRegistrationFromContext, ProducesValidResult) {
BuiltinOpResolver op_resolver;
std::unique_ptr<Interpreter> interpreter;
std::unique_ptr<FlatBufferModel> model = FlatBufferModel::BuildFromFile(
"tensorflow/lite/testdata/add.bin");
ASSERT_NE(model, nullptr);
InterpreterBuilder builder(*model, op_resolver);
ASSERT_EQ(builder(&interpreter), kTfLiteOk);
ASSERT_NE(interpreter, nullptr);
TfLiteContext* context = interpreter->primary_subgraph().context();
const TfLiteRegistration* registration = tflite::ops::builtin::Register_ADD();
TfLiteOperator* registration_external =
CommonOpaqueConversionUtil::ObtainOperator(context, registration, 42);
ASSERT_EQ(registration_external->builtin_code, kTfLiteBuiltinAdd);
ASSERT_EQ(registration_external->version, registration->version);
ASSERT_EQ(registration_external->custom_name, registration->custom_name);
ASSERT_EQ(registration_external->node_index, 42);
}
TEST(ObtainRegistrationFromContext, CachingWorks) {
BuiltinOpResolver op_resolver;
std::unique_ptr<Interpreter> interpreter;
std::unique_ptr<FlatBufferModel> model = FlatBufferModel::BuildFromFile(
"tensorflow/lite/testdata/add.bin");
ASSERT_NE(model, nullptr);
InterpreterBuilder builder(*model, op_resolver);
ASSERT_EQ(builder(&interpreter), kTfLiteOk);
ASSERT_NE(interpreter, nullptr);
TfLiteContext* context = interpreter->primary_subgraph().context();
const TfLiteRegistration* registration = tflite::ops::builtin::Register_ADD();
// Call it twice, and verify that we get the same result back.
TfLiteOperator* registration_external1 =
CommonOpaqueConversionUtil::ObtainOperator(context, registration, 0);
TfLiteOperator* registration_external2 =
CommonOpaqueConversionUtil::ObtainOperator(context, registration, 1);
ASSERT_EQ(registration_external1, registration_external2);
}
@@ -0,0 +1,229 @@
/* Copyright 2022 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 <array>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "tensorflow/lite/core/c/c_api.h"
#include "tensorflow/lite/core/c/common.h"
namespace tflite {
namespace {
TEST(SignatureRunnerTest, TestNoSignatures) {
TfLiteModel* model = TfLiteModelCreateFromFile(
"tensorflow/lite/testdata/no_signatures.bin");
ASSERT_NE(model, nullptr);
TfLiteInterpreter* interpreter =
TfLiteInterpreterCreate(model, /*optional_options=*/nullptr);
ASSERT_NE(interpreter, nullptr);
int nun_signatures = TfLiteInterpreterGetSignatureCount(interpreter);
ASSERT_EQ(nun_signatures, 0);
ASSERT_EQ(TfLiteInterpreterGetSignatureRunner(interpreter, "foo"), nullptr);
TfLiteSignatureRunner* runner =
TfLiteInterpreterGetSignatureRunner(interpreter, nullptr);
ASSERT_NE(runner, nullptr);
int num_interpreter_inputs =
TfLiteInterpreterGetInputTensorCount(interpreter);
int num_runner_inputs = TfLiteSignatureRunnerGetInputCount(runner);
ASSERT_EQ(num_runner_inputs, num_interpreter_inputs);
for (int i = 0; i < num_interpreter_inputs; ++i) {
auto* interpreter_input_tensor =
TfLiteInterpreterGetInputTensor(interpreter, i);
ASSERT_NE(interpreter_input_tensor, nullptr);
auto* interpreter_input_name = TfLiteTensorName(interpreter_input_tensor);
ASSERT_NE(interpreter_input_name, nullptr);
auto* runner_input_name = TfLiteSignatureRunnerGetInputName(runner, i);
ASSERT_NE(runner_input_name, nullptr);
EXPECT_STREQ(runner_input_name, interpreter_input_name);
auto* runner_input_tensor =
TfLiteSignatureRunnerGetInputTensor(runner, interpreter_input_name);
ASSERT_NE(runner_input_tensor, nullptr);
ASSERT_EQ(runner_input_tensor, interpreter_input_tensor);
}
int num_interpreter_outputs =
TfLiteInterpreterGetOutputTensorCount(interpreter);
int num_runner_outputs = TfLiteSignatureRunnerGetOutputCount(runner);
ASSERT_EQ(num_runner_outputs, num_interpreter_outputs);
for (int i = 0; i < num_interpreter_outputs; ++i) {
auto* interpreter_output_tensor =
TfLiteInterpreterGetOutputTensor(interpreter, i);
ASSERT_NE(interpreter_output_tensor, nullptr);
auto* interpreter_output_name = TfLiteTensorName(interpreter_output_tensor);
ASSERT_NE(interpreter_output_name, nullptr);
auto* runner_output_name = TfLiteSignatureRunnerGetOutputName(runner, i);
ASSERT_NE(runner_output_name, nullptr);
EXPECT_STREQ(runner_output_name, interpreter_output_name);
auto* runner_output_tensor =
TfLiteSignatureRunnerGetOutputTensor(runner, interpreter_output_name);
ASSERT_NE(runner_output_tensor, nullptr);
ASSERT_EQ(runner_output_tensor, interpreter_output_tensor);
}
std::array<int, 1> input_dims{2};
ASSERT_EQ(TfLiteSignatureRunnerResizeInputTensor(
runner, "x1", input_dims.data(), input_dims.size()),
kTfLiteOk);
ASSERT_EQ(TfLiteSignatureRunnerResizeInputTensor(
runner, "x2", input_dims.data(), input_dims.size()),
kTfLiteOk);
ASSERT_EQ(TfLiteSignatureRunnerAllocateTensors(runner), kTfLiteOk);
TfLiteTensor* input1 = TfLiteSignatureRunnerGetInputTensor(runner, "x1");
ASSERT_NE(input1, nullptr);
TfLiteTensor* input2 = TfLiteSignatureRunnerGetInputTensor(runner, "x2");
ASSERT_NE(input2, nullptr);
ASSERT_EQ(TfLiteSignatureRunnerGetInputTensor(runner, "foo"), nullptr);
const TfLiteTensor* output =
TfLiteSignatureRunnerGetOutputTensor(runner, "Identity");
ASSERT_NE(output, nullptr);
ASSERT_EQ(TfLiteSignatureRunnerGetOutputTensor(runner, "foo"), nullptr);
input1->data.f[0] = -8;
input1->data.f[1] = 0.5;
input2->data.f[0] = -1;
input2->data.f[1] = 1.5;
ASSERT_EQ(TfLiteSignatureRunnerInvoke(runner), kTfLiteOk);
ASSERT_EQ(output->data.f[0], 0);
ASSERT_EQ(output->data.f[1], 2);
TfLiteSignatureRunnerDelete(runner);
TfLiteInterpreterDelete(interpreter);
TfLiteModelDelete(model);
}
TEST(SignatureRunnerTest, TestMultiSignatures) {
TfLiteModel* model = TfLiteModelCreateFromFile(
"tensorflow/lite/testdata/multi_signatures.bin");
ASSERT_NE(model, nullptr);
TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
ASSERT_NE(options, nullptr);
TfLiteInterpreterOptionsSetNumThreads(options, 2);
TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
ASSERT_NE(interpreter, nullptr);
// The options can be deleted immediately after interpreter creation.
TfLiteInterpreterOptionsDelete(options);
std::vector<std::string> signature_defs;
for (int i = 0; i < TfLiteInterpreterGetSignatureCount(interpreter); i++) {
signature_defs.push_back(TfLiteInterpreterGetSignatureKey(interpreter, i));
}
ASSERT_EQ(signature_defs.size(), 2);
ASSERT_EQ(signature_defs[0], "add");
ASSERT_EQ(signature_defs[1], "sub");
ASSERT_EQ(TfLiteInterpreterGetSignatureRunner(interpreter, "foo"), nullptr);
// Test out-of-range values.
ASSERT_EQ(TfLiteInterpreterGetSignatureKey(interpreter, 2), nullptr);
ASSERT_EQ(TfLiteInterpreterGetSignatureKey(interpreter, -1), nullptr);
TfLiteSignatureRunner* add_runner = TfLiteInterpreterGetSignatureRunner(
interpreter, signature_defs[0].c_str());
ASSERT_NE(add_runner, nullptr);
std::vector<const char*> input_names;
for (int i = 0; i < TfLiteSignatureRunnerGetInputCount(add_runner); i++) {
input_names.push_back(TfLiteSignatureRunnerGetInputName(add_runner, i));
}
std::vector<const char*> output_names;
for (int i = 0; i < TfLiteSignatureRunnerGetOutputCount(add_runner); i++) {
output_names.push_back(TfLiteSignatureRunnerGetOutputName(add_runner, i));
}
ASSERT_EQ(input_names.size(), 1);
ASSERT_EQ(std::string(input_names[0]), "x");
ASSERT_EQ(output_names.size(), 1);
ASSERT_EQ(std::string(output_names[0]), "output_0");
std::array<int, 1> add_runner_input_dims{2};
ASSERT_EQ(TfLiteSignatureRunnerResizeInputTensor(
add_runner, "x", add_runner_input_dims.data(),
add_runner_input_dims.size()),
kTfLiteOk);
ASSERT_EQ(TfLiteSignatureRunnerAllocateTensors(add_runner), kTfLiteOk);
TfLiteTensor* add_input =
TfLiteSignatureRunnerGetInputTensor(add_runner, "x");
ASSERT_EQ(TfLiteSignatureRunnerGetInputTensor(add_runner, "foo"), nullptr);
const TfLiteTensor* add_output =
TfLiteSignatureRunnerGetOutputTensor(add_runner, "output_0");
ASSERT_EQ(TfLiteSignatureRunnerGetOutputTensor(add_runner, "foo"), nullptr);
ASSERT_NE(add_input, nullptr);
ASSERT_NE(add_output, nullptr);
add_input->data.f[0] = 2;
add_input->data.f[1] = 4;
ASSERT_EQ(TfLiteSignatureRunnerInvoke(add_runner), kTfLiteOk);
ASSERT_EQ(add_output->data.f[0], 4);
ASSERT_EQ(add_output->data.f[1], 6);
// Test out-of-range values.
ASSERT_EQ(TfLiteSignatureRunnerGetInputName(add_runner, 1), nullptr);
ASSERT_EQ(TfLiteSignatureRunnerGetInputName(add_runner, -1), nullptr);
ASSERT_EQ(TfLiteSignatureRunnerGetOutputName(add_runner, 1), nullptr);
ASSERT_EQ(TfLiteSignatureRunnerGetOutputName(add_runner, -1), nullptr);
TfLiteSignatureRunnerDelete(add_runner);
TfLiteSignatureRunner* sub_runner =
TfLiteInterpreterGetSignatureRunner(interpreter, "sub");
ASSERT_NE(sub_runner, nullptr);
std::vector<const char*> input_names2;
for (int i = 0; i < TfLiteSignatureRunnerGetInputCount(sub_runner); i++) {
input_names2.push_back(TfLiteSignatureRunnerGetInputName(sub_runner, i));
}
std::vector<const char*> output_names2;
for (int i = 0; i < TfLiteSignatureRunnerGetOutputCount(sub_runner); i++) {
output_names2.push_back(TfLiteSignatureRunnerGetOutputName(sub_runner, i));
}
ASSERT_EQ(input_names2.size(), 1);
ASSERT_EQ(std::string(input_names2[0]), "x");
ASSERT_EQ(output_names2.size(), 1);
ASSERT_EQ(std::string(output_names2[0]), "output_0");
std::array<int, 1> sub_runner_input_dims{3};
ASSERT_EQ(TfLiteSignatureRunnerResizeInputTensor(
sub_runner, "x", sub_runner_input_dims.data(),
sub_runner_input_dims.size()),
kTfLiteOk);
ASSERT_EQ(TfLiteSignatureRunnerAllocateTensors(sub_runner), kTfLiteOk);
TfLiteTensor* sub_input =
TfLiteSignatureRunnerGetInputTensor(sub_runner, "x");
ASSERT_EQ(TfLiteSignatureRunnerGetInputTensor(sub_runner, "foo"), nullptr);
const TfLiteTensor* sub_output =
TfLiteSignatureRunnerGetOutputTensor(sub_runner, "output_0");
ASSERT_EQ(TfLiteSignatureRunnerGetOutputTensor(sub_runner, "foo"), nullptr);
ASSERT_NE(sub_input, nullptr);
ASSERT_NE(sub_output, nullptr);
sub_input->data.f[0] = 2;
sub_input->data.f[1] = 4;
sub_input->data.f[2] = 6;
ASSERT_EQ(TfLiteSignatureRunnerInvoke(sub_runner), kTfLiteOk);
ASSERT_EQ(sub_output->data.f[0], -1);
ASSERT_EQ(sub_output->data.f[1], 1);
ASSERT_EQ(sub_output->data.f[2], 3);
TfLiteSignatureRunnerDelete(sub_runner);
TfLiteInterpreterDelete(interpreter);
TfLiteModelDelete(model);
}
} // namespace
} // namespace tflite
+26
View File
@@ -0,0 +1,26 @@
/* Copyright 2022 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_C_C_API_TYPES_H_
#define TENSORFLOW_LITE_C_C_API_TYPES_H_
/// \file
///
/// C API types for TensorFlow Lite.
///
/// For documentation, see tensorflow/lite/core/c/c_api_types.h
#include "tensorflow/lite/core/c/c_api_types.h"
#endif // TENSORFLOW_LITE_C_C_API_TYPES_H_
+441
View File
@@ -0,0 +1,441 @@
/* 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/core/c/builtin_op_data.h"
#include "tensorflow/lite/core/c/c_api.h"
#include "tensorflow/lite/core/c/c_api_experimental.h"
#include "tensorflow/lite/core/c/c_api_opaque.h"
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
// This file exists just to verify that the above header files above can build,
// link, and run as "C" code.
#ifdef __cplusplus
#error "This file should be compiled as C code, not as C++."
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
static void CheckFailed(const char *expression, const char *filename,
int line_number) {
fprintf(stderr, "ERROR: CHECK failed: %s:%d: %s\n", filename, line_number,
expression);
fflush(stderr);
abort();
}
// We use an extra level of macro indirection here to ensure that the
// macro arguments get evaluated, so that in a call to CHECK(foo),
// the call to STRINGIZE(condition) in the definition of the CHECK
// macro results in the string "foo" rather than the string "condition".
#define STRINGIZE(expression) STRINGIZE2(expression)
#define STRINGIZE2(expression) #expression
// Like assert(), but not dependent on NDEBUG.
#define CHECK(condition) \
((condition) ? (void)0 \
: CheckFailed(STRINGIZE(condition), __FILE__, __LINE__))
#define ASSERT_EQ(expected, actual) CHECK((expected) == (actual))
#define ASSERT_NE(expected, actual) CHECK((expected) != (actual))
#define ASSERT_STREQ(expected, actual) \
ASSERT_EQ(0, strcmp((expected), (actual)))
// Test the TfLiteVersion function.
static void TestVersion(void) {
const char *version = TfLiteVersion();
printf("Version = %s\n", version);
CHECK(version[0] != '\0');
}
static void TestInferenceUsingSignature(void) {
TfLiteModel* model = TfLiteModelCreateFromFile(
"tensorflow/lite/testdata/multi_signatures.bin");
ASSERT_NE(model, NULL);
TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
ASSERT_NE(options, NULL);
TfLiteInterpreterOptionsSetNumThreads(options, 2);
TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
ASSERT_NE(interpreter, NULL);
// The options can be deleted immediately after interpreter creation.
TfLiteInterpreterOptionsDelete(options);
// (optional) Validate signatures
ASSERT_EQ(TfLiteInterpreterGetSignatureCount(interpreter), 2);
ASSERT_STREQ(TfLiteInterpreterGetSignatureKey(interpreter, 0), "add");
ASSERT_STREQ(TfLiteInterpreterGetSignatureKey(interpreter, 1), "sub");
// Validate signature "add"
TfLiteSignatureRunner* add_runner =
TfLiteInterpreterGetSignatureRunner(interpreter, "add");
ASSERT_NE(add_runner, NULL);
ASSERT_EQ(TfLiteSignatureRunnerGetInputCount(add_runner), 1);
ASSERT_STREQ(TfLiteSignatureRunnerGetInputName(add_runner, 0), "x");
ASSERT_EQ(TfLiteSignatureRunnerGetOutputCount(add_runner), 1);
ASSERT_STREQ(TfLiteSignatureRunnerGetOutputName(add_runner, 0), "output_0");
// Resize signature "add" input tensor "x"
int input_dims[1] = {2};
ASSERT_EQ(
TfLiteSignatureRunnerResizeInputTensor(add_runner, "x", input_dims, 1),
kTfLiteOk);
// Allocate tensors for signature "add"
ASSERT_EQ(TfLiteSignatureRunnerAllocateTensors(add_runner), kTfLiteOk);
// Validate signature "add" input tensor "x"
TfLiteTensor* input_tensor =
TfLiteSignatureRunnerGetInputTensor(add_runner, "x");
ASSERT_NE(input_tensor, NULL);
ASSERT_EQ(TfLiteTensorType(input_tensor), kTfLiteFloat32);
ASSERT_EQ(TfLiteTensorNumDims(input_tensor), 1);
ASSERT_EQ(TfLiteTensorDim(input_tensor, 0), 2);
ASSERT_EQ(TfLiteTensorByteSize(input_tensor), sizeof(float) * 2);
ASSERT_NE(TfLiteTensorData(input_tensor), NULL);
TfLiteQuantizationParams input_params =
TfLiteTensorQuantizationParams(input_tensor);
ASSERT_EQ(input_params.scale, 0.f);
ASSERT_EQ(input_params.zero_point, 0);
float input[2] = {2.f, 4.f};
ASSERT_EQ(TfLiteTensorCopyFromBuffer(input_tensor, input, 2 * sizeof(float)),
kTfLiteOk);
ASSERT_EQ(TfLiteSignatureRunnerInvoke(add_runner), kTfLiteOk);
const TfLiteTensor* output_tensor =
TfLiteSignatureRunnerGetOutputTensor(add_runner, "output_0");
ASSERT_NE(output_tensor, NULL);
ASSERT_EQ(TfLiteTensorType(output_tensor), kTfLiteFloat32);
ASSERT_EQ(TfLiteTensorNumDims(output_tensor), 1);
ASSERT_EQ(TfLiteTensorDim(output_tensor, 0), 2);
ASSERT_EQ(TfLiteTensorByteSize(output_tensor), sizeof(float) * 2);
ASSERT_NE(TfLiteTensorData(output_tensor), NULL);
TfLiteQuantizationParams output_params =
TfLiteTensorQuantizationParams(output_tensor);
ASSERT_EQ(output_params.scale, 0.f);
ASSERT_EQ(output_params.zero_point, 0);
float output[2];
ASSERT_EQ(TfLiteTensorCopyToBuffer(output_tensor, output, 2 * sizeof(float)),
kTfLiteOk);
// Verify the result
ASSERT_EQ(output[0], input[0] + 2.f);
ASSERT_EQ(output[1], input[1] + 2.f);
// The signature runner should be deleted before interpreter deletion.
TfLiteSignatureRunnerDelete(add_runner);
TfLiteInterpreterDelete(interpreter);
// The model should only be deleted after destroying the interpreter.
TfLiteModelDelete(model);
}
// This test checks if resizing the input (decreasing or increasing it's size)
// would invalidate input/output tensors.
static void TestRepeatResizeInputTensor(void) {
TfLiteModel* model = TfLiteModelCreateFromFile(
"tensorflow/lite/testdata/multi_signatures.bin");
ASSERT_NE(model, NULL);
TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
ASSERT_NE(options, NULL);
TfLiteInterpreterOptionsSetNumThreads(options, 2);
TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
ASSERT_NE(interpreter, NULL);
TfLiteInterpreterOptionsDelete(options);
ASSERT_EQ(TfLiteInterpreterGetSignatureCount(interpreter), 2);
ASSERT_STREQ(TfLiteInterpreterGetSignatureKey(interpreter, 0), "add");
ASSERT_STREQ(TfLiteInterpreterGetSignatureKey(interpreter, 1), "sub");
TfLiteSignatureRunner* add_runner =
TfLiteInterpreterGetSignatureRunner(interpreter, "add");
ASSERT_NE(add_runner, NULL);
ASSERT_EQ(TfLiteSignatureRunnerGetInputCount(add_runner), 1);
ASSERT_STREQ(TfLiteSignatureRunnerGetInputName(add_runner, 0), "x");
ASSERT_EQ(TfLiteSignatureRunnerGetOutputCount(add_runner), 1);
ASSERT_STREQ(TfLiteSignatureRunnerGetOutputName(add_runner, 0), "output_0");
TfLiteTensor* input_tensor =
TfLiteSignatureRunnerGetInputTensor(add_runner, "x");
const TfLiteTensor* output_tensor =
TfLiteSignatureRunnerGetOutputTensor(add_runner, "output_0");
// For different input sizes, resize the input/output tensors and check if
// inferences runs as expected.
int sizes[] = {3, 1, 5};
float inputs_1[] = {3.f, 6.f, 11.f};
float inputs_2[] = {4.f};
float inputs_3[] = {5.f, 8.f, 11.f, 12.f, 20.f};
float* all_inputs[] = {inputs_1, inputs_2, inputs_3};
float actual_outputs1[] = {0.f, 0.f, 0.f};
float actual_outputs2[] = {0.f};
float actual_outputs3[] = {0.f, 0.f, 0.f, 0.f, 0.f};
float* all_actual_outputs[] = {actual_outputs1, actual_outputs2,
actual_outputs3};
for (int i = 0; i < 3; i++) {
int input_dims[] = {sizes[i]};
float* inputs = all_inputs[i];
ASSERT_EQ(
TfLiteSignatureRunnerResizeInputTensor(add_runner, "x", input_dims, 1),
kTfLiteOk);
ASSERT_EQ(TfLiteSignatureRunnerAllocateTensors(add_runner), kTfLiteOk);
ASSERT_NE(input_tensor, NULL);
ASSERT_EQ(TfLiteTensorType(input_tensor), kTfLiteFloat32);
ASSERT_EQ(TfLiteTensorNumDims(input_tensor), 1);
ASSERT_EQ(TfLiteTensorDim(input_tensor, 0), sizes[i]);
ASSERT_EQ(TfLiteTensorByteSize(input_tensor), sizes[i] * sizeof(float));
ASSERT_NE(TfLiteTensorData(input_tensor), NULL);
ASSERT_EQ(TfLiteTensorCopyFromBuffer(input_tensor, inputs,
sizes[i] * sizeof(float)),
kTfLiteOk);
ASSERT_EQ(TfLiteSignatureRunnerInvoke(add_runner), kTfLiteOk);
ASSERT_NE(output_tensor, NULL);
ASSERT_EQ(TfLiteTensorType(output_tensor), kTfLiteFloat32);
ASSERT_EQ(TfLiteTensorNumDims(output_tensor), 1);
ASSERT_EQ(TfLiteTensorDim(output_tensor, 0), sizes[i]);
ASSERT_EQ(TfLiteTensorByteSize(output_tensor), sizes[i] * sizeof(float));
ASSERT_NE(TfLiteTensorData(output_tensor), NULL);
float* actual_outputs = all_actual_outputs[i];
ASSERT_EQ(TfLiteTensorCopyToBuffer(output_tensor, actual_outputs,
sizes[i] * sizeof(float)),
kTfLiteOk);
for (int j = 0; j < sizes[i]; j++) {
ASSERT_EQ(actual_outputs[j], inputs[j] + 2);
}
}
TfLiteSignatureRunnerDelete(add_runner);
TfLiteInterpreterDelete(interpreter);
TfLiteModelDelete(model);
}
static void TestInferenceUsingInterpreter(void) {
TfLiteModel* model =
TfLiteModelCreateFromFile("tensorflow/lite/testdata/add.bin");
ASSERT_NE(model, NULL);
TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
ASSERT_NE(options, NULL);
TfLiteInterpreterOptionsSetNumThreads(options, 2);
TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
ASSERT_NE(interpreter, NULL);
// The options can be deleted immediately after interpreter creation.
TfLiteInterpreterOptionsDelete(options);
ASSERT_EQ(TfLiteInterpreterAllocateTensors(interpreter), kTfLiteOk);
ASSERT_EQ(TfLiteInterpreterGetInputTensorCount(interpreter), 1);
ASSERT_EQ(TfLiteInterpreterGetOutputTensorCount(interpreter), 1);
int input_dims[1] = {2};
ASSERT_EQ(TfLiteInterpreterResizeInputTensor(interpreter, 0, input_dims, 1),
kTfLiteOk);
ASSERT_EQ(TfLiteInterpreterAllocateTensors(interpreter), kTfLiteOk);
TfLiteTensor* input_tensor = TfLiteInterpreterGetInputTensor(interpreter, 0);
ASSERT_NE(input_tensor, NULL);
ASSERT_EQ(TfLiteTensorType(input_tensor), kTfLiteFloat32);
ASSERT_EQ(TfLiteTensorNumDims(input_tensor), 1);
ASSERT_EQ(TfLiteTensorDim(input_tensor, 0), 2);
ASSERT_EQ(TfLiteTensorByteSize(input_tensor), sizeof(float) * 2);
ASSERT_NE(TfLiteTensorData(input_tensor), NULL);
ASSERT_STREQ(TfLiteTensorName(input_tensor), "input");
TfLiteQuantizationParams input_params =
TfLiteTensorQuantizationParams(input_tensor);
ASSERT_EQ(input_params.scale, 0.f);
ASSERT_EQ(input_params.zero_point, 0);
float input[2] = {1.f, 3.f};
ASSERT_EQ(TfLiteTensorCopyFromBuffer(input_tensor, input, 2 * sizeof(float)),
kTfLiteOk);
ASSERT_EQ(TfLiteInterpreterInvoke(interpreter), kTfLiteOk);
const TfLiteTensor* output_tensor =
TfLiteInterpreterGetOutputTensor(interpreter, 0);
ASSERT_NE(output_tensor, NULL);
ASSERT_EQ(TfLiteTensorType(output_tensor), kTfLiteFloat32);
ASSERT_EQ(TfLiteTensorNumDims(output_tensor), 1);
ASSERT_EQ(TfLiteTensorDim(output_tensor, 0), 2);
ASSERT_EQ(TfLiteTensorByteSize(output_tensor), sizeof(float) * 2);
ASSERT_NE(TfLiteTensorData(output_tensor), NULL);
ASSERT_STREQ(TfLiteTensorName(output_tensor), "output");
TfLiteQuantizationParams output_params =
TfLiteTensorQuantizationParams(output_tensor);
ASSERT_EQ(output_params.scale, 0.f);
ASSERT_EQ(output_params.zero_point, 0);
float output[2];
ASSERT_EQ(TfLiteTensorCopyToBuffer(output_tensor, output, 2 * sizeof(float)),
kTfLiteOk);
ASSERT_EQ(output[0], 3.f);
ASSERT_EQ(output[1], 9.f);
TfLiteInterpreterDelete(interpreter);
// The model should only be deleted after destroying the interpreter.
TfLiteModelDelete(model);
}
TfLiteStatus PrepareThatChecksExecutionPlanSizeEqualsTwo(
TfLiteOpaqueContext* context,
TfLiteOpaqueDelegate* opaque_delegate, void* data) {
bool* delegate_prepared = (bool*)data;
*delegate_prepared = true;
TfLiteIntArray* execution_plan;
ASSERT_EQ(kTfLiteOk,
TfLiteOpaqueContextGetExecutionPlan(context, &execution_plan));
ASSERT_EQ(2, execution_plan->size);
return kTfLiteOk;
}
static void TestTfLiteOpaqueContextGetExecutionPlan(void) {
TfLiteModel* model =
TfLiteModelCreateFromFile("tensorflow/lite/testdata/add.bin");
// Create and install a delegate instance.
bool delegate_prepared = false;
TfLiteOpaqueDelegateBuilder opaque_delegate_builder = { NULL };
opaque_delegate_builder.data = &delegate_prepared;
opaque_delegate_builder.Prepare = PrepareThatChecksExecutionPlanSizeEqualsTwo;
TfLiteOpaqueDelegate* opaque_delegate =
TfLiteOpaqueDelegateCreate(&opaque_delegate_builder);
TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
TfLiteInterpreterOptionsAddDelegate(options, opaque_delegate);
TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
// The delegate should have been applied.
CHECK(delegate_prepared);
TfLiteInterpreterOptionsDelete(options);
TfLiteInterpreterDelete(interpreter);
TfLiteModelDelete(model);
TfLiteOpaqueDelegateDelete(opaque_delegate);
}
static void TestTfLiteOpaqueContextReportErrorMacros(
TfLiteStatus (*Prepare)(TfLiteOpaqueContext* context,
TfLiteOpaqueDelegate* delegate, void* data)) {
TfLiteModel* model =
TfLiteModelCreateFromFile("tensorflow/lite/testdata/add.bin");
// Create and install a delegate instance.
bool delegate_prepared_called = false;
TfLiteOpaqueDelegateBuilder opaque_delegate_builder = { NULL };
opaque_delegate_builder.data = &delegate_prepared_called;
opaque_delegate_builder.Prepare = Prepare;
TfLiteOpaqueDelegate* opaque_delegate =
TfLiteOpaqueDelegateCreate(&opaque_delegate_builder);
TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
TfLiteInterpreterOptionsAddDelegate(options, opaque_delegate);
TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
// The delegate's prepare function should have been called, even though it
// returned an error code.
CHECK(delegate_prepared_called);
TfLiteInterpreterOptionsDelete(options);
TfLiteInterpreterDelete(interpreter);
TfLiteModelDelete(model);
TfLiteOpaqueDelegateDelete(opaque_delegate);
}
TfLiteStatus TfLiteOpaqueContextReportErrorMacros_EnsureMsg_Prepare(
TfLiteOpaqueContext* context,
TfLiteOpaqueDelegate* opaque_delegate, void* data) {
bool* delegate_prepared = (bool*) data;
*delegate_prepared = true;
TF_LITE_OPAQUE_ENSURE_MSG(context, false, "false was not true!!!");
return kTfLiteOk;
}
TfLiteStatus TfLiteOpaqueContextReportErrorMacros_Ensure_Prepare(
TfLiteOpaqueContext* context,
TfLiteOpaqueDelegate* opaque_delegate, void* data) {
bool* delegate_prepared = (bool*) data;
*delegate_prepared = true;
TF_LITE_OPAQUE_ENSURE(context, false);
return kTfLiteOk;
}
TfLiteStatus TfLiteOpaqueContextReportErrorMacros_EnsureEq_Prepare(
TfLiteOpaqueContext* context,
TfLiteOpaqueDelegate* opaque_delegate, void* data) {
bool* delegate_prepared = (bool*) data;
*delegate_prepared = true;
TF_LITE_OPAQUE_ENSURE_EQ(context, 1, 2);
return kTfLiteOk;
}
TfLiteStatus TfLiteOpaqueContextReportErrorMacros_EnsureTypesEq_Prepare(
TfLiteOpaqueContext* context,
TfLiteOpaqueDelegate* opaque_delegate, void* data) {
bool* delegate_prepared = (bool*) data;
*delegate_prepared = true;
TF_LITE_OPAQUE_ENSURE_TYPES_EQ(context, '1', 2);
return kTfLiteOk;
}
TfLiteStatus TfLiteOpaqueContextReportErrorMacros_EnsureNear_Prepare(
TfLiteOpaqueContext* context,
TfLiteOpaqueDelegate* opaque_delegate, void* data) {
bool* delegate_prepared = (bool*) data;
*delegate_prepared = true;
TF_LITE_OPAQUE_ENSURE_NEAR(context, 3, 10, 1);
return kTfLiteOk;
}
static void RunTests(void) {
TestVersion();
TestInferenceUsingSignature();
TestRepeatResizeInputTensor();
TestInferenceUsingInterpreter();
TestTfLiteOpaqueContextGetExecutionPlan();
TestTfLiteOpaqueContextReportErrorMacros(
TfLiteOpaqueContextReportErrorMacros_Ensure_Prepare);
TestTfLiteOpaqueContextReportErrorMacros(
TfLiteOpaqueContextReportErrorMacros_EnsureMsg_Prepare);
TestTfLiteOpaqueContextReportErrorMacros(
TfLiteOpaqueContextReportErrorMacros_EnsureEq_Prepare);
TestTfLiteOpaqueContextReportErrorMacros(
TfLiteOpaqueContextReportErrorMacros_EnsureTypesEq_Prepare);
TestTfLiteOpaqueContextReportErrorMacros(
TfLiteOpaqueContextReportErrorMacros_EnsureNear_Prepare);
}
int main(void) {
RunTests();
return 0;
}
+33
View File
@@ -0,0 +1,33 @@
/* 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.
==============================================================================*/
/// \file
///
/// This file defines common C types and APIs for implementing operations,
/// delegates and other constructs in TensorFlow Lite. The actual operations and
/// delegates can be defined using C++, but the interface between the
/// interpreter and the operations are C.
///
/// For documentation, see tensorflow/lite/core/c/common.h.
///
/// See also c_api_opaque.h which has more ABI-stable variants of some of these
/// APIs.
#ifndef TENSORFLOW_LITE_C_COMMON_H_
#define TENSORFLOW_LITE_C_COMMON_H_
#include "tensorflow/lite/core/c/common.h"
#endif // TENSORFLOW_LITE_C_COMMON_H_
+98
View File
@@ -0,0 +1,98 @@
/* Copyright 2022 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/c/common_internal.h"
#include <cstdint>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
bool TfLiteDelegateIsOpaque(const TfLiteDelegate* delegate) {
return delegate != nullptr && delegate->Prepare == nullptr &&
delegate->CopyFromBufferHandle == nullptr &&
delegate->FreeBufferHandle == nullptr &&
delegate->opaque_delegate_builder != nullptr;
}
TfLiteStatus TfLiteDelegatePrepareInternal(TfLiteContext* context,
TfLiteDelegate* delegate) {
TfLiteStatus status = kTfLiteOk;
// The following casts are safe only because this code is part of the
// TF Lite runtime implementation. Apps using TF Lite should not rely on
// TfLiteOpaqueContext and TfLiteContext being equivalent, or on
// TfLiteOpaqueDelegate and TfLiteDelegate being equivalent.
if (TfLiteDelegateIsOpaque(delegate) &&
delegate->opaque_delegate_builder->Prepare) {
status = delegate->opaque_delegate_builder->Prepare(
reinterpret_cast<TfLiteOpaqueContext*>(context),
reinterpret_cast<TfLiteOpaqueDelegate*>(delegate),
delegate->opaque_delegate_builder->data);
} else {
status = delegate->Prepare(context, delegate);
}
return status;
}
TfLiteStatus TfLiteDelegateCopyFromBufferHandleInternal(
TfLiteContext* context, TfLiteDelegate* delegate,
TfLiteBufferHandle buffer_handle, TfLiteTensor* tensor) {
// The following casts are safe only because this code is part of the
// TF Lite runtime implementation. Apps using TF Lite should not rely on
// TfLiteOpaqueContext and TfLiteContext being equivalent, or on
// TfLiteOpaqueDelegate and TfLiteDelegate being equivalent.
if (TfLiteDelegateIsOpaque(delegate) &&
delegate->opaque_delegate_builder->CopyFromBufferHandle) {
return delegate->opaque_delegate_builder->CopyFromBufferHandle(
reinterpret_cast<TfLiteOpaqueContext*>(context),
reinterpret_cast<TfLiteOpaqueDelegate*>(delegate),
delegate->opaque_delegate_builder->data, tensor->buffer_handle,
reinterpret_cast<TfLiteOpaqueTensor*>(tensor));
} else {
TF_LITE_ENSURE(context, delegate->CopyFromBufferHandle != nullptr);
return delegate->CopyFromBufferHandle(context, delegate,
tensor->buffer_handle, tensor);
}
}
TfLiteStatus TfLiteDelegateFreeBufferHandleInternal(
TfLiteContext* context, TfLiteDelegate* delegate,
TfLiteBufferHandle* buffer_handle) {
// The following casts are safe only because this code is part of the
// TF Lite runtime implementation. Apps using TF Lite should not rely on
// TfLiteOpaqueContext and TfLiteContext being equivalent, or on
// TfLiteOpaqueDelegate and TfLiteDelegate being equivalent.
if (TfLiteDelegateIsOpaque(delegate) &&
delegate->opaque_delegate_builder->FreeBufferHandle) {
delegate->opaque_delegate_builder->FreeBufferHandle(
reinterpret_cast<TfLiteOpaqueContext*>(context),
reinterpret_cast<TfLiteOpaqueDelegate*>(delegate),
delegate->opaque_delegate_builder->data, buffer_handle);
return kTfLiteOk;
} else if (delegate->FreeBufferHandle != nullptr) {
delegate->FreeBufferHandle(context, delegate, buffer_handle);
return kTfLiteOk;
}
// We failed to free the buffer handle.
return kTfLiteError;
}
int64_t TfLiteDelegateGetFlagsInternal(TfLiteDelegate* delegate) {
if (TfLiteDelegateIsOpaque(delegate)) {
return delegate->opaque_delegate_builder->flags;
}
return delegate->flags;
}
+148
View File
@@ -0,0 +1,148 @@
/* Copyright 2022 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_C_COMMON_INTERNAL_H_
#define TENSORFLOW_LITE_C_COMMON_INTERNAL_H_
#include <stddef.h>
#include <stdint.h>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
// Internal structures and subroutines used by the C API. These are likely to
// change and should not be depended on directly by any C API clients.
//
// NOTE: This header does not follow C conventions and does not define a C API.
// It is effectively an (internal) implementation detail of the C API.
// `TfLiteOperator` is an external version of `TfLiteRegistration`
// for C API which doesn't use internal types (such as `TfLiteContext`) but only
// uses stable API types (such as `TfLiteOpaqueContext`). The purpose of each
// field is the exactly the same as with `TfLiteRegistration`.
typedef struct TfLiteOperator {
// Custom op name. This should be non-null iff the op is a custom op,
// i.e. iff builtin_code is kTfLiteBuiltinCustom.
const char* custom_name;
// The version of the op. The version should be higher than 0.
int version;
// Initializes the op from serialized data.
void* (*init)(TfLiteOpaqueContext* context, const char* buffer,
size_t length);
// Deallocates the op.
// The pointer `buffer` is the data previously returned by an init invocation.
void (*free)(TfLiteOpaqueContext* context, void* buffer);
// Called when the inputs that this node depends on have been resized.
TfLiteStatus (*prepare)(TfLiteOpaqueContext* context, TfLiteOpaqueNode* node);
// Called when the node is executed. (Should read node inputs and write to
// node outputs).
TfLiteStatus (*invoke)(TfLiteOpaqueContext* context, TfLiteOpaqueNode* node);
// Retrieves the async kernel. The functor is nullptr if the node / backend
// does not support asynchronous execution.
struct TfLiteAsyncKernel* (*async_kernel)(TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node);
// Builtin op code.
// The values stored in this field should be enum constants from the
// TfLiteBuiltinOperator enum.
// For custom ops, this should be the value kTfLiteBuiltinCustom.
int32_t builtin_code;
// The default value of this field is supposed to be '-1'.
// The default value indicates to the TF Lite runtime that this registration
// should be used through its callbacks, i.e. 'init', 'free' etc.
//
// This would be the case when a delegate implementation supplies an opaque
// delegate kernel to the runtime to claim the execution for a subset of
// nodes. This would also be the case when an application defines a custom OP.
//
// However, users might also iterate over the execution plan to visit the
// nodes and registrations associated with an opaque context. In this
// scenario, due to ABI stability reasons, we provide them with a registration
// external object, that internally delegates execution to a corresponding
// regular TfLiteRegistration. In such a case the 'node_index' field should
// store the index of that corresponding node (and registration).
int node_index;
// Indicates if an operator's output can safely overwrite its input.
// See the comments in `TfLiteInPlaceOp`.
uint64_t inplace_operator;
// Data supplied by the user in the `TfLiteOperatorCreate` call and then
// returned back to the user in the `TfLiteOperator` callbacks listed below.
// The user is expected to manage the memory pointed by this field and the
// lifetime of that memory should extend at least from the call to
// `TfLiteOperatorCreate` to the invocation of the callback set with
// `TfLiteOperatorSetFreeWithData`.
void* user_data;
// The following callbacks can be set with the `TfLiteOperatorSetXXXWithData`
// functions and if, so set, will pass back the value of the user_data field
// above as first argument.
//
// TODO(b/339641079): Remove the legacy callbacks listed above and rename
// these below without the `_with_data` suffix.
void* (*init_with_data)(void* user_data, TfLiteOpaqueContext* context,
const char* buffer, size_t length);
void (*free_with_data)(void* user_data, TfLiteOpaqueContext* context,
void* buffer);
TfLiteStatus (*prepare_with_data)(void* user_data,
TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node);
TfLiteStatus (*invoke_with_data)(void* user_data,
TfLiteOpaqueContext* context,
TfLiteOpaqueNode* node);
struct TfLiteAsyncKernel* (*async_kernel_with_data)(
void* user_data, TfLiteOpaqueContext* context, TfLiteOpaqueNode* node);
} TfLiteOperator;
// Returns true iff the delegate is a well-formed opaque delegate, i.e. none of
// the fields that are part of the legacy 'TfLiteDelegate' interface are set.
bool TfLiteDelegateIsOpaque(const TfLiteDelegate* delegate);
// Invokes 'Prepare' on the provided 'delegate', giving the 'delegate' a view
// of the current graph through the provided 'context'. Returns the delegate's
// 'Prepare' return value.
TfLiteStatus TfLiteDelegatePrepareInternal(TfLiteContext* context,
TfLiteDelegate* delegate);
// Invokes 'CopyFromBufferHandle' on the provided 'delegate', supplying the
// provided 'buffer_handle' and 'tensor' as arguments. The provided
// 'buffer_handle' must have a non-null buffer handle value (i.e., not
// 'kTfLiteNullBufferHandle'). Returns the delegate's 'CopyFromBufferHandle'
// return value.
TfLiteStatus TfLiteDelegateCopyFromBufferHandleInternal(
TfLiteContext* context, TfLiteDelegate* delegate,
TfLiteBufferHandle buffer_handle, TfLiteTensor* tensor);
// Invokes 'FreeBufferHandle' on the provided 'delegate', supplying the provided
// 'buffer_handle' as an argument. The '*buffer_handle' must have a non-null
// buffer handle value (i.e., not 'kTfLiteNullBufferHandle'). Returns
// 'kTfLiteOk' if 'FreeBufferHandle' was called, or 'kTfLiteError' if the
// callback is not available.
TfLiteStatus TfLiteDelegateFreeBufferHandleInternal(
TfLiteContext* context, TfLiteDelegate* delegate,
TfLiteBufferHandle* buffer_handle);
// Returns the 'delegate' flags value. Note, if the delegate contains a valid
// opaque_delegate_builder field, then the flags of the delegate external are
// returned. Otherwise, the flags field inside `TfLiteDelegate` is returned.
int64_t TfLiteDelegateGetFlagsInternal(TfLiteDelegate* delegate);
#endif // TENSORFLOW_LITE_C_COMMON_INTERNAL_H_
+1
View File
@@ -0,0 +1 @@
_TfLite*
+22
View File
@@ -0,0 +1,22 @@
load("//tensorflow/lite:special_rules.bzl", "tflite_portable_test_suite")
load("//tensorflow/lite/core/shims:cc_library_with_tflite.bzl", "cc_library_with_tflite_with_c_headers_test")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
licenses = ["notice"],
)
#------------------------------------------------------------------------------
# Utilities for use in JNI Bindings (e.g. Java API and Java Tasks library).
cc_library_with_tflite_with_c_headers_test(
name = "jni_utils",
srcs = ["jni_utils.cc"],
hdrs = ["jni_utils.h"],
visibility = ["//visibility:public"],
deps = [
"//tensorflow/lite/java/jni",
],
)
tflite_portable_test_suite()
+20
View File
@@ -0,0 +1,20 @@
/* Copyright 2021 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/c/jni/jni_utils.h"
bool TfLiteCheckInitializedOrThrow(JNIEnv* env) {
// No additional initialization is required.
return true;
}
+39
View File
@@ -0,0 +1,39 @@
/* Copyright 2021 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_JNI_JNI_UTILS_H_
#define TENSORFLOW_LITE_JNI_JNI_UTILS_H_
#include <jni.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/// Checks whether the TFLite API has been initialized, throwing a Java exception
/// otherwise.
///
/// @param env The JNIEnv for the current thread (which has to be attached to the
/// JVM).
/// @return Whether or not the TFLite API has been initialized. If this method
/// returns false, no other JNI method should be called until the pending
/// exception has been handled (typically by returning to Java).
bool TfLiteCheckInitializedOrThrow(JNIEnv* env);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_LITE_JNI_JNI_UTILS_H_
+19
View File
@@ -0,0 +1,19 @@
/* 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/c/test_util.h"
int TfLiteInitializeShimsForTest() {
return 0;
}
+32
View File
@@ -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_C_TEST_UTIL_H_
#define TENSORFLOW_LITE_C_TEST_UTIL_H_
#ifdef __cplusplus
extern "C" {
#endif
// Initialize TF Lite shims, in a manner appropriate for running unit tests.
// Returns zero on success, or an implementation-defined error code on failure.
// This should be called before calling any other shims functions or methods
// in unit tests.
int TfLiteInitializeShimsForTest(void);
#ifdef __cplusplus
}
#endif
#endif // TENSORFLOW_LITE_C_TEST_UTIL_H_
+9
View File
@@ -0,0 +1,9 @@
VERS_1.0 {
# Export symbols in c_api.h.
global:
TfLite*;
# Hide everything else.
local:
*;
};
+35
View File
@@ -0,0 +1,35 @@
#
# Copyright 2024 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
#
# https://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.
CMAKE_MINIMUM_REQUIRED(VERSION 3.5 FATAL_ERROR)
PROJECT(fp16-download NONE)
# Set file timestamps to the time of extraction.
IF(POLICY CMP0135)
CMAKE_POLICY(SET CMP0135 NEW)
ENDIF()
INCLUDE(ExternalProject)
ExternalProject_Add(fp16
URL https://github.com/Maratyszcza/FP16/archive/0a92994d729ff76a58f692d3028ca1b64b145d91.zip
URL_HASH SHA256=e66e65515fa09927b348d3d584c68be4215cfe664100d01c9dbc7655a5716d70
SOURCE_DIR "${CMAKE_BINARY_DIR}/FP16-source"
BINARY_DIR "${CMAKE_BINARY_DIR}/FP16"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
@@ -0,0 +1,30 @@
#
# Copyright 2022 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
#
# https://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.
CMAKE_MINIMUM_REQUIRED(VERSION 3.5 FATAL_ERROR)
PROJECT(pthreadpool-download NONE)
INCLUDE(ExternalProject)
ExternalProject_Add(pthreadpool
URL https://github.com/google/pthreadpool/archive/9003ee6c137cea3b94161bd5c614fb43be523ee1.zip
URL_HASH SHA256=00a9a1c633f62290a22ea1db42c4401dffe9f05645fb66d6609ae46a05333a2a
SOURCE_DIR "${CMAKE_BINARY_DIR}/pthreadpool-source"
BINARY_DIR "${CMAKE_BINARY_DIR}/pthreadpool"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)
+21
View File
@@ -0,0 +1,21 @@
/* Copyright 2017 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.
==============================================================================*/
// Compatibility shim for moved header location.
#ifndef TENSORFLOW_LITE_CONTEXT_H_
#define TENSORFLOW_LITE_CONTEXT_H_
#include "tensorflow/lite/core/c/common.h"
#endif // TENSORFLOW_LITE_CONTEXT_H_
+54
View File
@@ -0,0 +1,54 @@
/* Copyright 2017 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.
==============================================================================*/
/// \file
///
/// This provides a few C++ helpers that are useful for manipulating C
/// structures in C++.
#ifndef TENSORFLOW_LITE_CONTEXT_UTIL_H_
#define TENSORFLOW_LITE_CONTEXT_UTIL_H_
#include <stddef.h>
#include "tensorflow/lite/core/c/common.h"
namespace tflite {
/// Provides a range iterable wrapper for TfLiteIntArray* (C lists) that TfLite
/// C api uses.
// Can't use the google array_view, since we can't depend on even
// absl for embedded device reasons.
class TfLiteIntArrayView {
public:
/// Construct a view of a TfLiteIntArray*. Note, `int_array` should be
/// non-null and this view does not take ownership of it.
explicit TfLiteIntArrayView(const TfLiteIntArray* int_array)
: int_array_(int_array) {}
TfLiteIntArrayView(const TfLiteIntArrayView&) = default;
TfLiteIntArrayView& operator=(const TfLiteIntArrayView& rhs) = default;
typedef const int* const_iterator;
const_iterator begin() const { return int_array_->data; }
const_iterator end() const { return &int_array_->data[int_array_->size]; }
size_t size() const { return end() - begin(); }
int operator[](size_t pos) const { return int_array_->data[pos]; }
private:
const TfLiteIntArray* int_array_;
};
} // namespace tflite
#endif // TENSORFLOW_LITE_CONTEXT_UTIL_H_
+593
View File
@@ -0,0 +1,593 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("//tensorflow:tensorflow.default.bzl", "get_compatible_with_portable")
load("//tensorflow/lite:build_def.bzl", "tflite_copts", "tflite_copts_warnings", "tflite_self_contained_libs_test_suite")
load("//tensorflow/lite:special_rules.bzl", "internal_visibility_allowlist", "tflite_portable_test_suite")
load("//tensorflow/lite/core:special_rules.bzl", "core_cc_api_stable_visibility_allowlist", "macros_visibility_allowlist")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
licenses = ["notice"],
)
exports_files(
srcs = [
"create_op_resolver.h",
"macros.h",
"subgraph.h",
],
visibility = [
"//tensorflow/lite:__subpackages__",
],
)
bzl_library(
name = "special_rules_bzl",
srcs = ["special_rules.bzl"],
visibility = ["//tensorflow/lite:__subpackages__"],
)
# The public target for the C++ API excluding experimental APIs.
# TODO(ahentz): investigate dependency on gemm_support requiring usage of tf_copts.
cc_library(
name = "framework_stable",
srcs = [
"subgraph.h",
],
hdrs = [
"interpreter.h",
"interpreter_builder.h",
"macros.h",
"model.h",
"model_builder.h",
"signature_runner.h",
],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
visibility = ["//tensorflow/lite:__subpackages__"],
deps = [
":cc_api_stable",
":signature_runner",
"//tensorflow/compiler/mlir/lite/core:model_builder_base",
"//tensorflow/compiler/mlir/lite/experimental/remat:metadata_util",
"//tensorflow/lite:allocation",
"//tensorflow/lite:array",
"//tensorflow/lite:external_cpu_backend_context",
"//tensorflow/lite:graph_info",
"//tensorflow/lite:interpreter_options_header",
"//tensorflow/lite:macros",
"//tensorflow/lite:memory_planner",
"//tensorflow/lite:mutable_op_resolver",
"//tensorflow/lite:stderr_reporter",
"//tensorflow/lite:string",
"//tensorflow/lite:type_to_tflitetype",
"//tensorflow/lite:util",
"//tensorflow/lite/c:common_internal",
"//tensorflow/lite/core/api",
"//tensorflow/lite/core/async:async_signature_runner",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/experimental/resource",
"//tensorflow/lite/internal:signature_def",
"//tensorflow/lite/profiling:root_profiler",
"//tensorflow/lite/profiling/telemetry:profiler",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting_internal",
"//tensorflow/lite/schema:schema_fbs",
"@flatbuffers//:runtime_cc",
],
)
# The public target for the full C++ API, including experimental APIs.
#
# Experimental APIs are functional, tested and usable in production; however,
# the corresponding API surface has not been finalized, and is subject to
# change.
alias(
name = "framework",
actual = "framework_experimental",
compatible_with = get_compatible_with_portable(),
visibility = ["//visibility:public"],
)
# The full C++ API, including experimental APIs.
#
# Experimental APIs are functional, tested and usable in production; however,
# the corresponding API surface has not been finalized, and is subject to
# change.
#
# Note that if you have code which depends on both stable and experimental API
# features, it's fine to depend only on 'framework_experimental', since
# that includes 'framework_stable' as a subset.
cc_library(
name = "framework_experimental",
srcs = [],
hdrs = [
"interpreter.h",
"interpreter_builder.h",
"macros.h",
"model.h",
"model_builder.h",
"subgraph.h",
],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
visibility = [
"//tensorflow/lite:__subpackages__",
],
deps = [
":cc_api_experimental",
":cc_api_stable",
":model_builder",
":signature_runner",
"//tensorflow/compiler/mlir/lite/core:model_builder_base",
"//tensorflow/compiler/mlir/lite/experimental/remat:metadata_util",
"//tensorflow/lite:allocation",
"//tensorflow/lite:array",
"//tensorflow/lite:external_cpu_backend_context",
"//tensorflow/lite:graph_info",
"//tensorflow/lite:interpreter_options_header",
"//tensorflow/lite:macros",
"//tensorflow/lite:memory_planner",
"//tensorflow/lite:mutable_op_resolver",
"//tensorflow/lite:stderr_reporter",
"//tensorflow/lite:string",
"//tensorflow/lite:type_to_tflitetype",
"//tensorflow/lite:util",
"//tensorflow/lite/c:common_internal",
"//tensorflow/lite/core/api",
"//tensorflow/lite/core/async:async_signature_runner",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/experimental/resource",
"//tensorflow/lite/internal:signature_def",
"//tensorflow/lite/profiling:root_profiler",
"//tensorflow/lite/profiling/telemetry:profiler",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting_internal",
"//tensorflow/lite/schema:schema_fbs",
"@flatbuffers//:runtime_cc",
],
alwayslink = 1, # TODO(b/161243354): eliminate this.
)
# This is a private target, its visibility is set to public only to be
# used by LiteRT dependencies.
# Do not use this target directly and don't consider it as a part of the public API.
# TODO(weiyiw): Refactor LiteRT deps from TFLite.
alias(
name = "private_cc_api_stable",
actual = ":cc_api_stable",
tags = ["avoid_dep"],
visibility = [
"//visibility:public",
],
)
# TODO(b/242310498): move logger.cc from tensorflow/lite/ to here.
cc_library(
name = "cc_api_stable",
srcs = [
"interpreter.cc",
"interpreter_builder.cc",
"subgraph.h",
],
hdrs = [
"interpreter.h",
"interpreter_builder.h",
"model.h",
"model_builder.h",
"signature_runner.h",
],
compatible_with = get_compatible_with_portable(),
visibility = [
"//tensorflow/lite:__subpackages__",
"//third_party/deepmind/lyria_live/internal/odml:__subpackages__",
"//third_party/odml/litert:__subpackages__",
] + core_cc_api_stable_visibility_allowlist(),
deps = [
":model_builder",
":signature_runner",
":subgraph",
"//tensorflow/compiler/mlir/lite/core:model_builder_base",
"//tensorflow/compiler/mlir/lite/experimental/remat:metadata_util",
"//tensorflow/compiler/mlir/lite/schema:schema_fbs",
"//tensorflow/compiler/mlir/lite/schema:schema_utils",
"//tensorflow/lite:allocation",
"//tensorflow/lite:array",
"//tensorflow/lite:external_cpu_backend_context",
"//tensorflow/lite:graph_info",
"//tensorflow/lite:interpreter_options_header",
"//tensorflow/lite:macros",
"//tensorflow/lite:memory_planner",
"//tensorflow/lite:minimal_logging",
"//tensorflow/lite:mutable_op_resolver",
"//tensorflow/lite:shared_library",
"//tensorflow/lite:simple_memory_arena",
"//tensorflow/lite:stderr_reporter",
"//tensorflow/lite:string",
"//tensorflow/lite:tensorflow_profiler_logger_shim",
"//tensorflow/lite:type_to_tflitetype",
"//tensorflow/lite:util",
"//tensorflow/lite:version",
"//tensorflow/lite/c:common_internal",
"//tensorflow/lite/core/api",
"//tensorflow/lite/core/api:verifier",
"//tensorflow/lite/core/async:async_signature_runner",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
# copybara:uncomment "//tensorflow/lite/delegates:telemetry",
"//tensorflow/lite/delegates/xnnpack:tflite_with_xnnpack_qs8",
"//tensorflow/lite/delegates/xnnpack:tflite_with_xnnpack_qu8",
"//tensorflow/lite/experimental/resource",
"//tensorflow/lite/internal:signature_def",
"//tensorflow/lite/kernels/internal:compatibility",
"//tensorflow/lite/profiling:platform_profiler",
"//tensorflow/lite/profiling:root_profiler",
"//tensorflow/lite/profiling/telemetry",
"//tensorflow/lite/profiling/telemetry:profiler",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting_internal",
"//tensorflow/lite/schema:conversion_metadata_fbs",
"//tensorflow/lite/schema:schema_fbs",
"//tensorflow/lite/schema:schema_utils",
"@flatbuffers//:runtime_cc",
"@ruy//ruy:denormal",
],
alwayslink = 1,
)
# The key parts of the C++ API. This target defines the TF Lite classes for
# loading models and interpreting them.
# DEPRECATED: prefer to depend on :cc_api_stable or :cc_api_experimental.
alias(
name = "cc_api",
actual = "cc_api_experimental",
visibility = ["//tensorflow/lite:__subpackages__"],
)
# The key parts of the C++ API, including experimental APIs.
#
# This target has restricted visibility; for a public target that exposes
# these APIs, see 'framework_experimental' above.
cc_library(
name = "cc_api_experimental",
srcs = [
"interpreter_experimental.cc",
],
hdrs = [
"interpreter.h",
"interpreter_builder.h",
"model.h",
"model_builder.h",
"signature_runner.h",
"subgraph.h",
],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
visibility = [
"//tensorflow/lite:__subpackages__",
],
deps = [
":cc_api_stable",
":signature_runner",
"//tensorflow/compiler/mlir/lite/core:model_builder_base",
"//tensorflow/compiler/mlir/lite/experimental/remat:metadata_util",
"//tensorflow/lite:allocation",
"//tensorflow/lite:array",
"//tensorflow/lite:external_cpu_backend_context",
"//tensorflow/lite:graph_info",
"//tensorflow/lite:interpreter_options_header",
"//tensorflow/lite:macros",
"//tensorflow/lite:memory_planner",
"//tensorflow/lite:mutable_op_resolver",
"//tensorflow/lite:stderr_reporter",
"//tensorflow/lite:string",
"//tensorflow/lite:type_to_tflitetype",
"//tensorflow/lite:util",
"//tensorflow/lite/c:common_internal",
"//tensorflow/lite/core/api",
"//tensorflow/lite/core/async:async_signature_runner",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/experimental/resource",
"//tensorflow/lite/internal:signature_def",
"//tensorflow/lite/profiling:root_profiler",
"//tensorflow/lite/profiling/telemetry:profiler",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting",
"//tensorflow/lite/profiling/telemetry/c:telemetry_setting_internal",
"//tensorflow/lite/schema:schema_fbs",
"@flatbuffers//:runtime_cc",
],
alwayslink = 1, # TODO(b/161243354): eliminate this.
)
cc_library(
name = "model_builder",
hdrs = ["model_builder.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts_warnings(),
visibility = internal_visibility_allowlist(),
deps = [
"//tensorflow/compiler/mlir/lite/core:model_builder_base",
"//tensorflow/lite:stderr_reporter",
"//tensorflow/lite/core/api:error_reporter",
],
alwayslink = 1,
)
cc_library(
name = "signature_runner",
srcs = ["signature_runner.cc"],
hdrs = ["signature_runner.h"],
compatible_with = get_compatible_with_portable(),
visibility = [
"//tensorflow/lite:__pkg__",
"//tensorflow/lite/core:__subpackages__",
"//third_party/odml/infra/genai/inference/executor/google_tensor:__subpackages__",
],
deps = [
"//tensorflow/lite/c:common",
"//tensorflow/lite/core:subgraph",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/internal:signature_def",
],
)
# Test signature runner.
cc_test(
name = "signature_runner_test",
size = "small",
srcs = ["signature_runner_test.cc"],
data = [
"//tensorflow/lite:testdata/multi_signatures.bin",
"//tensorflow/lite:testdata/no_signatures.bin",
"//tensorflow/lite:testdata/no_signatures_no_tensor_names.bin",
"//tensorflow/lite:testdata/reverse_signature_model.bin",
],
deps = [
":framework",
":signature_runner",
"//tensorflow/compiler/mlir/lite/core:model_builder_base",
"//tensorflow/lite:model_builder",
"//tensorflow/lite/core/kernels:builtin_ops",
"//tensorflow/lite/testing:util",
"@com_google_googletest//:gtest_main",
],
)
# Test model framework.
cc_test(
name = "model_test",
size = "small",
srcs = ["model_test.cc"],
data = [
"//tensorflow/lite:testdata/0_subgraphs.bin",
"//tensorflow/lite:testdata/2_subgraphs.bin",
"//tensorflow/lite:testdata/2_subgraphs_dont_delegate_name.bin",
"//tensorflow/lite:testdata/add_shared_tensors.bin",
"//tensorflow/lite:testdata/empty_model.bin",
"//tensorflow/lite:testdata/multi_add_flex.bin",
"//tensorflow/lite:testdata/segment_sum_invalid_buffer.bin",
"//tensorflow/lite:testdata/sparse_tensor.bin",
"//tensorflow/lite:testdata/test_min_runtime.bin",
"//tensorflow/lite:testdata/test_model.bin",
"//tensorflow/lite:testdata/test_model_broken.bin",
"//tensorflow/lite:testdata/test_model_redux_precision.bin",
"//tensorflow/lite:testdata/while_op_with_forwarding_input.bin",
"//tensorflow/lite:testdata/zero_size_constant.bin",
],
tags = [
"no_windows", # TODO(b/194459105): the test is flaky.
"noasan",
"tflite_not_portable",
"tflite_smoke_test",
],
deps = [
":framework",
"//tensorflow/compiler/mlir/lite:allocation",
"//tensorflow/lite:framework",
"//tensorflow/lite:string_util",
"//tensorflow/lite:version",
"//tensorflow/lite/core/api",
"//tensorflow/lite/core/api:verifier",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/core/kernels:builtin_ops",
"//tensorflow/lite/schema:schema_fbs",
"//tensorflow/lite/testing:util",
"@com_google_googletest//:gtest_main",
"@flatbuffers//:runtime_cc",
],
)
cc_library(
name = "create_op_resolver_header",
hdrs = [
"create_op_resolver.h",
],
compatible_with = get_compatible_with_portable(),
visibility = [
"//tensorflow/lite:__subpackages__",
],
deps = [
"//tensorflow/lite:mutable_op_resolver",
"//tensorflow/lite:op_resolver",
],
)
# Defines CreateOpResolver with all builtin ops.
cc_library(
name = "create_op_resolver_with_builtin_ops",
srcs = ["create_op_resolver_with_builtin_ops.cc"],
hdrs = ["create_op_resolver.h"],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts(),
visibility = [
"//tensorflow/lite:__subpackages__",
],
deps = [
"//tensorflow/lite:mutable_op_resolver",
"//tensorflow/lite:op_resolver",
"//tensorflow/lite/core/kernels:builtin_ops",
],
# Some targets only have an implicit dependency on CreateOpResolver.
# This avoids warnings about backwards references when linking.
alwayslink = True,
)
# This target is only for use by the "tflite_custom_c_library" and "tflite_custom_cc_library" build
# macro and should not be used anywhere other than in the implementation of that build macro.
# "tflite_custom_c_library" requires target to be public, that's why we duplicated
# :create_op_resolver_header target to be used only by "tflite_custom_c_library".
# Making :create_op_resolver_header public could cause some problems because it is widely used
# inside the TF Lite code base, that might lead others outside the TF Lite code base to copy that
# dependency and use it and subsequently depend on it, which would be bad. Using a separate
# :private_create_op_resolver_header target ensures that the only use of the unwantedly-"public"
# target is inside the "tflite_custom_c_library" itself, where it is less likely to get copied into
# third party code.
alias(
name = "private_create_op_resolver_header",
actual = ":create_op_resolver_header",
tags = ["avoid_dep"],
visibility = [
"//visibility:public",
],
)
cc_library(
name = "macros",
hdrs = ["macros.h"],
compatible_with = get_compatible_with_portable(),
visibility = [
"//tensorflow/lite:__subpackages__",
] + macros_visibility_allowlist(),
)
cc_library(
name = "subgraph",
srcs = [
"subgraph.cc",
],
hdrs = [
"subgraph.h",
],
compatible_with = get_compatible_with_portable(),
copts = tflite_copts() + tflite_copts_warnings(),
visibility = [
"//tensorflow/lite:__subpackages__",
"//tensorflow/lite/core:__subpackages__",
"//tensorflow/lite/kernels:__subpackages__",
],
deps = [
"//tensorflow/compiler/mlir/lite/experimental/remat:metadata_util",
"//tensorflow/lite:allocation",
"//tensorflow/lite:array",
"//tensorflow/lite:graph_info",
"//tensorflow/lite:interpreter_options_header",
"//tensorflow/lite:kernel_api",
"//tensorflow/lite:macros",
"//tensorflow/lite:memory_planner",
"//tensorflow/lite:minimal_logging",
"//tensorflow/lite:util",
"//tensorflow/lite/c:common_internal",
"//tensorflow/lite/core/api",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/experimental/resource",
"//tensorflow/lite/profiling:root_profiler",
"//tensorflow/lite/profiling/telemetry",
"//tensorflow/lite/schema:schema_fbs",
] + select({
"//tensorflow/lite:tflite_use_simple_memory_planner": [
"//tensorflow/lite:simple_planner",
],
"//conditions:default": [
"//tensorflow/lite:arena_planner",
],
}) + select({
"//tensorflow/lite:tensorflow_profiler_config": [
"//tensorflow/lite:tensorflow_profiler_logger_shim",
],
"//conditions:default": [],
}),
alwayslink = 1, # TODO(b/161243354): eliminate this.
)
# Test subgraph.
cc_test(
name = "subgraph_test",
size = "small",
srcs = [
"subgraph_test.cc",
],
deps = [
":framework_stable",
"//tensorflow/lite:framework",
"//tensorflow/lite:util",
"//tensorflow/lite/c:c_api_types",
"//tensorflow/lite/kernels:builtin_ops", # build_cleaner: keep
"@com_google_absl//absl/log:check",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "model_building",
srcs = ["model_building.cc"],
hdrs = ["model_building.h"],
visibility = [
"//tensorflow/lite:__subpackages__",
],
deps = [
":subgraph",
"//tensorflow/lite:array",
"//tensorflow/lite:framework",
"//tensorflow/lite:type_to_tflitetype",
"//tensorflow/lite/c:c_api_types",
"//tensorflow/lite/c:common",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/kernels:builtin_ops",
"//tensorflow/lite/schema:schema_fbs",
"@com_google_absl//absl/container:flat_hash_map",
],
)
cc_test(
name = "model_building_test",
srcs = ["model_building_test.cc"],
deps = [
":model_building",
"//tensorflow/lite:framework",
"//tensorflow/lite/c:c_api_types",
"@com_google_absl//absl/algorithm:container",
"@com_google_absl//absl/types:span",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "subgraph_composite_inlining_test",
srcs = ["subgraph_composite_inlining_test.cc"],
deps = [
":model_building",
":subgraph",
"//tensorflow/lite:array",
"//tensorflow/lite:builtin_ops",
"//tensorflow/lite:framework",
"//tensorflow/lite:util",
"//tensorflow/lite/c:c_api_types",
"//tensorflow/lite/c:common",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/kernels:kernel_util",
"//tensorflow/lite/kernels:subgraph_test_util",
"//tensorflow/lite/kernels:test_util",
"//tensorflow/lite/kernels/internal:tensor_ctypes",
"//tensorflow/lite/schema:schema_fbs",
"@com_google_absl//absl/types:span",
"@com_google_googletest//:gtest_main",
],
)
tflite_self_contained_libs_test_suite(name = "self_contained_libs_test_suite")
tflite_portable_test_suite()
+28
View File
@@ -0,0 +1,28 @@
This directory contains the "core" part of the TensorFlow Lite runtime library.
The header files in this `tensorflow/lite/core/` directory fall into several
categories.
1. Public API headers, in the `api` subdirectory `tensorflow/lite/core/api/`
These are in addition to the other public API headers in `tensorflow/lite/`.
For example:
- `tensorflow/lite/core/api/error_reporter.h`
- `tensorflow/lite/core/api/op_resolver.h`
2. Private headers that define public API types and functions.
These headers are each `#include`d from a corresponding public "shim" header
in `tensorflow/lite/` that forwards to the private header.
For example:
- `tensorflow/lite/core/interpreter.h` is a private header file that is
included from the public "shim" header file `tensorflow/lite/interpeter.h`.
These private header files should be used as follows: `#include`s from `.cc`
files in TF Lite itself that are _implementing_ the TF Lite APIs should
include the "core" TF Lite API headers. `#include`s from files that are
just _using_ the regular TF Lite APIs should include the regular public
headers.
3. The header file `tensorflow/lite/core/subgraph.h`. This contains
some experimental APIs.
@@ -0,0 +1,133 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("//tensorflow:tensorflow.default.bzl", "get_compatible_with_portable")
load("//tensorflow/lite:special_rules.bzl", "nnapi_plugin_impl_visibility_allowlist", "xnnpack_plugin_impl_visibility_allowlist")
load("//tensorflow/lite/core:special_rules.bzl", "delegate_registry_visibility_allowlist")
load("//tensorflow/lite/core/c:special_rules.bzl", "experimental_acceleration_api_allowlist")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
licenses = ["notice"],
)
cc_library(
name = "delegate_registry",
srcs = ["delegate_registry.cc"],
hdrs = ["delegate_registry.h"],
compatible_with = get_compatible_with_portable(),
visibility = [
"//tensorflow/lite:__subpackages__",
] + delegate_registry_visibility_allowlist(),
deps = [
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/core/c:common",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/synchronization",
],
)
cc_library(
name = "nnapi_plugin",
srcs = ["nnapi_plugin.cc"],
hdrs = ["nnapi_plugin.h"],
compatible_with = get_compatible_with_portable(),
visibility = nnapi_plugin_impl_visibility_allowlist() + [
"//tensorflow/lite:__subpackages__",
],
deps = [
":delegate_registry",
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/core/acceleration/configuration/c:delegate_plugin",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/delegates/nnapi:nnapi_delegate",
"//tensorflow/lite/nnapi:nnapi_implementation_headers",
"//tensorflow/lite/nnapi:nnapi_lib",
"@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 = [
":delegate_registry",
":nnapi_plugin",
"//tensorflow/lite:framework",
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/core:framework",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/delegates/nnapi:nnapi_delegate",
"//tensorflow/lite/delegates/nnapi:nnapi_delegate_mock_test",
"//tensorflow/lite/kernels:test_util",
"//tensorflow/lite/nnapi:nnapi_implementation_headers",
"//tensorflow/lite/nnapi:nnapi_lib",
"//tensorflow/lite/schema:schema_fbs",
"@com_google_googletest//:gtest_main",
"@flatbuffers",
],
)
cc_library(
name = "stable_delegate_registry",
srcs = ["stable_delegate_registry.cc"],
hdrs = ["stable_delegate_registry.h"],
visibility = [
"//tensorflow/lite:__subpackages__",
] + experimental_acceleration_api_allowlist(),
deps = [
"//tensorflow/lite/core/acceleration/configuration/c:stable_delegate",
"//tensorflow/lite/core/shims:tflite_use_opaque_delegate", # buildcleaner: keep
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/synchronization",
],
)
cc_test(
name = "stable_delegate_registry_test",
srcs = ["stable_delegate_registry_test.cc"],
deps = [
":stable_delegate_registry",
"//tensorflow/lite/core/acceleration/configuration/c:stable_delegate",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "xnnpack_plugin",
srcs = ["xnnpack_plugin.cc"],
compatible_with = get_compatible_with_portable(),
visibility = xnnpack_plugin_impl_visibility_allowlist() + [
"//tensorflow/lite:__subpackages__",
],
deps = [
"//tensorflow/lite:minimal_logging",
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/c:c_api_types",
"//tensorflow/lite/core/acceleration/configuration:delegate_registry",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/delegates/xnnpack:xnnpack_delegate",
"@com_google_absl//absl/base:log_severity",
"@com_google_absl//absl/memory",
],
alwayslink = 1, # For registration to always run.
)
cc_test(
name = "xnnpack_plugin_test",
srcs = ["xnnpack_plugin_test.cc"],
deps = [
":xnnpack_plugin",
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/core/acceleration/configuration:delegate_registry",
"//tensorflow/lite/delegates/xnnpack:xnnpack_delegate",
"@com_google_googletest//:gtest_main",
"@flatbuffers//:runtime_cc",
"@pthreadpool",
],
)
@@ -0,0 +1,244 @@
# Copyright 2022 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.
# ==============================================================================
# C API for delegate plugins.
load("@rules_cc//cc:cc_test.bzl", "cc_test")
load("//tensorflow:tensorflow.default.bzl", "get_compatible_with_portable")
load(
"//tensorflow/core/platform:build_config_root.bzl",
"tf_gpu_tests_tags",
)
load("//tensorflow/lite:build_def.bzl", "tflite_cc_library_with_c_headers_test", "tflite_copts", "tflite_copts_warnings")
load(
"//tensorflow/lite/core/acceleration/configuration/c:special_rules.bzl",
"delegate_plugin_visibility_allowlist",
"gpu_plugin_visibility_allowlist",
"xnnpack_plugin_visibility_allowlist",
)
load("//tensorflow/lite/core/c:special_rules.bzl", "experimental_acceleration_api_allowlist")
load("//tensorflow/lite/core/shims:build_defs.bzl", "build_test")
load("//tensorflow/lite/delegates/gpu:build_defs.bzl", "gpu_delegate_linkopts")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = [
"//tensorflow/lite:__subpackages__",
] + experimental_acceleration_api_allowlist(),
licenses = ["notice"],
)
filegroup(
name = "tflite_internal_cc_3p_api_deps_src",
srcs = [
"stable_delegate.h",
],
visibility = [
"//tensorflow/lite:__pkg__",
],
)
# LINT.IfChange(tflite_acceleration_exported_headers)
exports_files([
"delegate_plugin.h",
"gpu_plugin.h",
"xnnpack_plugin.h",
])
# LINT.ThenChange(
# ../../../../acceleration/configuration/c/BUILD:tflite_acceleration_exported_headers,
# ../../../../java/BUILD:tflite_acceleration_exported_headers
# )
tflite_cc_library_with_c_headers_test(
name = "delegate_plugin",
hdrs = ["delegate_plugin.h"],
compatible_with = get_compatible_with_portable(),
visibility = [
"//tensorflow/lite:__subpackages__",
] + delegate_plugin_visibility_allowlist(),
deps = [
"//tensorflow/lite/core/c:common",
],
)
common_copts = tflite_copts() + tflite_copts_warnings()
tflite_cc_library_with_c_headers_test(
name = "gpu_plugin",
srcs = ["gpu_plugin.cc"],
hdrs = ["gpu_plugin.h"],
copts = common_copts + select({
"//tensorflow:ios": [
"-xobjective-c++",
],
"//tensorflow:macos_arm64": [
"-xobjective-c++",
],
"//conditions:default": [],
}),
visibility = [
"//tensorflow/lite:__subpackages__",
] + gpu_plugin_visibility_allowlist(),
deps = [
":delegate_plugin",
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/acceleration/configuration:gpu_plugin_impl",
"//tensorflow/lite/core/c:common",
] + select({
"//tensorflow/lite/delegates/gpu:supports_gpu_delegate": [
"//tensorflow/lite/delegates/gpu:delegate",
],
"//conditions:default": [],
}) + select({
"//tensorflow:ios": [
"//tensorflow/lite/delegates/gpu:metal_delegate",
],
"//tensorflow:macos_arm64": [
"//tensorflow/lite/delegates/gpu:metal_delegate",
],
"//conditions:default": [],
}),
)
# For non-Android platforms, this should be built with '--copt=-DCL_DELEGATE_NO_GL'.
# On non-supported platforms (i.e. non-Android platforms if -DCL_DELEGATE_NO_GL wasn't specified),
# the test srcs are set to the empty list, so the test will succeed without testing anything.
cc_test(
name = "gpu_plugin_test",
srcs = select({
"//tensorflow/lite/delegates/gpu:supports_gpu_delegate": ["gpu_plugin_test.cc"],
"//conditions:default": [],
}),
linkopts = gpu_delegate_linkopts(),
tags = tf_gpu_tests_tags(),
deps = select({
"//tensorflow/lite/delegates/gpu:supports_gpu_delegate": [":gpu_plugin"],
"//conditions:default": [],
}) + [
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/core/c:common",
"@com_google_googletest//:gtest_main",
],
)
tflite_cc_library_with_c_headers_test(
name = "nnapi_plugin",
srcs = ["nnapi_plugin.cc"],
hdrs = ["nnapi_plugin.h"],
deps = [
":delegate_plugin",
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/core/acceleration/configuration:nnapi_plugin",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/delegates/nnapi:nnapi_delegate",
],
)
cc_test(
name = "nnapi_plugin_test",
srcs = ["nnapi_plugin_test.cc"],
deps = [
":nnapi_plugin",
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/core/c:common",
"@com_google_googletest//:gtest_main",
"@flatbuffers//:runtime_cc",
],
)
tflite_cc_library_with_c_headers_test(
name = "xnnpack_plugin",
srcs = ["xnnpack_plugin.cc"],
hdrs = ["xnnpack_plugin.h"],
compatible_with = get_compatible_with_portable(),
visibility = [
"//tensorflow/lite:__subpackages__",
] + xnnpack_plugin_visibility_allowlist(),
deps = [
":delegate_plugin",
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/delegates/xnnpack:xnnpack_delegate",
],
)
cc_test(
name = "xnnpack_plugin_test",
srcs = ["xnnpack_plugin_test.cc"],
deps = [
":xnnpack_plugin",
"//tensorflow/lite/acceleration/configuration:configuration_fbs",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/delegates/xnnpack:xnnpack_delegate",
"@com_google_googletest//:gtest_main",
"@flatbuffers//:runtime_cc",
"@pthreadpool",
],
)
tflite_cc_library_with_c_headers_test(
name = "stable_delegate",
hdrs = ["stable_delegate.h"],
compatible_with = get_compatible_with_portable(),
deps = [
"//tensorflow/lite/core/acceleration/configuration/c:delegate_plugin",
],
)
# Commented out under the (b/279852433) because caused an error in the OSS
# TODO(zhurakovskyi): Uncomment when fixed.
#
# copybara:uncomment_begin
# # This rule invokes the "flatcc" FlatBuffer C API compiler to generate the sources
# # use by the ":configuration_c_fbs" C library rule below.
# genrule(
# name = "configuration_c_fbs_gen",
# srcs = ["//tensorflow/lite/acceleration/configuration:configuration.fbs"],
# outs = [
# "configuration_builder.h",
# "configuration_reader.h",
# ],
# cmd = "$(location //third_party/flatcc:flatcc) -o$(RULEDIR) --builder --reader $(SRCS)",
# tools = ["//third_party/flatcc"],
# # Currently this only enables the API for _building_ configuration flatbuffer objects,
# # not the APIs for reading them, verifying them, or converting them to/from JSON.
# # [If you need to enable those, replace the two lines above with the following
# # outs = ["configuration_builder.h", "configuration_reader.h", "configuration_verifier.h",
# # "configuration_json_parser.h", "configuration_json_printer.h"],
# # cmd = "$(location //third_party/flatcc:flatcc) -o$(RULEDIR) " +
# # "--builder --reader --verifier --json $(SRCS)",
# # and then in the rule below -- or preferably in a separate target --
# # add the additional header files in "hdrs" and fix the dependencies.]
# )
#
# # This rule defines a C library containing the Flatbuffer-generated C API for constructing objects
# # using the FlatBuffer schema generated from tensorflow/lite/acceleration/configuration/configuration.proto,
# # which defines the 'TFLiteSettings' FlatBuffer table and related types.
# tflite_cc_library_with_c_headers_test(
# name = "configuration_c_fbs",
# hdrs = [
# "configuration_builder.h",
# "configuration_reader.h",
# ],
# deps = ["//third_party/flatcc:runtime"],
# )
#
# build_test(
# name = "configuration_c_fbs_build_test",
# targets = [
# ":configuration_c_fbs",
# ],
# )
# copybara:uncomment_end
@@ -0,0 +1,144 @@
/* Copyright 2021 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.
==============================================================================*/
// WARNING: Users of TensorFlow Lite should not include this file directly,
// but should instead include
// "third_party/tensorflow/lite/acceleration/configuration/c/delegate_plugin.h".
// Only the TensorFlow Lite implementation itself should include this file
// directly.
#ifndef TENSORFLOW_LITE_CORE_ACCELERATION_CONFIGURATION_C_DELEGATE_PLUGIN_H_
#define TENSORFLOW_LITE_CORE_ACCELERATION_CONFIGURATION_C_DELEGATE_PLUGIN_H_
/// C API types for TF Lite delegate plugins.
// clang-format off
// NOLINTBEGIN(whitespace/line_length)
/// \note Users of TensorFlow Lite should use
/// \code
/// #include "tensorflow/lite/acceleration/configuration/c/delegate_plugin.h"
/// \endcode
/// to access the APIs documented on this page.
// NOLINTEND(whitespace/line_length)
// clang-format on
#include "tensorflow/lite/core/c/common.h"
#ifdef __cplusplus
extern "C" {
#endif
// clang-format off
// NOLINTBEGIN(whitespace/line_length)
/** \defgroup delegate_plugin lite/acceleration/configuration/c/delegate_plugin.h
* @{
*/
// NOLINTEND(whitespace/line_length)
// clang-format on
/// Type of delegate creation function used to allocate and construct a
/// delegate.
///
/// The `tflite_settings` parameter passed to the delegate creation function
/// should be a pointer to a FlatBuffer table object of type
/// `tflite::TFLiteSettings`. We use `const void *` here rather than `const
/// tflite::TFLiteSettings*` since this is a C API so we don't want to directly
/// reference C++ types such as `tflite::TFLiteSettings`. But note that this
/// address should point to the 'parsed' FlatBuffer object, not the raw byte
/// buffer. (Note that 'parsing' FlatBuffers is very cheap, it's just an offset
/// load.)
///
/// If you are using the FlatBuffers C API, then you can alternatively pass
/// in a value of type `tflite_TFLiteSettings_table_t`, which is a typedef for
/// `const struct tflite_TFLiteSettings_table*` -- that is the corresponding
/// type for the 'parsed' FlatBuffer object in the FlatBuffers C API.
///
/// Ownership of the `tflite_settings` flatbuffer remains with the caller.
/// The caller of a delegate creation function may end the lifetime of the
/// `tflite_settings` FlatBuffer immediately after the call to the function.
/// So the delegate creation function should ensure that any settings that the
/// delegate may need to reference later, after the delegate has been
/// constructed, are copied from the FlatBuffer into storage owned by the
/// delegate.
typedef TfLiteDelegate *TfLiteDelegatePluginCreateFunc(
const void *tflite_settings);
/// Type of function to destroy and deallocate a delegate.
/// The delegate argument must have been created with the corresponding
/// create function from the same delegate plugin.
typedef void TfLiteDelegatePluginDestroyFunc(TfLiteDelegate *);
/// Type of function to return an error code for the last delegate operation.
/// The delegate argument must have been created with the corresponding
/// create function from the same delegate plugin.
typedef int TfLiteDelegatePluginGetDelegateErrnoFunc(TfLiteDelegate *);
/// Struct to hold all the methods for a delegate plugin.
typedef struct TfLiteDelegatePlugin {
/// Function to allocate and construct a delegate.
TfLiteDelegatePluginCreateFunc *create;
/// Function to deallocate a delegate.
TfLiteDelegatePluginDestroyFunc *destroy;
/// Function to return an error code for the last delegate operation.
TfLiteDelegatePluginGetDelegateErrnoFunc *get_delegate_errno;
} TfLiteDelegatePlugin;
// The following block guarded by TFLITE_USE_OPAQUE_DELEGATE has the exact same
// functionality as the concrete types above but only uses truly opaque types.
// Note that it has to be an addition along with the concrete types at this
// point because the in some cases both types are used together in a same build
// target. e.g. TFLite-in-Play Services initialization context.
#if TFLITE_USE_OPAQUE_DELEGATE
/// Same as TfLiteDelegatePluginCreateFunc but uses truly opaque types.
typedef TfLiteOpaqueDelegateStruct *TfLiteOpaqueDelegatePluginCreateFunc(
const void *tflite_settings);
/// Same as TfLiteDelegatePluginDestroyFunc but uses truly opaque types.
typedef void TfLiteOpaqueDelegatePluginDestroyFunc(
TfLiteOpaqueDelegateStruct *delegate);
/// Same as TfLiteDelegatePluginGetDelegateErrnoFunc but uses truly opaque
/// types.
typedef int TfLiteOpaqueDelegatePluginGetDelegateErrnoFunc(
TfLiteOpaqueDelegateStruct *delegate);
/// Same as TfLiteDelegatePlugin but uses truly opaque types.
typedef struct TfLiteOpaqueDelegatePlugin {
TfLiteOpaqueDelegatePluginCreateFunc *create;
TfLiteOpaqueDelegatePluginDestroyFunc *destroy;
TfLiteOpaqueDelegatePluginGetDelegateErrnoFunc *get_delegate_errno;
} TfLiteOpaqueDelegatePlugin;
#else
typedef TfLiteDelegatePluginCreateFunc TfLiteOpaqueDelegatePluginCreateFunc;
typedef TfLiteDelegatePluginDestroyFunc TfLiteOpaqueDelegatePluginDestroyFunc;
typedef TfLiteDelegatePluginGetDelegateErrnoFunc
TfLiteOpaqueDelegatePluginGetDelegateErrnoFunc;
typedef TfLiteDelegatePlugin TfLiteOpaqueDelegatePlugin;
#endif // TFLITE_USE_OPAQUE_DELEGATE
/** @} */
#ifdef __cplusplus
}; // extern "C"
#endif
#endif // TENSORFLOW_LITE_CORE_ACCELERATION_CONFIGURATION_C_DELEGATE_PLUGIN_H_
@@ -0,0 +1,68 @@
/* Copyright 2021 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 file implements the Delegate Plugin for the GPU Delegate.
#include "tensorflow/lite/core/acceleration/configuration/c/gpu_plugin.h"
#include <memory>
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/acceleration/configuration/gpu_plugin.h"
#include "tensorflow/lite/core/acceleration/configuration/c/delegate_plugin.h"
#include "tensorflow/lite/core/c/common.h"
#if TFLITE_SUPPORTS_GPU_DELEGATE
#include "tensorflow/lite/delegates/gpu/delegate.h"
#elif defined(REAL_IPHONE_DEVICE)
#include "tensorflow/lite/delegates/gpu/metal_delegate.h"
#endif
extern "C" {
static TfLiteDelegate* CreateDelegate(const void* settings) {
const ::tflite::TFLiteSettings* tflite_settings =
static_cast<const ::tflite::TFLiteSettings*>(settings);
tflite::delegates::GpuPlugin gpu_plugin(*tflite_settings);
#if TFLITE_SUPPORTS_GPU_DELEGATE
return TfLiteGpuDelegateV2Create(&gpu_plugin.Options());
#elif defined(REAL_IPHONE_DEVICE)
return TFLGpuDelegateCreate(&gpu_plugin.Options());
#else
return nullptr;
#endif
}
static void DestroyDelegate(TfLiteDelegate* delegate) {
#if TFLITE_SUPPORTS_GPU_DELEGATE
TfLiteGpuDelegateV2Delete(delegate);
#elif defined(REAL_IPHONE_DEVICE)
TFLGpuDelegateDelete(delegate);
#endif
}
static int DelegateErrno(TfLiteDelegate* from_delegate) { return 0; }
static constexpr TfLiteDelegatePlugin kPluginCApi{
CreateDelegate,
DestroyDelegate,
DelegateErrno,
};
const TfLiteDelegatePlugin* TfLiteGpuDelegatePluginCApi() {
return &kPluginCApi;
}
} // extern "C"
@@ -0,0 +1,69 @@
/* Copyright 2021 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.
==============================================================================*/
// WARNING: Users of TensorFlow Lite should not include this file directly, but
// should instead include
// "third_party/tensorflow/lite/acceleration/configuration/c/gpu_plugin.h".
// Only the TensorFlow Lite implementation itself should include this file
// directly.
#ifndef TENSORFLOW_LITE_CORE_ACCELERATION_CONFIGURATION_C_GPU_PLUGIN_H_
#define TENSORFLOW_LITE_CORE_ACCELERATION_CONFIGURATION_C_GPU_PLUGIN_H_
/// This header file is for the delegate plugin for GPU.
///
/// For the C++ delegate plugin interface, the GPU delegate plugin is added to
/// the `DelegatePluginRegistry` by the side effect of a constructor for a
/// static object, so there's no public API needed for this plugin, other than
/// the API of `tflite::delegates::DelegatePluginRegistry`s, which is declared
/// in delegate_registry.h.
///
/// But to provide a C API to access the GPU delegate plugin, we do expose
/// some functions, which are declared below.
///
// clang-format off
// NOLINTBEGIN(whitespace/line_length)
/// \note Users of TensorFlow Lite should use
/// \code
/// #include "tensorflow/lite/acceleration/configuration/c/gpu_plugin.h"
/// \endcode
/// to access the APIs documented on this page.
// NOLINTEND(whitespace/line_length)
// clang-format on
#include "tensorflow/lite/core/acceleration/configuration/c/delegate_plugin.h"
#ifdef __cplusplus
extern "C" {
#endif
// clang-format off
// NOLINTBEGIN(whitespace/line_length)
/** \defgroup gpu_plugin lite/acceleration/configuration/c/gpu_plugin.h
* @{
*/
// NOLINTEND(whitespace/line_length)
// clang-format on
/// C API for the GPU delegate plugin.
/// Returns a pointer to a statically allocated table of function pointers.
const TfLiteDelegatePlugin* TfLiteGpuDelegatePluginCApi();
/** @} */
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_LITE_CORE_ACCELERATION_CONFIGURATION_C_GPU_PLUGIN_H_
@@ -0,0 +1,68 @@
/* Copyright 2021 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.
==============================================================================*/
// Some very simple unit tests of the C API Delegate Plugin for the
// GPU Delegate.
#include "tensorflow/lite/core/acceleration/configuration/c/gpu_plugin.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "tensorflow/lite/acceleration/configuration/configuration_generated.h"
#include "tensorflow/lite/core/c/common.h"
namespace tflite {
class GpuTest : public testing::Test {
public:
void SetUp() override {
// Construct a FlatBuffer that contains
// TFLiteSettings { GpuSettings { foo1 : bar1, foo2 : bar2, ...} }.
GPUSettingsBuilder gpu_settings_builder(flatbuffer_builder_);
flatbuffers::Offset<GPUSettings> gpu_settings =
gpu_settings_builder.Finish();
// gpu_settings_builder.add_foo1(bar1);
// gpu_settings_builder.add_foo2(bar2);
TFLiteSettingsBuilder tflite_settings_builder(flatbuffer_builder_);
tflite_settings_builder.add_gpu_settings(gpu_settings);
flatbuffers::Offset<TFLiteSettings> tflite_settings =
tflite_settings_builder.Finish();
flatbuffer_builder_.Finish(tflite_settings);
settings_ = flatbuffers::GetRoot<TFLiteSettings>(
flatbuffer_builder_.GetBufferPointer());
}
~GpuTest() override {}
protected:
// settings_ points into storage owned by flatbuffer_builder_.
flatbuffers::FlatBufferBuilder flatbuffer_builder_;
const TFLiteSettings *settings_;
};
TEST_F(GpuTest, CanCreateAndDestroyDelegate) {
TfLiteDelegate *delegate = TfLiteGpuDelegatePluginCApi()->create(settings_);
EXPECT_NE(delegate, nullptr);
TfLiteGpuDelegatePluginCApi()->destroy(delegate);
}
TEST_F(GpuTest, CanGetDelegateErrno) {
TfLiteDelegate *delegate = TfLiteGpuDelegatePluginCApi()->create(settings_);
int error_number =
TfLiteGpuDelegatePluginCApi()->get_delegate_errno(delegate);
EXPECT_EQ(error_number, 0);
TfLiteGpuDelegatePluginCApi()->destroy(delegate);
}
} // namespace tflite

Some files were not shown because too many files have changed in this diff Show More