開始使用 LiteRT

本指南將說明在裝置端執行 LiteRT 模型的程序 並根據輸入資料做出預測使用 LiteRT 使用靜態圖形排序和自訂 (無動態) 的解譯器 盡可能降低負載、初始化和執行延遲時間。

LiteRT 推論通常遵循以下步驟:

  1. 載入模型:將 .tflite 模型載入記憶體,其中包含 定義模型執行圖

  2. 轉換資料:將輸入資料轉換為預期格式, 維度。模型的原始輸入資料通常和輸入內容不相符 也就是模型預期的資料格式舉例來說,以某個 圖像或變更圖片格式,以便與模型相容

  3. 執行推論:執行 LiteRT 模型來進行預測。這個 您需要使用 LiteRT API 來執行模型這牽涉到 例如建構解譯器和分配張量

  4. 解讀輸出:以有意義的方式解讀輸出張量 以打造實用又實用的應用程式舉例來說,模型可能只會傳回 機率清單您可以自行將可能性對應到 以及設定輸出內容的格式

本指南說明如何存取 LiteRT 直譯器,並執行 以及使用 C++、Java 和 Python 進行推論

支援的平台

TensorFlow 推論 API 適用於最常見的行動和嵌入式 平台 (如 AndroidiOSLinux) 及 使用多種程式設計語言

在大多數情況下,API 設計反映出效能偏好而非 相關單位會如何運用資料,並讓他們覺得自己 獲得充分告知,且能夠針對該使用方式表示同意LiteRT 是專為在小型裝置上快速推論而設計,因此 API 能避免 為方便取用

LiteRT API 能讓您載入模型、動態饋給輸入內容 擷取推論輸出內容

Android 平台

在 Android 上,可使用 Java 或 C++ API 執行 LiteRT 推論。 Java API 不僅方便,而且可直接在 Android 中使用 活動類別。C++ API 提供更多彈性和速度,但可能會需要 編寫 JNI 包裝函式,在 Java 和 C++ 層之間移動資料。

詳情請參閱 C++Java 區段,或 請按照 Android 快速入門導覽課程操作。

iOS 平台

iOS 裝置支援 LiteRT SwiftObjective-C iOS 程式庫您也可以使用 C API 進行這項操作。

詳情請參閱 SwiftObjective-CC API ,或按照 iOS 快速入門導覽課程的說明操作。

Linux 平台

在 Linux 平台上,您可以使用下列提供的 LiteRT API 執行推論: C++

載入並執行模型

載入及執行 LiteRT 模型的步驟如下:

  1. 將模型載入記憶體。
  2. 根據現有模型建構 Interpreter
  3. 設定輸入張量值。
  4. 叫用推論。
  5. 輸出張量值。

Android (Java)

用於透過 LiteRT 執行推論的 Java API 主要用於 ,因此可用做 Android 程式庫依附元件: com.google.ai.edge.litert

在 Java 中,您將使用 Interpreter 類別載入模型和硬碟模型 推論在許多情況下,這可能就是您需要的唯一 API。

您可以使用 FlatBuffers (.tflite) 檔案初始化 Interpreter

public Interpreter(@NotNull File modelFile);

或是使用 MappedByteBuffer

public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer);

無論是哪種情況,您都必須提供有效的 LiteRT 模型,或是 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 方法使用三個引數:

  • 輸入內容:將簽章中的輸入名稱對應至輸入項目 物件。

  • 輸出:對應從簽名到輸出的輸出對應 資料。

  • 簽名名稱 (選填):簽名名稱 (如有 單一特徵碼)。

在模型沒有已定義的特徵碼的情況下,另一種執行推論的方式。 只要呼叫 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 會將輸出張量的索引對應到相應的 輸出資料

在這兩種情況下,張量索引應對應至您提供給 LiteRT Converter。注意事項 input 中的張量順序必須與提供給 LiteRT 的順序相符 轉換者。

Interpreter 類別也提供便利的函式, 使用作業名稱的任何模型輸入或輸出索引:

public int getInputIndex(String opName);
public int getOutputIndex(String opName);

如果 opName 不是模型中的有效作業,則會擲回 IllegalArgumentException

此外請注意,Interpreter 擁有資源。為避免記憶體流失, 使用以下條件時,必須先釋出資源:

interpreter.close();

如需使用 Java 的專案範例,請參閱 Android 物件偵測範例 app

支援的資料類型

如要使用 LiteRT,輸入和輸出張量的資料類型必須是 下列原始類型:

  • float
  • int
  • long
  • byte

也支援 String 類型,但其編碼方式與 原始類型具體來說,Tensor 的形狀會決定數字的 以及 Tensor 中字串的排列方式,每個元素本身都是 變數長度字串因此,Tensor 的 (位元組) 大小不能 只根據形狀和類型計算,因此字串不可 做為單一固定 ByteBuffer 引數提供。

如果使用其他資料類型 (包括 IntegerFloat 等方塊類型), 系統將擲回 IllegalArgumentException

輸入

每個輸入都必須是支援該欄位的陣列或多維陣列 原始類型,或適當大小的原始 ByteBuffer。如果輸入 陣列或多維陣列,相關輸入張量就會 在推論期間,自動調整為陣列的尺寸。如果輸入 ByteBuffer 而言,呼叫端應先手動調整關聯的輸入內容大小 張量 (透過 Interpreter.resizeInput()) 執行推論再執行推論作業。

使用 ByteBuffer 時,建議使用直接位元組緩衝區,因為這樣能 Interpreter,避免不必要的副本。如果 ByteBuffer 是直接位元組 緩衝區,順序必須是 ByteOrder.nativeOrder()。在使用 就必須保持不變,直到模型推論結束為止。

輸出

每個輸出內容應為支援項目陣列或多維陣列 原始型別,或適當大小的 ByteBuffer。請注意 會有動態輸出,而輸出張量的形狀可能會因以下因素而異 輸入內容使用現有的現有資源 Java ference API,而預定的擴充功能就能做到這一點。

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...
}

iOS (Objective-C)

Objective-C API 可從 Cocoapods 的 LiteRTObjC Pod 取得。

首先,您需要匯入 TensorFlowLiteObjC 模組。

@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++

用 LiteRT 執行推論的 C++ API 與 Android、iOS、 和 Linux 平台iOS 上的 C++ API 只能在使用 bazel 時使用。

在 C++ 中,模型會儲存在 FlatBufferModel 類別。 會封裝 LiteRT 模型,且您可以透過幾種不同方式 視模型儲存位置而定:

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()

搭配 C++ 使用的 LiteRT 最簡單的用法如下:

// 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 needed.
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

執行推論的 Python API 會使用 Interpreter:載入模型並 執行推論

安裝 LiteRT 套件:

$ python3 -m pip install ai-edge-litert

匯入 LiteRT 翻譯工具

from ai_edge_litert.interpreter import Interpreter
Interpreter = Interpreter(model_path=args.model.file)

以下範例說明如何使用 Python 解譯器載入 FlatBuffers (.tflite) 檔案,並以隨機輸入資料執行推論:

如果您是透過已定義的 module 轉換,建議採用這個範例 SignatureDef。

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 LiteRT model in LiteRT Interpreter
from ai_edge_litert.interpreter import Interpreter
interpreter = 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 LiteRT model and allocate tensors.
from ai_edge_litert.interpreter import Interpreter
interpreter = Interpreter(TFLITE_FILE_PATH)
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 檔案之外,您可以 可以將您的程式碼與 LiteRT 編譯器 ,以便將 Keras 模型轉換為 LiteRT 格式,然後執行 推論:

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 LiteRT format
converter = tf.lite.TFLiteConverter.from_keras_model(tf.keras.models.Model(inputs=[img], outputs=[out]))
tflite_model = converter.convert()

# Load the LiteRT model and allocate tensors.
from ai_edge_litert.interpreter import Interpreter
interpreter = Interpreter(model_content=tflite_model)
interpreter.allocate_tensors()

# Continue to get tensors and so forth, as shown above...

如需更多 Python 程式碼範例,請參閱 label_image.py

使用動態形狀模型執行推論

如要執行採用動態輸入形狀的模型,請調整輸入形狀的大小 再執行推論否則,Tensorflow 模型中的 None 形狀會 在 LiteRT 模型中,會替換為 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 LiteRT model in LiteRT Interpreter
from ai_edge_litert.interpreter import Interpreter
interpreter = 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()