Inferensi TensorFlow Lite

Istilah inferensi mengacu pada proses mengeksekusi model TensorFlow Lite di perangkat untuk membuat prediksi berdasarkan data input. Untuk melakukan inferensi dengan model TensorFlow Lite, Anda harus menjalankannya melalui interpreter. Penafsir TensorFlow Lite dirancang agar ramping dan cepat. Penafsir menggunakan pengurutan grafik statis dan alokator memori kustom (kurang-dinamis) untuk memastikan minimal beban, inisialisasi, dan latensi eksekusi.

Halaman ini menjelaskan cara mengakses penafsir TensorFlow Lite dan melakukan inferensi menggunakan C++, Java, dan Python, serta link ke resource lain untuk setiap platform yang didukung.

Konsep penting

Inferensi TensorFlow Lite biasanya mengikuti langkah-langkah berikut:

  1. Memuat model

    Anda harus memuat model .tflite ke dalam memori, yang berisi grafik eksekusi model.

  2. Mentransformasi data

    Data input mentah untuk model umumnya tidak sesuai dengan format data input yang diharapkan oleh model. Misalnya, Anda mungkin perlu mengubah ukuran gambar atau mengubah format gambar agar kompatibel dengan model.

  3. Menjalankan Inferensi

    Pada langkah ini, Anda akan menggunakan TensorFlow Lite API untuk mengeksekusi model. Proses ini memerlukan beberapa langkah seperti membuat penafsir dan mengalokasikan tensor, seperti yang dijelaskan di bagian berikut.

  4. Menafsirkan output

    Saat menerima hasil dari inferensi model, Anda harus menafsirkan tensor dengan cara yang bermakna yang berguna dalam aplikasi Anda.

    Misalnya, model mungkin hanya menampilkan daftar probabilitas. Anda dapat memetakan probabilitas ke kategori yang relevan dan menyajikannya kepada pengguna akhir.

Platform yang didukung

API inferensi TensorFlow disediakan untuk sebagian besar platform seluler/sematan yang umum, seperti Android, iOS, dan Linux, dalam beberapa bahasa pemrograman.

Pada umumnya, desain API mencerminkan preferensi terhadap performa daripada kemudahan penggunaan. TensorFlow Lite dirancang untuk inferensi cepat di perangkat kecil, sehingga seharusnya tidak mengherankan jika API mencoba menghindari salinan yang tidak perlu dengan mengorbankan kenyamanan. Demikian pula, konsistensi dengan TensorFlow API bukanlah tujuan yang eksplisit dan akan ada beberapa varian antar-bahasa.

Di semua library, TensorFlow Lite API memungkinkan Anda memuat model, input feed, dan mengambil output inferensi.

Platform Android

Di Android, inferensi TensorFlow Lite dapat dilakukan menggunakan Java atau C++ API. API Java memberikan kemudahan dan dapat digunakan langsung dalam class Aktivitas Android Anda. C++ API menawarkan fleksibilitas dan kecepatan yang lebih tinggi, tetapi mungkin memerlukan penulisan wrapper JNI untuk memindahkan data antara lapisan Java dan C++.

Lihat di bawah untuk mengetahui detail cara menggunakan C++ dan Java, atau ikuti panduan memulai Android untuk mempelajari tutorial dan kode contoh.

Generator kode wrapper Android TensorFlow Lite

Untuk model TensorFlow Lite yang ditingkatkan dengan metadata, developer dapat menggunakan generator kode wrapper Android TensorFlow Lite untuk membuat kode wrapper khusus platform. Kode wrapper menghilangkan kebutuhan untuk berinteraksi langsung dengan ByteBuffer di Android. Sebagai gantinya, developer dapat berinteraksi dengan model TensorFlow Lite dengan objek yang diketik seperti Bitmap dan Rect. Untuk mengetahui informasi selengkapnya, lihat generator kode wrapper Android TensorFlow Lite.

Platform iOS

Di iOS, TensorFlow Lite tersedia dengan library iOS native yang ditulis di Swift dan Objective-C. Anda juga dapat menggunakan C API secara langsung dalam kode Objective-C.

Lihat di bawah untuk mengetahui detail penggunaan Swift, Objective-C, dan C API, atau ikuti panduan memulai iOS untuk mendapatkan tutorial dan kode contoh.

Platform Linux

Di platform Linux (termasuk Raspberry Pi), Anda dapat menjalankan inferensi menggunakan TensorFlow Lite API yang tersedia di C++ dan Python, seperti yang ditunjukkan pada bagian berikut.

Menjalankan model

Menjalankan model TensorFlow Lite melibatkan beberapa langkah sederhana:

  1. Muat model ke dalam memori.
  2. Buat Interpreter berdasarkan model yang ada.
  3. Menetapkan nilai tensor input. (Anda juga dapat mengubah ukuran tensor input jika ukuran yang telah ditentukan tidak diinginkan.)
  4. Panggil inferensi.
  5. Membaca nilai tensor output.

Bagian berikut menjelaskan cara melakukan langkah-langkah ini dalam setiap bahasa.

Memuat dan menjalankan model di Java

Platform: Android

Java API untuk menjalankan inferensi dengan TensorFlow Lite terutama dirancang untuk digunakan dengan Android, sehingga tersedia sebagai dependensi library Android: org.tensorflow:tensorflow-lite.

Di Java, Anda akan menggunakan class Interpreter untuk memuat model dan mendorong inferensi model. Dalam banyak kasus, ini mungkin satu-satunya API yang Anda butuhkan.

Anda dapat menginisialisasi Interpreter menggunakan file .tflite:

public Interpreter(@NotNull File modelFile);

Atau dengan MappedByteBuffer:

public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer);

Dalam kedua kasus tersebut, Anda harus memberikan model TensorFlow Lite yang valid atau API akan menampilkan IllegalArgumentException. Jika Anda menggunakan MappedByteBuffer untuk menginisialisasi Interpreter, tindakan tersebut tidak boleh diubah sepanjang waktu Interpreter.

Cara yang lebih disukai untuk menjalankan inferensi pada model adalah dengan 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:

  • Input : memetakan input dari nama input dalam tanda tangan ke objek input.

  • Output : memetakan untuk pemetaan output dari nama output dalam tanda tangan hingga data output.

  • Signature Name (opsional): Nama tanda tangan (Dapat dibiarkan kosong jika model 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 terkait dengan sebuah tensor input dan map_of_indices_to_outputs memetakan indeks tensor output ke data output yang sesuai.

Dalam kedua kasus tersebut, indeks tensor harus sesuai dengan nilai yang Anda berikan ke TensorFlow Lite Converter saat membuat model. Perhatikan bahwa urutan tensor di input harus sesuai dengan urutan yang diberikan ke TensorFlow Lite Converter.

Class Interpreter juga menyediakan fungsi yang mudah bagi Anda untuk mendapatkan indeks input atau output model apa pun menggunakan nama operasi:

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

Jika opName bukan operasi yang valid dalam model, IllegalArgumentException akan ditampilkan.

Perlu diketahui juga bahwa Interpreter memiliki resource. Untuk menghindari kebocoran memori, resource harus dilepaskan setelah digunakan oleh:

interpreter.close();

Untuk contoh project dengan Java, lihat contoh klasifikasi gambar Android.

Jenis data yang didukung (di Java)

Untuk menggunakan TensorFlow Lite, jenis data tensor input dan output harus berupa salah satu dari 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 pengaturan string di Tensor, dengan setiap elemen itu sendiri berupa string dengan panjang variabel. Dalam hal ini, ukuran (byte) Tensor tidak dapat dihitung hanya dari bentuk dan jenisnya. Oleh karena itu, string tidak dapat diberikan sebagai satu argumen ByteBuffer datar.

Jika jenis data lain, termasuk jenis kotak seperti Integer dan Float, digunakan, IllegalArgumentException akan ditampilkan.

Input

Setiap input harus berupa array atau array multi-dimensi dari jenis primitif yang didukung, atau ByteBuffer mentah dengan ukuran yang sesuai. Jika inputnya adalah array atau array multi-dimensi, tensor input yang terkait akan diubah ukurannya secara implisit ke dimensi array pada waktu inferensi. Jika inputnya adalah ByteBuffer, pemanggil harus terlebih dahulu mengubah ukuran tensor input terkait (melalui Interpreter.resizeInput()) sebelum menjalankan inferensi.

Saat menggunakan ByteBuffer, lebih baik gunakan buffering byte langsung karena memungkinkan Interpreter menghindari salinan yang tidak perlu. Jika ByteBuffer adalah buffering byte langsung, urutannya harus ByteOrder.nativeOrder(). Setelah digunakan untuk inferensi model, inferensi harus tetap tidak berubah sampai inferensi model selesai.

Output

Setiap output harus berupa array atau array multi-dimensi dari jenis primitif yang didukung, atau ByteBuffer dengan ukuran yang sesuai. Perhatikan bahwa beberapa model memiliki output dinamis, dengan bentuk tensor output yang dapat bervariasi bergantung pada inputnya. Tidak ada cara mudah untuk menangani hal ini dengan API inferensi Java yang sudah ada, tetapi ekstensi terencana akan memungkinkan hal ini.

Memuat dan menjalankan model di Swift

Platform: iOS

Swift API tersedia di Pod TensorFlowLiteSwift dari Cocoapods.

Pertama, Anda perlu 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...
}

Memuat dan menjalankan model di Objective-C

Platform: iOS

Objective-C API tersedia dalam Pod TensorFlowLiteObjC dari Cocoapods.

Pertama, Anda perlu mengimpor modul 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... */ }

Menggunakan C API dalam kode Objective-C

Saat ini 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);

Memuat dan menjalankan model di C++

Platform: Android, iOS, dan Linux

Pada C++, model disimpan di class FlatBufferModel. Model ini mengenkapsulasi model TensorFlow Lite dan Anda dapat mem-build-nya dengan beberapa cara, 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 mengeksekusinya dengan Interpreter. Satu FlatBufferModel dapat digunakan secara bersamaan oleh lebih dari satu Interpreter.

Bagian penting dari Interpreter API ditampilkan dalam cuplikan kode di bawah. Perlu diperhatikan bahwa:

  • Tensor direpresentasikan oleh bilangan bulat untuk menghindari perbandingan string (dan dependensi tetap apa pun pada library string).
  • Penafsir tidak boleh diakses dari thread serentak.
  • Alokasi memori untuk tensor input dan output harus dipicu dengan memanggil AllocateTensors() tepat setelah mengubah ukuran tensor.

Penggunaan TensorFlow Lite yang paling sederhana dengan C++ 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 desired.
interpreter->AllocateTensors();

float* input = interpreter->typed_input_tensor<float>(0);
// Fill `input`.

interpreter->Invoke();

float* output = interpreter->typed_output_tensor<float>(0);

Untuk kode contoh lainnya, lihat minimal.cc dan label_image.cc.

Memuat dan menjalankan model di Python

Platform: Linux

Python API untuk menjalankan inferensi sebagian besar hanya memerlukan tf.lite.Interpreter untuk memuat model dan menjalankan inferensi.

Contoh berikut menunjukkan cara menggunakan penafsir Python untuk memuat file .tflite dan menjalankan inferensi dengan data input acak:

Contoh ini direkomendasikan jika Anda melakukan konversi dariSavedModel dengan SignatureDef yang ditentukan. Tersedia mulai 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'])

Contoh lain jika model tidak menentukan 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)

Sebagai alternatif untuk memuat model sebagai file .tflite yang telah dikonversi sebelumnya, Anda dapat menggabungkan kode dengan TensorFlow Lite Converter Python API, yang memungkinkan Anda mengonversi model Keras menjadi format TensorFlow Lite, 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 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...

Untuk kode contoh Python selengkapnya, 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 TFLite.

Contoh berikut menunjukkan cara mengubah ukuran bentuk input sebelum menjalankan inferensi dalam berbagai bahasa. Semua contoh mengasumsikan bahwa bentuk input ditetapkan 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 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()

Operasi yang didukung

TensorFlow Lite mendukung subset operasi TensorFlow dengan beberapa batasan. Untuk daftar lengkap operasi dan batasan, lihat halaman TF Lite Ops.