Termin wnioskowanie odnosi się do procesu wykonywania modelu TensorFlow Lite na urządzeniu w celu prognozowania na podstawie danych wejściowych. Aby przeprowadzić wnioskowanie z modelem TensorFlow Lite, należy przeprowadzić je przez interpreter . Interpreter TensorFlow Lite został zaprojektowany tak, aby był oszczędny i szybki. Interpreter używa statycznego porządkowania wykresó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 łącza do innych zasobów dla każdej obsługiwanej platformy .
Ważne pojęcia
Wnioskowanie TensorFlow Lite zazwyczaj obejmuje następujące kroki:
Ładowanie modelu
Musisz załadować model
.tflite
do pamięci, która zawiera wykres wykonania modelu.Przekształcanie danych
Nieprzetworzone dane wejściowe dla modelu zazwyczaj nie są zgodne z formatem danych wejściowych oczekiwanym przez model. Na przykład może zajść potrzeba zmiany rozmiaru obrazu lub zmiany formatu obrazu, aby był zgodny z modelem.
Wnioskowanie biegowe
Ten krok obejmuje użycie interfejsu API TensorFlow Lite do wykonania modelu. Obejmuje kilka kroków, takich jak zbudowanie interpretera i przydzielenie tensorów, jak opisano w następnych sekcjach.
Interpretowanie wyników
Po otrzymaniu wyników z wnioskowania modelu należy zinterpretować tensory w zrozumiały sposób, który jest przydatny w aplikacji.
Na przykład model może zwracać tylko listę prawdopodobieństw. Do Ciebie należy mapowanie prawdopodobieństw do odpowiednich kategorii i prezentowanie ich użytkownikowi końcowemu.
Obsługiwane platformy
Interfejsy API wnioskowania TensorFlow są dostępne dla większości popularnych platform mobilnych / osadzonych, 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 API próbuje unikać niepotrzebnych kopii kosztem wygody. Podobnie spójność z interfejsami API TensorFlow nie była jawnym celem i należy się spodziewać pewnych rozbieżności między językami.
We wszystkich bibliotekach interfejs API TensorFlow Lite umożliwia ładowanie modeli, dane wejściowe i pobieranie wyników wnioskowania.
Platforma Android
W systemie Android wnioskowanie TensorFlow Lite można przeprowadzić przy użyciu interfejsów API języka Java lub C ++. Interfejsy API języka Java zapewniają wygodę i mogą być używane bezpośrednio w klasach aktywności Androida. Interfejsy API C ++ oferują większą elastyczność i szybkość, ale mogą wymagać pisania opakowań JNI w celu przenoszenia danych między warstwami Java i C ++.
Poniżej znajdziesz szczegółowe informacje na temat używania języka C ++ i Java lub skorzystaj z przewodnika Szybki start dla systemu Android, aby uzyskać samouczek i przykładowy kod.
Generator kodu otoki TensorFlow Lite dla Androida
W przypadku modelu TensorFlow Lite wzbogaconego o metadane programiści mogą używać generatora kodu opakowującego TensorFlow Lite dla systemu Android do tworzenia kodu opakowania specyficznego dla platformy. Kod opakowania eliminuje potrzebę bezpośredniej interakcji z ByteBuffer
w systemie Android. Zamiast tego programiści mogą współdziałać z modelem TensorFlow Lite za pomocą obiektów wpisanych, takich jak Bitmap
i Rect
. Aby uzyskać więcej informacji, zapoznaj się z generatorem kodu opakowania TensorFlow Lite dla systemu 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 również użyć C API bezpośrednio w kodach Objective-C.
Zobacz poniżej, aby uzyskać szczegółowe informacje na temat używania języka Swift , Objective-C i interfejsu API języka C , lub postępuj zgodnie z przewodnikiem Szybki start dla systemu iOS, aby uzyskać samouczek i przykładowy kod.
Platforma Linux
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.
Uruchomienie modelu
Uruchomienie modelu TensorFlow Lite obejmuje kilka prostych kroków:
- Załaduj model do pamięci.
- Zbuduj
Interpreter
oparciu o istniejący model. - Ustaw wartości tensorów wejściowych. (Opcjonalnie zmień rozmiar tensorów wejściowych, jeśli predefiniowane rozmiary nie są pożądane).
- Wywołaj wnioskowanie.
- Odczytaj wartości tensorów wyjściowych.
Poniższe sekcje opisują, jak 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 głównie do użytku z systemem Android, dlatego 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 kierowania wnioskami o modelu. W wielu przypadkach może to być jedyny potrzebny interfejs API.
Możesz zainicjować Interpreter
używając pliku .tflite
:
public Interpreter(@NotNull File modelFile);
Lub z MappedByteBuffer
:
public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer);
W obu przypadkach należy podać prawidłowy model TensorFlow Lite lub interfejs API zgłosi IllegalArgumentException
. Jeśli używasz MappedByteBuffer
do inicjalizacji Interpreter
, musi on pozostać niezmieniony przez cały okres istnienia Interpreter
.
Aby następnie przeprowadzić wnioskowanie z modelem, 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. Jeśli więc 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
mapuje indeksy tensorów wyjściowych do odpowiednich danych wyjściowych.
W obu przypadkach indeksy tensorów powinny odpowiadać wartościom nadanym konwerterowi TensorFlow Lite podczas tworzenia modelu. Należy pamiętać, że kolejność tensorów na input
musi odpowiadać kolejności podanej w konwerterze TensorFlow Lite.
Klasa Interpreter
zapewnia 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 IllegalArgumentException
.
Uważaj również, że Interpreter
posiada zasoby. 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ład klasyfikacji obrazów systemu Android .
Obsługiwane typy danych (w Javie)
Aby użyć TensorFlow Lite, typy danych tensorów wejściowych i wyjściowych muszą być jednym 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 ciągów w tensorze, przy czym każdy element jest łańcuchem o zmiennej długości. W tym sensie (bajtowego) rozmiaru Tensora nie można obliczyć na podstawie samego kształtu i typu, w związku z czym ciągi nie mogą być dostarczane jako pojedynczy, płaski argument ByteBuffer
.
Jeśli używane są inne typy danych, w tym typy pudełkowe, takie jak Integer
i Float
, zostanie IllegalArgumentException
.
Wejścia
Każde wejście powinno być tablicą lub wielowymiarową tablicą obsługiwanych typów pierwotnych lub surowym ByteBuffer
o odpowiednim rozmiarze. Jeśli dane wejściowe to tablica lub tablica wielowymiarowa, skojarzony tensor wejściowy zostanie niejawnie zmieniony na wymiary tablicy w czasie wnioskowania. Jeśli dane wejściowe to ByteBuffer, obiekt wywołujący powinien najpierw ręcznie zmienić rozmiar skojarzonego tensora wejściowego (za pośrednictwem Interpreter.resizeInput()
) przed uruchomieniem wnioskowania.
Korzystając z ByteBuffer
, preferuj używanie bezpośrednich buforów bajtowych, 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ć niezmieniona do 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 wejścia. Nie ma prostego sposobu rozwiązania tego problemu za pomocą istniejącego interfejsu API wnioskowania w języku Java, ale planowane rozszerzenia umożliwią to.
Załaduj i uruchom model w języku Swift
Platforma: iOS
Interfejs API Swift 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
Interfejs API Objective-C jest dostępny 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...
// Copy the input data to the input `TFLTensor`.
[interpreter copyData:inputData toInputTensorAtIndex:0 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... */ }
Korzystanie z interfejsu API języka C 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łać 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
. Hermetyzuje model TensorFlow Lite i możesz go zbudować na kilka różnych sposobów, w zależności od miejsca przechowywania modelu:
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
.
Ważne części interfejsu Interpreter
API są pokazane w poniższym fragmencie kodu. Należy zauważyć że:
- Tensory są reprezentowane przez liczby całkowite, aby uniknąć porównań ciągów (i wszelkich stałych zależności od bibliotek ciągów).
- Nie można uzyskiwać dostępu do interpretera z współbieżnych wątków.
- Alokacja pamięci dla tensorów wejściowych i wyjściowych musi być wyzwalana przez wywołanie
AllocateTensors()
zaraz po zmianie rozmiaru tensorów.
Najprostsze użycie TensorFlow Lite w 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ładowy kod, patrz minimal.cc
i label_image.cc
.
Załaduj i uruchom model w Pythonie
Platforma: Linux
Interfejs API Pythona do uruchamiania wnioskowania znajduje się w module tf.lite
. Z którego najczęściej potrzebujesz tylko tf.lite.Interpreter
aby załadować model i uruchomić wnioskowanie.
Poniższy przykład pokazuje, jak użyć interpretera Pythona do załadowania pliku .tflite
i uruchomienia wnioskowania z losowymi danymi wejściowymi:
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)
Alternatywą dla ładowania modelu jako wstępnie przekonwertowanego pliku .tflite
jest połączenie kodu z interfejsem API TensorFlow Lite Converter Python ( tf.lite.TFLiteConverter
), co pozwala na konwersję modelu TensorFlow do formatu TensorFlow Lite, a następnie uruchomić 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...
Więcej przykładowego kodu w Pythonie można znaleźć na stronie label_image.py
.
Wskazówka: uruchom help(tf.lite.Interpreter)
w terminalu Pythona, aby uzyskać szczegółową dokumentację dotyczącą interpretera.
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 .