Termin wnioskowanie odnosi się do procesu wykonywania modelu TensorFlow Lite na urządzeniu w celu dokonania prognoz na podstawie danych wejściowych. Aby przeprowadzić wnioskowanie za pomocą modelu TensorFlow Lite, należy uruchomić go za pomocą interpretera . Interpreter TensorFlow Lite został zaprojektowany tak, aby był oszczędny i szybki. Interpreter używa statycznego porządkowania grafów i niestandardowego (mniej dynamicznego) alokatora pamięci, aby zapewnić minimalne obciążenie, inicjalizację i opóźnienie wykonania.
Na tej stronie opisano, jak uzyskać dostęp do interpretera TensorFlow Lite i przeprowadzić wnioskowanie przy użyciu języków C++, Java i Python, a także linki do innych zasobów dla każdej obsługiwanej platformy .
Ważne pojęcia
Wnioskowanie TensorFlow Lite zwykle obejmuje następujące kroki:
Ładowanie modelu
Musisz załadować model
.tflite
do pamięci, która zawiera wykres wykonania modelu.Transformacja danych
Surowe dane wejściowe dla modelu generalnie nie pasują do formatu danych wejściowych oczekiwanego przez model. Na przykład może być konieczna zmiana rozmiaru obrazu lub zmiana formatu obrazu, aby był zgodny z modelem.
Uruchamianie wnioskowania
Ten krok obejmuje użycie interfejsu API TensorFlow Lite do wykonania modelu. Obejmuje kilka kroków, takich jak budowanie interpretera i przydzielanie tensorów, jak opisano w poniższych sekcjach.
Wynik tłumaczenia
Po otrzymaniu wyników z wnioskowania o modelu należy interpretować tensory w zrozumiały sposób, który jest przydatny w aplikacji.
Na przykład model może zwrócić tylko listę prawdopodobieństw. Do Ciebie należy mapowanie prawdopodobieństw do odpowiednich kategorii i przedstawienie ich użytkownikowi końcowemu.
Obsługiwane platformy
Interfejsy API wnioskowania TensorFlow są dostępne dla większości popularnych platform mobilnych/wbudowanych, takich jak Android , iOS i Linux , w wielu językach programowania.
W większości przypadków projekt interfejsu API odzwierciedla preferencje dotyczące wydajności, a nie łatwości użytkowania. TensorFlow Lite jest przeznaczony do szybkiego wnioskowania na małych urządzeniach, więc nie powinno dziwić, że interfejsy API starają się unikać niepotrzebnych kopii kosztem wygody. Podobnie spójność z interfejsami API TensorFlow nie była wyraźnym celem i należy spodziewać się pewnych różnic między językami.
We wszystkich bibliotekach interfejs API TensorFlow Lite umożliwia ładowanie modeli, wprowadzanie danych wejściowych i pobieranie wyników wnioskowania.
Platforma Androida
W systemie Android wnioskowanie TensorFlow Lite można przeprowadzić przy użyciu interfejsów API Java lub C++. Interfejsy API języka Java zapewniają wygodę i mogą być używane bezpośrednio w klasach aktywności systemu Android. Interfejsy API C++ oferują większą elastyczność i szybkość, ale mogą wymagać napisania opakowań JNI w celu przenoszenia danych między warstwami Java i C++.
Poniżej znajdziesz szczegółowe informacje na temat korzystania z języka C++ i języka Java lub skorzystaj z przewodnika Szybki start dla systemu Android , aby zapoznać się z samouczkiem i przykładowym kodem.
TensorFlow Lite Generator kodu opakowania dla Androida
W przypadku modelu TensorFlow Lite wzbogaconego o metadane programiści mogą użyć generatora kodu opakowania TensorFlow Lite dla systemu Android, aby utworzyć kod opakowania specyficzny dla platformy. Kod opakowujący eliminuje potrzebę bezpośredniej interakcji z ByteBuffer
na Androidzie. Zamiast tego programiści mogą wchodzić w interakcje z modelem TensorFlow Lite za pomocą wpisywanych obiektów, takich jak Bitmap
i Rect
. Aby uzyskać więcej informacji, zapoznaj się z generatorem kodów opakowania TensorFlow Lite Android .
Platforma iOS
W systemie iOS TensorFlow Lite jest dostępny z natywnymi bibliotekami iOS napisanymi w językach Swift i Objective-C . Możesz także użyć C API bezpośrednio w kodach Objective-C.
Zobacz poniżej, aby uzyskać szczegółowe informacje na temat korzystania z Swift , Objective-C i C API lub postępuj zgodnie z przewodnikiem Szybki start dla systemu iOS , aby uzyskać samouczek i przykładowy kod.
Platforma Linuksowa
Na platformach Linux (w tym Raspberry Pi ) można uruchamiać wnioskowania przy użyciu interfejsów API TensorFlow Lite dostępnych w językach C++ i Python , jak pokazano w poniższych sekcjach.
Prowadzenie modelu
Uruchomienie modelu TensorFlow Lite obejmuje kilka prostych kroków:
- Załaduj model do pamięci.
- Zbuduj
Interpreter
w oparciu o istniejący model. - Ustaw wartości tensora wejściowego. (Opcjonalnie zmień rozmiar tensorów wejściowych, jeśli predefiniowane rozmiary nie są pożądane).
- Wywołaj wnioskowanie.
- Odczytaj wartości tensora wyjściowego.
W poniższych sekcjach opisano, w jaki sposób można wykonać te kroki w każdym języku.
Załaduj i uruchom model w Javie
Platforma: Android
Interfejs API języka Java do uruchamiania wnioskowania za pomocą TensorFlow Lite jest przeznaczony przede wszystkim do użytku z systemem Android, więc jest dostępny jako zależność biblioteki systemu Android: org.tensorflow:tensorflow-lite
.
W Javie będziesz używać klasy Interpreter
do ładowania modelu i prowadzenia wnioskowania o modelu. W wielu przypadkach może to być jedyne potrzebne API.
Możesz zainicjować Interpreter
za pomocą pliku .tflite
:
public Interpreter(@NotNull File modelFile);
Lub z MappedByteBuffer
:
public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer);
W obu przypadkach musisz podać prawidłowy model TensorFlow Lite, w przeciwnym razie interfejs API zgłosi IllegalArgumentException
. Jeśli użyjesz MappedByteBuffer
do zainicjowania Interpreter
, musi on pozostać niezmieniony przez cały okres istnienia Interpreter
.
Preferowanym sposobem uruchamiania wnioskowania na modelu jest użycie sygnatur — dostępne dla modeli przekonwertowanych począwszy od 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");
}
Metoda runSignature
przyjmuje trzy argumenty:
Wejścia : mapa wejść od nazwy wejścia w sygnaturze do obiektu wejściowego.
Wyjścia : mapa do mapowania danych wyjściowych z nazwy wyjściowej w sygnaturze do danych wyjściowych.
Nazwa podpisu [opcjonalnie]: Nazwa podpisu (można pozostawić puste, jeśli model ma pojedynczy podpis).
Inny sposób uruchomienia wnioskowania, gdy model nie ma zdefiniowanych sygnatur. Po prostu wywołaj Interpreter.run()
. Na przykład:
try (Interpreter interpreter = new Interpreter(file_of_a_tensorflowlite_model)) {
interpreter.run(input, output);
}
Metoda run()
przyjmuje tylko jedno wejście i zwraca tylko jedno wyjście. Więc jeśli twój model ma wiele wejść lub wiele wyjść, zamiast tego użyj:
interpreter.runForMultipleInputsOutputs(inputs, map_of_indices_to_outputs);
W tym przypadku każdy wpis w inputs
odpowiada tensorowi wejściowemu, a map_of_indices_to_outputs
odwzorowuje indeksy tensorów wyjściowych na odpowiednie dane wyjściowe.
W obu przypadkach wskaźniki tensorów powinny odpowiadać wartościom nadanym konwerterowi TensorFlow Lite podczas tworzenia modelu. Należy pamiętać, że kolejność tensorów na input
musi być zgodna z kolejnością nadaną konwerterowi TensorFlow Lite.
Klasa Interpreter
udostępnia również wygodne funkcje umożliwiające uzyskanie indeksu dowolnego wejścia lub wyjścia modelu przy użyciu nazwy operacji:
public int getInputIndex(String opName);
public int getOutputIndex(String opName);
Jeśli opName
nie jest prawidłową operacją w modelu, zgłasza wyjątek IllegalArgumentException
.
Należy również pamiętać, że Interpreter
jest właścicielem zasobów. Aby uniknąć wycieku pamięci, zasoby muszą zostać zwolnione po użyciu przez:
interpreter.close();
Aby zapoznać się z przykładowym projektem z Javą, zobacz przykładową klasyfikację obrazu systemu Android .
Obsługiwane typy danych (w Javie)
Aby korzystać z TensorFlow Lite, typy danych tensorów wejściowych i wyjściowych muszą należeć do jednego z następujących typów pierwotnych:
-
float
-
int
-
long
-
byte
Obsługiwane są również typy String
, ale są one kodowane inaczej niż typy pierwotne. W szczególności kształt struny Tensor dyktuje liczbę i rozmieszczenie strun w Tensorze, przy czym każdy element sam w sobie jest struną o zmiennej długości. W tym sensie rozmiar (bajtowy) Tensor nie może być obliczony na podstawie samego kształtu i typu, w związku z czym łańcuchy znaków nie mogą być dostarczane jako pojedynczy, płaski argument ByteBuffer
. Możesz zobaczyć kilka przykładów na tej stronie .
Jeśli używane są inne typy danych, w tym typy opakowane, takie jak Integer
i Float
, zostanie zgłoszony wyjątek IllegalArgumentException
.
Wejścia
Każde wejście powinno być tablicą lub tablicą wielowymiarową obsługiwanych typów pierwotnych lub nieprzetworzonym buforem ByteBuffer
o odpowiednim rozmiarze. Jeśli dane wejściowe są tablicą lub tablicą wielowymiarową, powiązany tensor wejściowy zostanie niejawnie przeskalowany do wymiarów tablicy w czasie wnioskowania. Jeśli dane wejściowe to ByteBuffer, wywołujący powinien najpierw ręcznie zmienić rozmiar powiązanego tensora wejściowego (poprzez Interpreter.resizeInput()
) przed uruchomieniem wnioskowania.
Używając ByteBuffer
, preferuj używanie bezpośrednich buforów bajtów, ponieważ pozwala to Interpreter
uniknąć niepotrzebnych kopii. Jeśli ByteBuffer
jest bezpośrednim buforem bajtów, jego kolejność musi być ByteOrder.nativeOrder()
. Po użyciu do wnioskowania o modelu musi pozostać niezmieniony do momentu zakończenia wnioskowania o modelu.
Wyjścia
Każde wyjście powinno być tablicą lub wielowymiarową tablicą obsługiwanych typów pierwotnych lub ByteBuffer o odpowiednim rozmiarze. Należy zauważyć, że niektóre modele mają wyjścia dynamiczne, w których kształt tensorów wyjściowych może się różnić w zależności od danych wejściowych. Nie ma prostego sposobu radzenia sobie z tym za pomocą istniejącego interfejsu API wnioskowania Java, ale planowane rozszerzenia to umożliwią.
Załaduj i uruchom model w Swift
Platforma: iOS
Swift API jest dostępny w TensorFlowLiteSwift
Pod firmy Cocoapods.
Najpierw musisz zaimportować moduł 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...
}
Załaduj i uruchom model w Objective-C
Platforma: iOS
API Objective-C jest dostępne w TensorFlowLiteObjC
Pod firmy Cocoapods.
Najpierw musisz zaimportować moduł 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... */ }
Używanie C API w kodzie Objective-C
Obecnie interfejs API Objective-C nie obsługuje delegatów. Aby używać delegatów z kodem Objective-C, musisz bezpośrednio wywoływać podstawowy interfejs API języka C.
#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);
Załaduj i uruchom model w C++
Platformy: Android, iOS i Linux
W C++ model jest przechowywany w klasie FlatBufferModel
. Zawiera model TensorFlow Lite i można go zbudować na kilka różnych sposobów, w zależności od tego, gdzie jest przechowywany model:
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);
};
Teraz, gdy masz model jako obiekt FlatBufferModel
, możesz go wykonać za pomocą Interpreter
. Pojedynczy FlatBufferModel
może być używany jednocześnie przez więcej niż jednego Interpreter
.
W poniższym fragmencie kodu przedstawiono ważne części interfejsu API Interpreter
. Należy zauważyć że:
- Tensory są reprezentowane przez liczby całkowite, aby uniknąć porównań łańcuchów (i wszelkich stałych zależności od bibliotek ciągów).
- Nie należy uzyskiwać dostępu do interpretera z współbieżnych wątków.
- Alokacja pamięci dla tensorów wejściowych i wyjściowych musi zostać wywołana przez wywołanie
AllocateTensors()
zaraz po zmianie rozmiaru tensorów.
Najprostsze użycie TensorFlow Lite z C++ wygląda następująco:
// 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);
Aby uzyskać więcej przykładowego kodu, zobacz minimal.cc
i label_image.cc
.
Załaduj i uruchom model w Pythonie
Platforma: Linuks
Interfejs API języka Python do uruchamiania wnioskowania jest dostępny w module tf.lite
. Z tego najczęściej potrzebujesz tylko tf.lite.Interpreter
, aby załadować model i uruchomić wnioskowanie.
Poniższy przykład pokazuje, jak użyć interpretera języka Python do załadowania pliku .tflite
i uruchomienia wnioskowania z losowymi danymi wejściowymi:
Ten przykład jest zalecany w przypadku konwersji z SavedModel ze zdefiniowanym SignatureDef. Dostępne począwszy od 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'])
Inny przykład, jeśli model nie ma zdefiniowanych 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)
Jako alternatywę dla ładowania modelu jako wstępnie przekonwertowanego pliku .tflite
, możesz połączyć swój kod z interfejsem API TensorFlow Lite Converter Python ( tf.lite.TFLiteConverter
), co pozwoli Ci przekonwertować model TensorFlow do formatu TensorFlow Lite, a następnie uruchom wnioskowanie:
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...
Aby uzyskać więcej przykładowego kodu języka Python, zobacz label_image.py
.
Uruchom wnioskowanie z dynamicznym modelem kształtu
Jeśli chcesz uruchomić model z dynamicznym kształtem wejściowym, zmień rozmiar kształtu wejściowego przed uruchomieniem wnioskowania. W przeciwnym razie kształt None
w modelach Tensorflow zostanie zastąpiony symbolem zastępczym 1
w modelach TFLite.
Poniższe przykłady pokazują, jak zmienić rozmiar kształtu wejściowego przed uruchomieniem wnioskowania w różnych językach. We wszystkich przykładach przyjęto założenie, że kształt wejściowy jest zdefiniowany jako [1/None, 10]
i należy zmienić jego rozmiar na [3, 10]
.
Obsługiwane operacje
TensorFlow Lite obsługuje podzbiór operacji TensorFlow z pewnymi ograniczeniami. Pełna lista operacji i ograniczeń znajduje się na stronie TF Lite Ops .