Panduan ini memperkenalkan proses menjalankan model LiteRT (singkatan dari Lite Runtime) di perangkat untuk membuat prediksi berdasarkan data input. Hal ini dicapai dengan penafsir LiteRT, yang menggunakan pengurutan grafik statis dan allocator memori kustom (kurang dinamis) untuk memastikan latensi pemuatan, inisialisasi, dan eksekusi minimal.
Inferensi LiteRT biasanya mengikuti langkah-langkah berikut:
Memuat model: memuat model
.tflite
ke dalam memori, yang berisi grafik eksekusi model.Mentransformasi data: Ubah data input menjadi format yang diharapkan dan dimensi kustom. Data input mentah untuk model umumnya tidak cocok dengan input format data yang diharapkan oleh model. Misalnya, Anda mungkin perlu mengubah ukuran gambar atau mengubah format gambar agar kompatibel dengan model.
Menjalankan inferensi: Menjalankan model LiteRT untuk membuat prediksi. Langkah ini melibatkan penggunaan LiteRT API untuk mengeksekusi model. Proses ini melibatkan beberapa langkah seperti mem-build penafsir, dan mengalokasikan tensor.
Menafsirkan output: Menafsirkan tensor output dengan cara yang bermanfaat yang berguna dalam aplikasi Anda. Misalnya, model mungkin hanya menampilkan daftar probabilitas. Anda dapat memetakan probabilitas ke kategori yang relevan dan memformat output.
Panduan ini menjelaskan cara mengakses penafsir LiteRT dan melakukan inferensi menggunakan C++, Java, dan Python.
Platform yang didukung
API inferensi TensorFlow disediakan untuk sebagian besar platform seluler dan tersemat yang umum seperti Android, iOS, dan Linux, dalam beberapa bahasa pemrograman.
Dalam kebanyakan kasus, desain API mencerminkan preferensi terhadap performa daripada kemudahan gunakan. LiteRT dirancang untuk inferensi cepat pada perangkat kecil, sehingga API menghindari salinan yang tidak perlu dengan mengorbankan kenyamanan.
Di semua library, LiteRT API memungkinkan Anda memuat model, input feed, dan mengambil output inferensi.
Platform Android
Di Android, inferensi LiteRT dapat dilakukan menggunakan Java atau C++ API. Tujuan API Java memberikan kemudahan dan dapat digunakan langsung dalam Android Class aktivitas. C++ API menawarkan fleksibilitas dan kecepatan yang lebih besar, tetapi mungkin memerlukan penulisan wrapper JNI untuk memindahkan data antarlapisan Java dan C++.
Lihat bagian C++ dan Java untuk mengetahui informasi selengkapnya, atau ikuti panduan memulai Android.
Platform iOS
Di iOS, LiteRT tersedia di library iOS Swift dan Objective-C. Anda juga dapat menggunakan C API secara langsung dalam kode Objective-C.
Lihat bagian Swift, Objective-C, dan C API, atau ikuti panduan memulai iOS.
Platform Linux
Pada platform Linux, Anda dapat menjalankan inferensi menggunakan API LiteRT yang tersedia di C++.
Memuat dan menjalankan model
Memuat dan menjalankan model LiteRT melibatkan langkah-langkah berikut:
- Memuat model ke dalam memori.
- Membuat
Interpreter
berdasarkan model yang sudah ada. - Menyetel nilai tensor input.
- Memanggil inferensi.
- Menghasilkan nilai tensor.
Android (Java)
Java API untuk menjalankan inferensi dengan LiteRT terutama dirancang untuk digunakan
dengan Android, sehingga tersedia sebagai dependensi library Android:
com.google.ai.edge.litert
.
Di Java, Anda akan menggunakan class Interpreter
untuk memuat model dan model drive
inferensi. Dalam banyak kasus, ini mungkin satu-satunya API yang Anda perlukan.
Anda dapat melakukan inisialisasi Interpreter
menggunakan file FlatBuffers (.tflite
):
public Interpreter(@NotNull File modelFile);
Atau dengan MappedByteBuffer
:
public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer);
Dalam kedua kasus tersebut, Anda harus memberikan model LiteRT yang valid atau API akan menampilkan
IllegalArgumentException
. Jika Anda menggunakan MappedByteBuffer
untuk melakukan inisialisasi
Interpreter
, MappedByteBuffer
tersebut tidak boleh berubah selama seluruh masa aktif
Interpreter
.
Cara yang lebih disukai untuk menjalankan inferensi pada model adalah menggunakan tanda tangan - Tersedia untuk model yang dikonversi mulai 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");
}
Metode runSignature
menggunakan tiga argumen:
Inputs : peta untuk input dari nama input dalam tanda tangan ke objek input.
Output : peta untuk pemetaan output dari nama output dalam tanda tangan ke data output.
Signature Name (opsional): Nama tanda tangan (Dapat dibiarkan kosong jika memiliki tanda tangan tunggal).
Cara lain untuk menjalankan inferensi saat model tidak memiliki tanda tangan yang ditentukan.
Cukup panggil Interpreter.run()
. Contoh:
try (Interpreter interpreter = new Interpreter(file_of_a_tensorflowlite_model)) {
interpreter.run(input, output);
}
Metode run()
hanya mengambil satu input dan hanya menampilkan satu output. Jadi, jika
model Anda memiliki beberapa input atau beberapa output, gunakan:
interpreter.runForMultipleInputsOutputs(inputs, map_of_indices_to_outputs);
Dalam hal ini, setiap entri dalam inputs
sesuai dengan tensor input dan
map_of_indices_to_outputs
memetakan indeks tensor output ke
data output.
Dalam kedua kasus tersebut, indeks tensor harus sesuai dengan nilai yang Anda berikan ke
LiteRT Converter saat membuat model. Harus tahu
bahwa urutan tensor di input
harus sesuai dengan urutan yang diberikan ke LiteRT
Pengonversi.
Class Interpreter
juga menyediakan fungsi yang mudah bagi Anda untuk mendapatkan
indeks input atau output model apa pun yang menggunakan nama operasi:
public int getInputIndex(String opName);
public int getOutputIndex(String opName);
Jika opName
bukan operasi yang valid dalam model, opName
akan menampilkan
IllegalArgumentException
.
Perhatikan juga bahwa Interpreter
memiliki resource. Untuk menghindari kebocoran memori,
resource harus dirilis setelah digunakan dengan:
interpreter.close();
Untuk contoh project dengan Java, lihat Contoh deteksi objek Android aplikasi.
Jenis data yang didukung
Untuk menggunakan LiteRT, jenis data tensor input dan output harus berupa salah satu jenis primitif berikut:
float
int
long
byte
Jenis String
juga didukung, tetapi dienkode secara berbeda dengan
jenis primitif. Secara khusus, bentuk string Tensor menentukan jumlah
dan susunan string di Tensor, dengan setiap elemen itu sendiri menjadi
{i>string <i}dengan panjang variabel. Dalam hal ini, ukuran (byte) Tensor tidak bisa
dihitung dari bentuk dan jenis saja, dan akibatnya {i>string<i} tidak bisa
disediakan sebagai argumen ByteBuffer
datar tunggal.
Jika jenis data lain, termasuk jenis kotak seperti Integer
dan Float
, digunakan,
IllegalArgumentException
akan ditampilkan.
Input
Setiap input harus berupa array atau array multidimensi dari jenis primitif
yang didukung, atau ByteBuffer
mentah dengan ukuran yang sesuai. Jika inputnya adalah
sebuah array atau array multi-dimensi, tensor input terkait akan
secara implisit diubah ukurannya ke dimensi array pada waktu inferensi. Jika inputnya adalah
ByteBuffer, pemanggil harus terlebih dahulu mengubah ukuran input terkait secara manual
Tensor (melalui Interpreter.resizeInput()
) sebelum menjalankan inferensi.
Saat menggunakan ByteBuffer
, sebaiknya gunakan buffering byte langsung, karena hal ini memungkinkan
Interpreter
untuk menghindari salinan yang tidak perlu. Jika ByteBuffer
adalah buffering byte
langsung, urutannya harus ByteOrder.nativeOrder()
. Setelah digunakan untuk
inferensi model, tidak boleh berubah sampai inferensi model selesai.
Output
Setiap output harus berupa array atau array multi-dimensi dari output yang didukung jenis primitif, atau ByteBuffer dengan ukuran yang sesuai. Perhatikan bahwa beberapa model memiliki output dinamis, dengan bentuk tensor output yang dapat bervariasi bergantung pada input. Tidak ada cara mudah untuk menangani hal ini dengan API inferensi Java yang ada, tetapi ekstensi yang direncanakan akan memungkinkan hal ini.
iOS (Swift)
Swift
API
tersedia di Pod TensorFlowLiteSwift
dari Cocoapods.
Pertama, Anda harus mengimpor modul 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
tersedia di Pod LiteRTObjC
dari Cocoapods.
Pertama, Anda harus mengimpor modul 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... */ }
C API dalam kode Objective-C
Objective-C API tidak mendukung delegasi. Untuk menggunakan delegasi dengan kode Objective-C, Anda harus langsung memanggil C API yang mendasarinya.
#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++
API C++ untuk menjalankan inferensi dengan LiteRT kompatibel dengan platform Android, iOS, dan Linux. C++ API di iOS hanya tersedia saat menggunakan bazel.
Dalam C++, model disimpan di
Class FlatBufferModel
.
Model ini mengenkapsulasi model LiteRT dan Anda dapat mem-build-nya dengan beberapa cara
yang berbeda, bergantung pada tempat model disimpan:
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);
};
Setelah memiliki model sebagai objek FlatBufferModel
, Anda dapat menjalankannya
dengan
Interpreter
.
Satu FlatBufferModel
dapat digunakan secara bersamaan oleh lebih dari satu
Interpreter
.
Bagian penting dari Interpreter
API ditampilkan dalam cuplikan kode
di bawah ini. Perlu diperhatikan bahwa:
- Tensor direpresentasikan oleh bilangan bulat untuk menghindari perbandingan string (dan dependensi tetap apa pun pada library string).
- Penerjemah tidak boleh diakses dari thread serentak.
- Alokasi memori untuk tensor input dan output harus dipicu dengan memanggil
AllocateTensors()
tepat setelah mengubah ukuran tensor.
Penggunaan LiteRT dengan C++ yang paling sederhana terlihat seperti ini:
// 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);
Untuk contoh kode lainnya, lihat
minimal.cc
dan
label_image.cc
.
Python
API Python untuk menjalankan inferensi menggunakan
Interpreter
untuk memuat model dan
menjalankan inferensi.
Instal paket LiteRT:
$ python3 -m pip install ai-edge-litert
Mengimpor Penafsir LiteRT
from ai_edge_litert.interpreter import Interpreter
Interpreter = Interpreter(model_path=args.model.file)
Contoh berikut menunjukkan cara menggunakan penafsir Python untuk memuat
FlatBuffers (.tflite
) dan menjalankan inferensi dengan data input acak:
Contoh ini direkomendasikan jika Anda mengonversi dari SavedModel dengan SignatureDef yang ditentukan.
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'])
Contoh lain jika model belum menentukan 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)
Sebagai alternatif untuk memuat model sebagai file .tflite
yang telah dikonversi sebelumnya, Anda
dapat menggabungkan kode dengan LiteRT
Compiler
, yang memungkinkan Anda mengonversi model Keras menjadi format LiteRT, lalu menjalankan
inferensi:
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...
Untuk kode contoh Python lainnya, lihat
label_image.py
.
Menjalankan inferensi dengan model bentuk dinamis
Jika Anda ingin menjalankan model dengan bentuk input dinamis, ubah ukuran bentuk input
sebelum menjalankan inferensi. Jika tidak, bentuk None
dalam model TensorFlow akan diganti dengan placeholder 1
dalam model LiteRT.
Contoh berikut menunjukkan cara mengubah ukuran bentuk input sebelum menjalankan
inferensi dalam berbagai bahasa. Semua contoh mengasumsikan bahwa bentuk input
ditentukan sebagai [1/None, 10]
, dan perlu diubah ukurannya menjadi [3, 10]
.
Contoh C++:
// Resize input tensors before allocate tensors
interpreter->ResizeInputTensor(/*tensor_index=*/0, std::vector<int>{3,10});
interpreter->AllocateTensors();
Contoh 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()