Ta strona została przetłumaczona przez Cloud Translation API.
Switch to English

Wnioskowanie TensorFlow Lite

Termin wnioskowanie odnosi się do procesu wykonywania modelu TensorFlow Lite na urządzeniu w celu tworzenia prognoz 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.

Ta strona opisuje, jak uzyskać dostęp do interpretera TensorFlow Lite i przeprowadzać wnioskowanie przy użyciu 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:

  1. Ładowanie modelu

    Musisz załadować model .tflite do pamięci, która zawiera wykres wykonania modelu.

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

  3. 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 kolejnych sekcjach.

  4. 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 / 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 API próbuje unikać niepotrzebnych kopii kosztem wygody. Podobnie spójność z interfejsami API TensorFlow nie była wyraźnym 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 zapoznać się z samouczkiem i przykładowym kodem.

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:

  1. Załaduj model do pamięci.
  2. Zbuduj Interpreter na podstawie istniejącego modelu.
  3. Ustaw wartości tensorów wejściowych. (Opcjonalnie zmień rozmiar tensorów wejściowych, jeśli predefiniowane rozmiary nie są pożądane).
  4. Wywołaj wnioskowanie.
  5. 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 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 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 odwzorowuje indeksy tensorów wyjściowych na odpowiednie dane wyjściowe.

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 struną o zmiennej długości. W tym sensie rozmiar (bajtów) Tensora nie może być obliczony 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ą dynamiczne wyjścia, 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 radzenia sobie z tym za pomocą istniejącego interfejsu API wnioskowania Java, ale planowane rozszerzenia umożliwią to.

Załaduj i uruchom model w 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:&amp;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żna 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żywać interpretera Pythona do ładowania pliku .tflite i uruchamiania 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 języku Python 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 .