Google I / O là một kết quả hoàn hảo! Cập nhật các phiên TensorFlow Xem phiên

Suy luận của TensorFlow Lite

Các suy luận hạn đề cập đến quá trình thực hiện một 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 một suy luận với một mô hình TensorFlow Lite, bạn phải chạy nó thông qua một thông dịch viên. Trình thông dịch TensorFlow Lite được thiết kế gọn nhẹ và nhanh chóng. Trình thông dịch sử dụng thứ tự đồ thị tĩnh và trình 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 tối thiểu.

Trang này mô tả làm thế nào để truy cập vào các thông dịch viên TensorFlow Lite và thực hiện một suy luận sử dụng C ++, Java, và Python, cộng với các liên kết đến các nguồn lực khác cho mỗi nền tảng được hỗ trợ .

Các khái niệm quan trọng

Suy luận của TensorFlow Lite thường tuân theo các bước sau:

  1. Đang tải một mô hình

    Bạn phải tải .tflite mô hình vào bộ nhớ, trong đó có đồ thị thực của mô hình.

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

  3. 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 số bước như xây dựng trình thông dịch và phân bổ các bộ căng, như được mô tả trong các phần sau.

  4. Phiên dịch đầu ra

    Khi bạn nhận được kết quả từ suy luận mô hình, bạn phải giải thích các tensors theo cách có ý nghĩa và 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. Bạn tùy thuộc vào 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.

Nền tảng được hỗ trợ

API suy luận TensorFlow được cung cấp cho hầu hết các điện thoại di động / nền tảng nhúng phổ biến như Android , iOSLinux , 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 sở thích 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 với chi phí 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à dự kiến ​​sẽ có 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 mô hình, đầu vào nguồn cấp dữ liệu và truy xuất đầu ra suy luận.

Nền tảng Android

Trên Android, suy luận TensorFlow Lite có thể được thực hiện bằng cách sử dụng API Java hoặc C ++. Các API Java mang lại 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. Các 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ề việc sử dụng C ++Java , hoặc làm theo các quickstart Android cho một hướng dẫn và ví dụ mã.

Trình tạo mã trình bao bọc Android TensorFlow Lite

Đối với TensorFlow Lite mô hình cải tiến với siêu dữ liệu , các nhà phát triển có thể sử dụng máy phát điện mã wrapper TensorFlow Lite Android để tạo ra nền tảng mã cụ thể wrapper. Mã wrapper loại bỏ sự cần thiết phải 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 các mô hình với các đối tượng đánh máy như TensorFlow Lite BitmapRect . Để biết thêm thông tin, vui lòng tham khảo tạo mã wrapper TensorFlow Lite Android .

Nền tảng iOS

Trên iOS, TensorFlow Lite là có sẵn với iOS thư viện nguồn gốc viết bằng SwiftObjective-C . Bạn cũng có thể sử dụng C API trực tiếp trong mã Objective-C.

Xem bên dưới để biết chi tiết về việc sử dụng Swift , Objective-CC API , hoặc làm theo các quickstart iOS cho một hướng dẫn và ví dụ mã.

Nền tảng Linux

Trên nền tảng Linux (bao gồm Raspberry Pi ), bạn có thể chạy các suy luận sử dụng TensorFlow Lite API có sẵn trong C ++Python , như thể hiện trong các phần sau.

Chạy một mô hình

Chạy mô hình TensorFlow Lite bao gồm một vài bước đơn giản:

  1. Tải mô hình vào bộ nhớ.
  2. Xây dựng một Interpreter dựa trên một mô hình hiện có.
  3. Đặt giá trị tensor đầu vào. (Tùy chọn thay đổi kích thước bộ căng đầu vào nếu không muốn kích thước xác định trước.)
  4. Gọi ra suy luận.
  5. Đọc giá trị tensor đầu ra.

Các phần sau đây 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 một suy luận với TensorFlow Lite được thiết kế chủ yếu để sử dụng với Android, do đó, nó có sẵn như là một sự phụ thuộc thư viện Android: org.tensorflow:tensorflow-lite .

Trong Java, bạn sẽ sử dụng Interpreter lớp để nạp một mô hình và ổ đĩa mô hình suy luận. 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 một Interpreter sử dụng một .tflite file:

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 ném IllegalArgumentException . Nếu bạn sử dụng MappedByteBuffer để khởi tạo một Interpreter , nó phải vẫn không thay đổi trong suốt cuộc đời của Interpreter .

Cách ưa thích để 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");
}

Các runSignature phương pháp mất ba đối số:

  • Đầu vào: bản đồ cho các đầu vào từ tên đầu vào trong chữ ký cho một đối tượng đầu vào.

  • Đầu ra: bản đồ để lập bản đồ đầu ra từ tên đầu ra trong chữ ký số liệu đầu ra.

  • Chữ ký Name [tùy chọn]: Tên chữ ký (có thể bỏ trống nếu mô hình có chữ ký duy nhất).

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 Interpreter.run() . Ví dụ:

try (Interpreter interpreter = new Interpreter(file_of_a_tensorflowlite_model)) {
  interpreter.run(input, output);
}

Các run() phương pháp chỉ mất một đầu vào và trả về chỉ có 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 trong inputs tương ứng với một tensor đầu vào và map_of_indices_to_outputs bản đồ chỉ số của tensors đầu ra cho các dữ liệu đầu ra tương ứng.

Trong cả hai trường hợp, các chỉ số tensor phải tương ứng với giá trị mà bạn đã cung cấp cho các TensorFlow Lite Chuyển đổi khi bạn đã tạo mô hình. Hãy nhận biết rằng thứ tự của tensors ở input phải phù hợp với trình tự trao cho các TensorFlow Lite Chuyển đổi.

Các Interpreter lớp cũng cung cấp các chức năng thuận tiện cho bạn để có được những chỉ số của bất kỳ đầu vào mô hình hoặc sản lượng sử dụng một tên hoạt động:

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

Nếu opName không phải là một hoạt động có hiệu lực trong mô hình, nó ném một IllegalArgumentException .

Cũng hãy cẩn thận rằng Interpreter sở hữu nguồn 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ằng cách:

interpreter.close();

Đối với một dự án ví dụ với Java, xem mẫu phân loại hình ảnh Android .

Các kiểu dữ liệu được hỗ trợ (trong Java)

Để sử dụng TensorFlow Lite, kiểu dữ liệu của các 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

String các loại cũng được hỗ trợ, nhưng họ được mã hóa khác biệt so với các loại nguyên thủy. Đặc biệt, hình dạng của một chuỗi Tensor quy định số lượng và sự sắp xếp của các chuỗi trong Tensor, với bản thân mỗi phần tử là một chuỗi có độ dài thay đổi. Theo nghĩa này, (byte) kích thước của tensor không có thể được tính từ hình dạng và gõ một mình, và hậu quả là chuỗi không thể được cung cấp như một, bằng phẳng đơn ByteBuffer tranh cãi.

Nếu kiểu dữ liệu khác, bao gồm các loại đóng hộp như IntegerFloat , được sử dụng, một IllegalArgumentException sẽ được ném ra.

Đầu vào

Mỗi đầu vào phải là một mảng hoặc đa chiều mảng của các kiểu dữ liệu được hỗ trợ, hoặc một nguyên ByteBuffer kích thước thích hợp. Nếu đầu vào là một mảng hoặc mảng nhiều chiều, thì 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à một ByteBuffer, người gọi nên đầu tiên thay đổi kích thước các tensor đầu vào liên quan (thông qua Interpreter.resizeInput() ) trước khi chạy suy luận.

Khi sử dụng ByteBuffer , thích sử dụng bộ đệm byte trực tiếp, vì điều này cho phép người Interpreter để tránh bản sao không cần thiết. Nếu ByteBuffer là một bộ đệm byte trực tiếp, trật tự của nó phải ByteOrder.nativeOrder() . Sau khi nó được sử dụng cho một 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.

Kết quả đầu ra

Mỗi đầu ra phải là một mảng hoặc mảng đa chiều của các kiểu nguyên thủy được hỗ trợ hoặc một ByteBuffer có kích thước thích hợp. Lưu ý rằng một số mô hình có đầu ra động, trong đó hình dạng của bộ căng đầu ra có thể khác nhau tùy thuộc vào đầu vào. Không có cách nào đơn giản để xử lý vấn đề này với API suy luận Java hiện có, nhưng các phần 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

Các Swift API có sẵn trong TensorFlowLiteSwift Pod từ Cocoapods.

Trước tiên, bạn cần phải nhập khẩu TensorFlowLite module.

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

Các Objective-C API có sẵn trong TensorFlowLiteObjC Pod từ Cocoapods.

Trước tiên, bạn cần phải nhập khẩu TensorFlowLite module.

@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ã Objective-C

Hiện tại Objective-C API không hỗ trợ các đại biểu. Để đại biểu sử dụng với mã Objective-C, bạn cần phải trực tiếp gọi cơ bản 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);

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 FlatBufferModel lớp. Nó đóng gói một mô hình TensorFlow Lite và bạn có thể xây dựng nó theo một vài cách khác nhau, tùy thuộc vào nơi mô hình được lưu trữ:

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 như một FlatBufferModel đối tượng, bạn có thể thực hiện nó với một Interpreter . Một đơn FlatBufferModel có thể được sử dụng đồng thời bởi nhiều hơn một Interpreter .

Các bộ phận quan trọng của Interpreter API được hiển thị trong đoạn mã dưới đây. Cần lưu ý rằng:

  • Hàng chục được biểu diễn 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).
  • Một trình thông dịch không được truy cập từ các luồng đồng thời.
  • Phân bổ bộ nhớ cho đầu vào và đầu ra tensors phải được kích hoạt bằng cách gọi AllocateTensors() ngay sau khi thay đổi kích thước tensors.

Cách sử dụng đơn giản nhất của TensorFlow Lite với C ++ trông như sau:

// 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ụ, xem minimal.cclabel_image.cc .

Tải và chạy một mô hình bằng Python

Nền tảng: Linux

API Python để chạy một suy luận được cung cấp trong tf.lite module. Từ đó, bạn chủ yếu chỉ cần tf.lite.Interpreter để nạp một mô hình và chạy một suy luận.

Các chương trình ví dụ sau đây làm thế nào để sử dụng trình thông dịch Python để tải một .tflite tập tin và chạy suy luận với các 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ừ SavedModel 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)

Để thay thế cho tải mô hình như là một tiền được chuyển đổi .tflite tập tin, bạn có thể kết hợp mã của bạn với các API TensorFlow Lite Chuyển đổi Python ( tf.lite.TFLiteConverter ), cho phép bạn chuyển đổi mô hình TensorFlow của bạn sang định dạng TensorFlow Lite và sau đó chạy suy luận:

import numpy as np
import tensorflow as tf

img = tf.placeholder(name="img", dtype=tf.float32, shape=(1, 64, 64, 3))
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
with tf.Session() as sess:
  converter = tf.lite.TFLiteConverter.from_session(sess, [img], [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 Python mẫu mã, xem label_image.py .

Mẹo: Chạy help(tf.lite.Interpreter) tại nhà ga Python để có được tài liệu chi tiết về người phiên dịch.

Các hoạt động được hỗ trợ

TensorFlow Lite hỗ trợ một tập hợp con các hoạt động TensorFlow với một số hạn chế. Đối với danh sách đầy đủ các hoạt động và hạn chế thấy trang Ops TF Lite .