Thuật ngữ suy luận đề cập đến quá trình thực thi mô hình TensorFlow Lite trên thiết bị để đưa ra dự đoán dựa trên dữ liệu đầu vào. Để thực hiện suy luận với mô hình TensorFlow Lite, bạn phải chạy nó thông qua trình thông dịch . Trình thông dịch TensorFlow Lite được thiết kế gọn gàng và nhanh chóng. Trình thông dịch sử dụng thứ tự đồ thị tĩnh và bộ cấp phát bộ nhớ tùy chỉnh (ít động hơn) để đảm bảo độ trễ tải, khởi tạo và thực thi là tối thiểu.
Trang này mô tả cách truy cập vào trình thông dịch TensorFlow Lite và thực hiện suy luận bằng C++, Java và Python, cùng với các liên kết tới các tài nguyên khác cho từng nền tảng được hỗ trợ .
khái niệm quan trọng
Suy luận TensorFlow Lite thường tuân theo các bước sau:
Đang tải một mô hình
Bạn phải tải mô hình
.tflite
vào bộ nhớ chứa biểu đồ thực thi của mô hình.Chuyển đổi dữ liệu
Dữ liệu đầu vào thô cho mô hình thường không khớp với định dạng dữ liệu đầu vào mà mô hình mong đợi. Ví dụ: bạn có thể cần thay đổi kích thước hình ảnh hoặc thay đổi định dạng hình ảnh để tương thích với kiểu máy.
Chạy suy luận
Bước này liên quan đến việc sử dụng API TensorFlow Lite để thực thi mô hình. Nó bao gồm một vài bước chẳng hạn như xây dựng trình thông dịch và cấp phát tenxơ, như được mô tả trong các phần sau.
Thông dịch đầu ra
Khi bạn nhận được kết quả từ suy luận mô hình, bạn phải diễn giải các tenxơ theo cách có ý nghĩa hữu ích trong ứng dụng của bạn.
Ví dụ, một mô hình có thể chỉ trả về một danh sách các xác suất. Việc lập bản đồ xác suất cho các danh mục có liên quan và trình bày nó cho người dùng cuối của bạn là tùy thuộc vào bạn.
Nền tảng được hỗ trợ
API suy luận TensorFlow được cung cấp cho hầu hết các nền tảng nhúng/di động phổ biến như Android , iOS và Linux , bằng nhiều ngôn ngữ lập trình.
Trong hầu hết các trường hợp, thiết kế API phản ánh ưu tiên về hiệu suất hơn là tính dễ sử dụng. TensorFlow Lite được thiết kế để suy luận nhanh trên các thiết bị nhỏ, vì vậy không có gì ngạc nhiên khi các API cố gắng tránh các bản sao không cần thiết gây bất lợi cho sự thuận tiện. Tương tự, tính nhất quán với các API TensorFlow không phải là một mục tiêu rõ ràng và có thể xảy ra một số khác biệt giữa các ngôn ngữ.
Trên tất cả các thư viện, API TensorFlow Lite cho phép bạn tải các mô hình, cung cấp dữ liệu đầu vào và truy xuất kết quả suy luận.
Nền tảng Android
Trên Android, có thể thực hiện suy luận TensorFlow Lite bằng API Java hoặc C++. Các API Java cung cấp sự tiện lợi và có thể được sử dụng trực tiếp trong các lớp Hoạt động Android của bạn. API C++ cung cấp tính linh hoạt và tốc độ cao hơn, nhưng có thể yêu cầu viết trình bao bọc JNI để di chuyển dữ liệu giữa các lớp Java và C++.
Xem bên dưới để biết chi tiết về cách sử dụng C++ và Java hoặc làm theo phần bắt đầu nhanh của Android để biết mã ví dụ và hướng dẫn.
Trình tạo mã trình bao bọc Android TensorFlow Lite
Đối với mô hình TensorFlow Lite được tăng cường bằng siêu dữ liệu , nhà phát triển có thể sử dụng trình tạo mã trình bao bọc Android TensorFlow Lite để tạo mã trình bao bọc dành riêng cho nền tảng. Mã trình bao bọc loại bỏ nhu cầu tương tác trực tiếp với ByteBuffer
trên Android. Thay vào đó, các nhà phát triển có thể tương tác với mô hình TensorFlow Lite bằng các đối tượng được nhập như Bitmap
và Rect
. Để biết thêm thông tin, vui lòng tham khảo trình tạo mã trình bao bọc Android TensorFlow Lite .
Nền tảng iOS
Trên iOS, TensorFlow Lite khả dụng với các thư viện iOS gốc được viết bằng Swift và Objective-C . Bạn cũng có thể sử dụng API C trực tiếp trong mã Mục tiêu-C.
Xem bên dưới để biết chi tiết về cách sử dụng Swift , Objective-C và C API hoặc làm theo hướng dẫn nhanh về iOS để biết mã ví dụ và hướng dẫn.
Nền tảng Linux
Trên nền tảng Linux (bao gồm cả Raspberry Pi ), bạn có thể chạy suy luận bằng cách sử dụng API TensorFlow Lite có sẵn trong C++ và Python , như được trình bày trong các phần sau.
Chạy mô hình
Chạy mô hình TensorFlow Lite bao gồm một vài bước đơn giản:
- Tải mô hình vào bộ nhớ.
- Xây dựng
Interpreter
dựa trên mô hình có sẵn. - Đặt giá trị tenxơ đầu vào. (Tùy chọn thay đổi kích thước tenxơ đầu vào nếu kích thước được xác định trước không được mong muốn.)
- Gọi suy luận.
- Đọc các giá trị tenxơ đầu ra.
Các phần sau mô tả cách thực hiện các bước này trong mỗi ngôn ngữ.
Tải và chạy một mô hình trong Java
Nền tảng: Android
API Java để chạy suy luận với TensorFlow Lite chủ yếu được thiết kế để sử dụng với Android, do đó, nó có sẵn dưới dạng phụ thuộc thư viện Android: org.tensorflow:tensorflow-lite
.
Trong Java, bạn sẽ sử dụng lớp Interpreter
để tải mô hình và điều khiển suy luận mô hình. Trong nhiều trường hợp, đây có thể là API duy nhất bạn cần.
Bạn có thể khởi tạo Interpreter
bằng tệp .tflite
:
public Interpreter(@NotNull File modelFile);
Hoặc với một MappedByteBuffer
:
public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer);
Trong cả hai trường hợp, bạn phải cung cấp một mô hình TensorFlow Lite hợp lệ hoặc API sẽ ném IllegalArgumentException
. Nếu bạn sử dụng MappedByteBuffer
để khởi tạo một Interpreter
, nó phải không thay đổi trong suốt vòng đời của Interpreter
.
Cách ưu tiên để chạy suy luận trên một mô hình là sử dụng chữ ký - Có sẵn cho các mô hình được chuyển đổi bắt đầu từ 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");
}
Phương thức runSignature
nhận ba đối số:
Đầu vào : ánh xạ cho các đầu vào từ tên đầu vào trong chữ ký tới một đối tượng đầu vào.
Đầu ra : bản đồ để ánh xạ đầu ra từ tên đầu ra trong chữ ký sang dữ liệu đầu ra.
Tên chữ ký [tùy chọn]: Tên chữ ký (Có thể để trống nếu kiểu máy có một chữ ký).
Một cách khác để chạy suy luận khi mô hình không có chữ ký xác định. Đơn giản chỉ cần gọi đến Interpreter.run()
. Ví dụ:
try (Interpreter interpreter = new Interpreter(file_of_a_tensorflowlite_model)) {
interpreter.run(input, output);
}
Phương thức run()
chỉ nhận một đầu vào và chỉ trả về một đầu ra. Vì vậy, nếu mô hình của bạn có nhiều đầu vào hoặc nhiều đầu ra, thay vào đó hãy sử dụng:
interpreter.runForMultipleInputsOutputs(inputs, map_of_indices_to_outputs);
Trong trường hợp này, mỗi mục nhập trong inputs
tương ứng với một tenxơ đầu vào và map_of_indices_to_outputs
ánh xạ các chỉ số của tenxơ đầu ra với dữ liệu đầu ra tương ứng.
Trong cả hai trường hợp, các chỉ số tenxơ phải tương ứng với các giá trị bạn đã cung cấp cho Bộ chuyển đổi TensorFlow Lite khi bạn tạo mô hình. Xin lưu ý rằng thứ tự của tenxơ trong input
phải khớp với thứ tự được cung cấp cho Bộ chuyển đổi TensorFlow Lite.
Lớp Interpreter
cũng cung cấp các hàm thuận tiện để bạn lấy chỉ mục của bất kỳ đầu vào hoặc đầu ra mô hình nào bằng cách sử dụng tên thao tác:
public int getInputIndex(String opName);
public int getOutputIndex(String opName);
Nếu opName
không phải là một hoạt động hợp lệ trong mô hình, nó sẽ đưa ra một IllegalArgumentException
.
Ngoài ra, hãy cẩn thận rằng Interpreter
sở hữu tài nguyên. Để tránh rò rỉ bộ nhớ, tài nguyên phải được giải phóng sau khi sử dụng bởi:
interpreter.close();
Đối với một dự án ví dụ với Java, hãy xem mẫu phân loại hình ảnh Android .
Các kiểu dữ liệu được hỗ trợ (bằng Java)
Để sử dụng TensorFlow Lite, kiểu dữ liệu của tenxơ đầu vào và đầu ra phải là một trong các kiểu nguyên thủy sau:
-
float
-
int
-
long
-
byte
Các kiểu String
cũng được hỗ trợ, nhưng chúng được mã hóa khác với các kiểu nguyên thủy. Đặc biệt, hình dạng của chuỗi Tensor quy định số lượng và cách sắp xếp các chuỗi trong Tensor, với mỗi phần tử chính là một chuỗi có độ dài thay đổi. Theo nghĩa này, kích thước (byte) của Tensor không thể được tính toán chỉ từ hình dạng và loại, và do đó, các chuỗi không thể được cung cấp dưới dạng một đối số ByteBuffer
đơn, phẳng. Bạn có thể xem một số ví dụ trong trang này.
Nếu các loại dữ liệu khác, bao gồm các loại được đóng hộp như Integer
và Float
, được sử dụng, thì một IllegalArgumentException
sẽ được đưa ra.
đầu vào
Mỗi đầu vào phải là một mảng hoặc mảng nhiều chiều thuộc các kiểu nguyên thủy được hỗ trợ hoặc một ByteBuffer
thô có kích thước phù hợp. Nếu đầu vào là một mảng hoặc mảng nhiều chiều, tenxơ đầu vào được liên kết sẽ được thay đổi kích thước hoàn toàn thành kích thước của mảng tại thời điểm suy luận. Nếu đầu vào là ByteBuffer, thì trước tiên, người gọi phải thay đổi kích thước tenxơ đầu vào được liên kết theo cách thủ công (thông qua Interpreter.resizeInput()
) trước khi chạy suy luận.
Khi sử dụng ByteBuffer
, hãy ưu tiên sử dụng bộ đệm byte trực tiếp, vì điều này cho phép Interpreter
tránh các bản sao không cần thiết. Nếu ByteBuffer
là bộ đệm byte trực tiếp, thì thứ tự của nó phải là ByteOrder.nativeOrder()
. Sau khi nó được sử dụng cho suy luận mô hình, nó phải không thay đổi cho đến khi kết thúc suy luận mô hình.
đầu ra
Mỗi đầu ra phải là một mảng hoặc mảng nhiều chiều thuộc các kiểu nguyên thủy được hỗ trợ hoặc một ByteBuffer có kích thước phù hợp. Lưu ý rằng một số kiểu máy có đầu ra động, trong đó hình dạng của tenxơ đầu ra có thể khác nhau tùy thuộc vào đầu vào. Không có cách đơn giản nào để xử lý vấn đề này với API suy luận Java hiện có, nhưng các tiện ích mở rộng được lên kế hoạch sẽ giúp điều này trở nên khả thi.
Tải và chạy một mô hình trong Swift
Nền tảng: iOS
API Swift có sẵn trong TensorFlowLiteSwift
Pod từ Cocoapods.
Trước tiên, bạn cần nhập mô-đun 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...
}
Tải và chạy một mô hình trong Objective-C
Nền tảng: iOS
API Objective-C có sẵn trong TensorFlowLiteObjC
Pod từ Cocoapods.
Trước tiên, bạn cần nhập mô-đun 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... */ }
Sử dụng API C trong mã Mục tiêu-C
Hiện tại API Mục tiêu-C không hỗ trợ đại biểu. Để sử dụng các đại biểu với mã Objective-C, bạn cần gọi trực tiếp API C bên dưới.
#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);
Tải và chạy một mô hình trong C++
Nền tảng: Android, iOS và Linux
Trong C++, mô hình được lưu trữ trong lớp FlatBufferModel
. Nó đóng gói một mô hình TensorFlow Lite và bạn có thể xây dựng mô hình đó theo một số cách khác nhau, tùy thuộc vào nơi lưu trữ mô hình:
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);
};
Bây giờ bạn đã có mô hình dưới dạng đối tượng FlatBufferModel
, bạn có thể thực thi nó với một Interpreter
. Một FlatBufferModel
duy nhất có thể được sử dụng đồng thời bởi nhiều Interpreter
.
Các phần quan trọng của API Interpreter
được hiển thị trong đoạn mã bên dưới. Cần lưu ý rằng:
- Các thang đo được biểu thị bằng số nguyên, để tránh so sánh chuỗi (và bất kỳ sự phụ thuộc cố định nào vào thư viện chuỗi).
- Không được truy cập trình thông dịch từ các luồng đồng thời.
- Cấp phát bộ nhớ cho tenxơ đầu vào và đầu ra phải được kích hoạt bằng cách gọi
AllocateTensors()
ngay sau khi thay đổi kích thước tenxơ.
Cách sử dụng đơn giản nhất của TensorFlow Lite với C++ trông như thế này:
// 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);
Để biết thêm mã ví dụ, hãy xem minimal.cc
và label_image.cc
.
Tải và chạy một mô hình trong Python
Nền tảng: Linux
API Python để chạy suy luận được cung cấp trong mô-đun tf.lite
. Từ đó, hầu như bạn chỉ cần tf.lite.Interpreter
để tải mô hình và chạy suy luận.
Ví dụ sau đây cho thấy cách sử dụng trình thông dịch Python để tải tệp .tflite
và chạy suy luận với dữ liệu đầu vào ngẫu nhiên:
Ví dụ này được khuyến nghị nếu bạn đang chuyển đổi từ SavingModel với một SignatureDef đã xác định. Có sẵn bắt đầu từ 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'])
Một ví dụ khác nếu mô hình không có SignatureDefs được xác định.
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)
Là một giải pháp thay thế cho việc tải mô hình dưới dạng .tflite
được chuyển đổi trước, bạn có thể kết hợp mã của mình với API Python của Bộ chuyển đổi TensorFlow Lite ( tf.lite.TFLiteConverter
), cho phép bạn chuyển đổi mô hình Keras của mình sang định dạng TensorFlow Lite và sau đó chạy suy luận:
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...
Để biết thêm mã mẫu Python, hãy xem label_image.py
.
Chạy suy luận với mô hình hình dạng động
Nếu bạn muốn chạy một mô hình có hình dạng đầu vào động, hãy thay đổi kích thước hình dạng đầu vào trước khi chạy suy luận. Nếu không, hình dạng None
trong các mô hình Tensorflow sẽ được thay thế bằng một trình giữ chỗ 1
trong các mô hình TFLite.
Các ví dụ sau đây cho thấy cách thay đổi kích thước hình dạng đầu vào trước khi chạy suy luận bằng các ngôn ngữ khác nhau. Tất cả các ví dụ đều giả định rằng hình dạng đầu vào được xác định là [1/None, 10]
và cần được thay đổi kích thước thành [3, 10]
.
ví dụ C++:
// Resize input tensors before allocate tensors
interpreter->ResizeInputTensor(/*tensor_index=*/0, std::vector<int>{3,10});
interpreter->AllocateTensors();
Ví dụ về 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()
hoạt động được hỗ trợ
TensorFlow Lite hỗ trợ một tập hợp con các hoạt động của TensorFlow với một số hạn chế. Để biết danh sách đầy đủ các hoạt động và giới hạn, hãy xem trang TF Lite Ops .