「推論」一詞是指在裝置端執行 TensorFlow Lite 模型的程序,以便根據輸入資料進行預測。如要使用 TensorFlow Lite 模型執行推論,您必須透過解譯器執行模型。TensorFlow Lite 解譯器旨在運作快速又快速。 解譯器使用靜態圖形排序和自訂 (無動態) 記憶體分配器,將負載、初始化和執行作業的延遲時間降至最低。
本頁面說明如何存取 TensorFlow Lite 解譯器並使用 C++、Java 和 Python 執行推論,以及每個支援平台的其他資源連結。
重要概念
TensorFlow Lite 推論通常執行下列步驟:
載入模型
您必須將
.tflite
模型載入記憶體中,記憶體中會包含模型的執行圖。轉換資料
模型的原始輸入資料通常與模型預期的輸入資料格式不符。舉例來說,您可能需要調整圖片大小或變更圖片格式,才能與模型相容。
執行推論
這個步驟涉及使用 TensorFlow Lite API 執行模型。包含一些步驟,例如建構解譯器和配置張量,如以下各節所述。
解讀輸出內容
當您收到模型推論產生的結果時,必須以適合應用程式中的有意義的方式解讀張量。
舉例來說,模型可能只會傳回機率清單。您也可以選擇將機率對應至相關類別,並向使用者顯示。
支援的平台
TensorFlow 推論 API 適用於最常見的行動/內嵌平台 (例如 Android、iOS 和 Linux),並且提供多種語言版本。
在大多數情況下,API 設計反映的是效能比易用性更想要的程度。TensorFlow Lite 專為在小型裝置上快速推論而設計,因此 API 會為了方便起見,盡量避免執行不必要的複製。同樣地,TensorFlow API 的一致性並非明確的目標,語言之間也會出現一些差異。
TensorFlow Lite API 適用於所有程式庫,可讓您載入模型、動態饋給輸入及擷取推論輸出內容。
Android 平台
在 Android 上,您可以使用 Java 或 C++ API 執行 TensorFlow Lite 推論。Java API 提供了便利,可以直接在 Android Activity 類別中使用。C++ API 提供更多彈性和速度,但您可能需要編寫 JNI 包裝函式,才能在 Java 和 C++ 層之間移動資料。
請參閱下文,進一步瞭解如何使用 C++ 和 Java,或參閱 Android 快速入門導覽課程,查看教學課程和程式碼範例。
TensorFlow Lite Android 包裝函式程式碼產生器
如果是以中繼資料強化 TensorFlow Lite 模型,開發人員可以使用 TensorFlow Lite Android 包裝函式程式碼產生器建立平台專屬的包裝函式程式碼。包裝函式程式碼不必在 Android 上直接與 ByteBuffer
互動,開發人員可以改為透過 Bitmap
和 Rect
等類型物件與 TensorFlow Lite 模型互動。詳情請參閱 TensorFlow Lite Android 包裝函式程式碼產生器。
iOS 平台
在 iOS 上,TensorFlow Lite 適用於以 Swift 和 Objective-C 編寫的原生 iOS 程式庫。您也可以直接在 Objective-C 程式碼中使用 C API。
請參閱以下內容,進一步瞭解如何使用 Swift、Objective-C 和 C API,或是參閱 iOS 快速入門導覽課程取得教學課程和範例程式碼。
Linux 平台
在 Linux 平台 (包括 Raspberry Pi) 上,您可以使用 C++ 和 Python 提供的 TensorFlow Lite API 執行推論,如以下各節所示。
執行模型
執行 TensorFlow Lite 模型需要幾個簡單步驟:
- 將模型載入記憶體。
- 根據現有模型建構
Interpreter
。 - 設定輸入張量值。(如果不需要預先定義的大小,可視需要調整輸入張量大小)。
- 叫用推論。
- 讀取輸出張量值。
以下各節將說明如何以各種語言執行這些步驟。
在 Java 中載入並執行模型
平台:Android
使用 TensorFlow Lite 執行推論的 Java API 主要是為搭配 Android 使用,因此可做為 Android 程式庫依附元件使用:org.tensorflow:tensorflow-lite
。
在 Java 中,您會使用 Interpreter
類別載入模型及驅動模型推論。在許多情況下,您可能只需要使用這個 API。
您可以使用 .tflite
檔案初始化 Interpreter
:
public Interpreter(@NotNull File modelFile);
或使用 MappedByteBuffer
:
public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer);
無論是哪種情況,您都必須提供有效的 TensorFlow Lite 模型,否則 API 會擲回 IllegalArgumentException
。如果您使用 MappedByteBuffer
初始化 Interpreter
,在整個 Interpreter
生命週期內,這個值不得維持不變。
如要在模型上執行推論,建議您使用簽章 - 適用於由 Tensorflow 2.5 轉換的模型
try (Interpreter interpreter = new Interpreter(file_of_tensorflowlite_model)) {
Map<String, Object> inputs = new HashMap<>();
inputs.put("input_1", input1);
inputs.put("input_2", input2);
Map<String, Object> outputs = new HashMap<>();
outputs.put("output_1", output1);
interpreter.runSignature(inputs, outputs, "mySignature");
}
runSignature
方法使用三個引數:
「Inputs」:將簽名中的輸入名稱輸入內容對應至輸入物件。
輸出:對簽名中的輸出名稱與輸出資料進行對應。
Signature Name (選填):簽章名稱 (如果模型有單一簽名,則可留空)。
在模型沒有已定義的簽名時,另一種執行推論的方式。只要呼叫 Interpreter.run()
即可。例如:
try (Interpreter interpreter = new Interpreter(file_of_a_tensorflowlite_model)) {
interpreter.run(input, output);
}
run()
方法只需要一個輸入內容,且只會傳回一個輸出內容。因此,如果模型有多個輸入或多個輸出內容,請改用:
interpreter.runForMultipleInputsOutputs(inputs, map_of_indices_to_outputs);
在此情況下,inputs
中的每個項目都會對應至輸入張量,且 map_of_indices_to_outputs
會將輸出張量索引對應至對應的輸出資料。
在這兩種情況下,張量索引應與您建立模型時提供給 TensorFlow Lite Converter 的值相對應。請注意,input
中的張量順序必須與提供給 TensorFlow Lite 轉換工具的順序相符。
Interpreter
類別也提供便利的函式,方便您使用作業名稱取得任何模型輸入或輸出內容的索引:
public int getInputIndex(String opName);
public int getOutputIndex(String opName);
如果 opName
不是模型中的有效作業,就會擲回 IllegalArgumentException
。
另請注意,Interpreter
擁有資源。為避免記憶體流失,使用資源後,必須釋出資源,方法如下:
interpreter.close();
如需使用 Java 的專案範例,請參閱 Android 圖片分類範例。
支援的資料類型 (Java)
如要使用 TensorFlow Lite,輸入和輸出張量的資料類型必須是以下其中一種原始類型:
float
int
long
byte
此外,系統也支援 String
類型,但其編碼方式與原始類型不同。具體來說,字串的形狀決定了 Tensor 中的字串數量和排列方式,而每個元素本身都是變數長度字串。這表示無法單獨根據形狀和類型計算 Tensor 的 (位元組) 大小,因此也無法以單一固定 ByteBuffer
引數提供字串。
如果使用其他資料類型 (包括 Integer
和 Float
等方塊類型),系統會擲回 IllegalArgumentException
。
輸入
每個輸入內容都應為支援原始類型的陣列或多維陣列,或是適當大小的原始 ByteBuffer
。如果輸入內容是陣列或多維度陣列,相關聯的輸入張量會在推論期間間接調整為陣列的尺寸。如果輸入內容為 ByteBuffer,則呼叫端必須先透過 Interpreter.resizeInput()
手動調整關聯輸入張量,然後再執行推論。
使用 ByteBuffer
時,建議使用直接位元組緩衝區,因為這可讓 Interpreter
避免不必要的複製。如果 ByteBuffer
是直接位元組緩衝區,則順序必須為 ByteOrder.nativeOrder()
。將模型用於模型推論後,在模型推論完成前,這個值必須保持不變。
輸出
每個輸出都應為支援基本類型的陣列或多維陣列,或是適當大小的 ByteBuffer。請注意,部分模型具有動態輸出,其中輸出張量的形狀可能因輸入而異。使用現有的 Java Inference API 處理這種情況並不直接,但預定的擴充功能可以做到。
在 Swift 中載入及執行模型
平台:iOS
Swift API 位於 Cocoapods 的 TensorFlowLiteSwift
Pod 中。
首先,您必須匯入 TensorFlowLite
模組。
import TensorFlowLite
// Getting model path
guard
let modelPath = Bundle.main.path(forResource: "model", ofType: "tflite")
else {
// Error handling...
}
do {
// Initialize an interpreter with the model.
let interpreter = try Interpreter(modelPath: modelPath)
// Allocate memory for the model's input `Tensor`s.
try interpreter.allocateTensors()
let inputData: Data // Should be initialized
// input data preparation...
// Copy the input data to the input `Tensor`.
try self.interpreter.copy(inputData, toInputAt: 0)
// Run inference by invoking the `Interpreter`.
try self.interpreter.invoke()
// Get the output `Tensor`
let outputTensor = try self.interpreter.output(at: 0)
// Copy output to `Data` to process the inference results.
let outputSize = outputTensor.shape.dimensions.reduce(1, {x, y in x * y})
let outputData =
UnsafeMutableBufferPointer<Float32>.allocate(capacity: outputSize)
outputTensor.data.copyBytes(to: outputData)
if (error != nil) { /* Error handling... */ }
} catch error {
// Error handling...
}
在 Objective-C 中載入並執行模型
平台:iOS
Objective-C API 可在 Cocoapods 的 TensorFlowLiteObjC
Pod 中找到。
首先,您必須匯入 TensorFlowLite
模組。
@import TensorFlowLite;
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"model"
ofType:@"tflite"];
NSError *error;
// Initialize an interpreter with the model.
TFLInterpreter *interpreter = [[TFLInterpreter alloc] initWithModelPath:modelPath
error:&error];
if (error != nil) { /* Error handling... */ }
// Allocate memory for the model's input `TFLTensor`s.
[interpreter allocateTensorsWithError:&error];
if (error != nil) { /* Error handling... */ }
NSMutableData *inputData; // Should be initialized
// input data preparation...
// Get the input `TFLTensor`
TFLTensor *inputTensor = [interpreter inputTensorAtIndex:0 error:&error];
if (error != nil) { /* Error handling... */ }
// Copy the input data to the input `TFLTensor`.
[inputTensor copyData:inputData error:&error];
if (error != nil) { /* Error handling... */ }
// Run inference by invoking the `TFLInterpreter`.
[interpreter invokeWithError:&error];
if (error != nil) { /* Error handling... */ }
// Get the output `TFLTensor`
TFLTensor *outputTensor = [interpreter outputTensorAtIndex:0 error:&error];
if (error != nil) { /* Error handling... */ }
// Copy output to `NSData` to process the inference results.
NSData *outputData = [outputTensor dataWithError:&error];
if (error != nil) { /* Error handling... */ }
在 Objective-C 程式碼中使用 C API
Objective-C API 目前不支援委派功能。如要搭配使用委派與 Objective-C 程式碼,您必須直接呼叫基礎 C API。
#include "tensorflow/lite/c/c_api.h"
TfLiteModel* model = TfLiteModelCreateFromFile([modelPath UTF8String]);
TfLiteInterpreterOptions* options = TfLiteInterpreterOptionsCreate();
// Create the interpreter.
TfLiteInterpreter* interpreter = TfLiteInterpreterCreate(model, options);
// Allocate tensors and populate the input tensor data.
TfLiteInterpreterAllocateTensors(interpreter);
TfLiteTensor* input_tensor =
TfLiteInterpreterGetInputTensor(interpreter, 0);
TfLiteTensorCopyFromBuffer(input_tensor, input.data(),
input.size() * sizeof(float));
// Execute inference.
TfLiteInterpreterInvoke(interpreter);
// Extract the output tensor data.
const TfLiteTensor* output_tensor =
TfLiteInterpreterGetOutputTensor(interpreter, 0);
TfLiteTensorCopyToBuffer(output_tensor, output.data(),
output.size() * sizeof(float));
// Dispose of the model and interpreter objects.
TfLiteInterpreterDelete(interpreter);
TfLiteInterpreterOptionsDelete(options);
TfLiteModelDelete(model);
在 C++ 中載入並執行模型
平台:Android、iOS 和 Linux
在 C++ 中,模型會儲存在 FlatBufferModel
類別中。它會封裝 TensorFlow Lite 模型,您可以根據模型儲存位置,以幾種不同的方式建構模型:
class FlatBufferModel {
// Build a model based on a file. Return a nullptr in case of failure.
static std::unique_ptr<FlatBufferModel> BuildFromFile(
const char* filename,
ErrorReporter* error_reporter);
// Build a model based on a pre-loaded flatbuffer. The caller retains
// ownership of the buffer and should keep it alive until the returned object
// is destroyed. Return a nullptr in case of failure.
static std::unique_ptr<FlatBufferModel> BuildFromBuffer(
const char* buffer,
size_t buffer_size,
ErrorReporter* error_reporter);
};
現在,您已將模型設為 FlatBufferModel
物件,接著就能使用 Interpreter
執行該模型。單一 FlatBufferModel
可由多個 Interpreter
同時使用。
以下程式碼片段顯示 Interpreter
API 的重要部分。注意事項:
- 張量是以整數表示,以避免字串比較 (以及任何對字串程式庫的固定依附元件)。
- 無法透過並行執行緒存取解譯器。
- 您必須在調整張量後立即呼叫
AllocateTensors()
,觸發輸入和輸出張量的記憶體配置。
TensorFlow Lite 與 C++ 的最簡單用法如下所示:
// Load the model
std::unique_ptr<tflite::FlatBufferModel> model =
tflite::FlatBufferModel::BuildFromFile(filename);
// Build the interpreter
tflite::ops::builtin::BuiltinOpResolver resolver;
std::unique_ptr<tflite::Interpreter> interpreter;
tflite::InterpreterBuilder(*model, resolver)(&interpreter);
// Resize input tensors, if desired.
interpreter->AllocateTensors();
float* input = interpreter->typed_input_tensor<float>(0);
// Fill `input`.
interpreter->Invoke();
float* output = interpreter->typed_output_tensor<float>(0);
如需更多程式碼範例,請參閱 minimal.cc
和 label_image.cc
。
在 Python 中載入並執行模型
平台:Linux
用於執行推論的 Python API 通常只需要 tf.lite.Interpreter
來載入模型及執行推論作業。
以下範例說明如何使用 Python 解譯器載入 .tflite
檔案,並以隨機輸入資料執行推論:
如果您是從含有已定義的 SignatureDef 的 SavedModel 轉換,建議參考這個範例。自 TensorFlow 2.5 開始提供
class TestModel(tf.Module):
def __init__(self):
super(TestModel, self).__init__()
@tf.function(input_signature=[tf.TensorSpec(shape=[1, 10], dtype=tf.float32)])
def add(self, x):
'''
Simple method that accepts single input 'x' and returns 'x' + 4.
'''
# Name the output 'result' for convenience.
return {'result' : x + 4}
SAVED_MODEL_PATH = 'content/saved_models/test_variable'
TFLITE_FILE_PATH = 'content/test_variable.tflite'
# Save the model
module = TestModel()
# You can omit the signatures argument and a default signature name will be
# created with name 'serving_default'.
tf.saved_model.save(
module, SAVED_MODEL_PATH,
signatures={'my_signature':module.add.get_concrete_function()})
# Convert the model using TFLiteConverter
converter = tf.lite.TFLiteConverter.from_saved_model(SAVED_MODEL_PATH)
tflite_model = converter.convert()
with open(TFLITE_FILE_PATH, 'wb') as f:
f.write(tflite_model)
# Load the TFLite model in TFLite Interpreter
interpreter = tf.lite.Interpreter(TFLITE_FILE_PATH)
# There is only 1 signature defined in the model,
# so it will return it by default.
# If there are multiple signatures then we can pass the name.
my_signature = interpreter.get_signature_runner()
# my_signature is callable with input as arguments.
output = my_signature(x=tf.constant([1.0], shape=(1,10), dtype=tf.float32))
# 'output' is dictionary with all outputs from the inference.
# In this case we have single output 'result'.
print(output['result'])
如果模型未定義 SignatureDefs 則是另一個範例。
import numpy as np
import tensorflow as tf
# Load the TFLite model and allocate tensors.
interpreter = tf.lite.Interpreter(model_path="converted_model.tflite")
interpreter.allocate_tensors()
# Get input and output tensors.
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
# Test the model on random input data.
input_shape = input_details[0]['shape']
input_data = np.array(np.random.random_sample(input_shape), dtype=np.float32)
interpreter.set_tensor(input_details[0]['index'], input_data)
interpreter.invoke()
# The function `get_tensor()` returns a copy of the tensor data.
# Use `tensor()` in order to get a pointer to the tensor.
output_data = interpreter.get_tensor(output_details[0]['index'])
print(output_data)
如果您不希望將模型載入為預先轉換的 .tflite
檔案,可以將自己的程式碼與 TensorFlow Lite Converter Python API 結合,將 Keras 模型轉換為 TensorFlow Lite 格式,然後執行推論:
import numpy as np
import tensorflow as tf
img = tf.keras.Input(shape=(64, 64, 3), name="img")
const = tf.constant([1., 2., 3.]) + tf.constant([1., 4., 4.])
val = img + const
out = tf.identity(val, name="out")
# Convert to TF Lite format
converter = tf.lite.TFLiteConverter.from_keras_model(tf.keras.models.Model(inputs=[img], outputs=[out]))
tflite_model = converter.convert()
# Load the TFLite model and allocate tensors.
interpreter = tf.lite.Interpreter(model_content=tflite_model)
interpreter.allocate_tensors()
# Continue to get tensors and so forth, as shown above...
如需更多 Python 程式碼範例,請參閱 label_image.py
。
使用動態形狀模型執行推論
如果您想執行含有動態輸入形狀的模型,請在執行推論之前調整輸入形狀大小。否則,Tensorflow 模型中的 None
形狀會由 TFLite 模型中的 1
預留位置取代。
以下範例說明如何在執行不同語言的推論前調整輸入形狀大小。所有範例都假設輸入形狀已定義為 [1/None, 10]
,且需要調整大小為 [3, 10]
。
C++ 範例:
// Resize input tensors before allocate tensors
interpreter->ResizeInputTensor(/*tensor_index=*/0, std::vector<int>{3,10});
interpreter->AllocateTensors();
Python 範例:
# Load the TFLite model in TFLite Interpreter
interpreter = tf.lite.Interpreter(model_path=TFLITE_FILE_PATH)
# Resize input shape for dynamic shape model and allocate tensor
interpreter.resize_tensor_input(interpreter.get_input_details()[0]['index'], [3, 10])
interpreter.allocate_tensors()
# Get input and output tensors.
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
支援作業
TensorFlow Lite 支援一部分的 TensorFlow 運算,但有一些限制。如需作業和限制的完整清單,請參閱 TF Lite 作業頁面。