TensorFlow Lite-Inferenz

Der Begriff bezieht sich auf den Inferenz - Prozeß ein TensorFlow Lite - Modell , um auf dem Gerät auszuführen , um Vorhersagen basierend auf Eingangsdaten zu machen. Zur Durchführung einer Inferenz mit einem Modell TensorFlow Lite, müssen Sie es mit Hilfe eines Dolmetschers geführt. Der TensorFlow Lite-Interpreter ist schlank und schnell konzipiert. Der Interpreter verwendet eine statische Diagrammreihenfolge und einen benutzerdefinierten (weniger dynamischen) Speicherzuordner, um eine minimale Last, Initialisierung und Ausführungslatenz sicherzustellen.

Diese Seite beschreibt , wie der Zugriff auf das TensorFlow Lite - Interpreter und führen Sie eine Folgerung unter Verwendung von C ++, Java und Python sowie Links zu anderen Ressourcen für jede unterstützte Plattform .

Wichtige Konzepte

Die TensorFlow Lite-Inferenz folgt normalerweise den folgenden Schritten:

  1. Laden eines Modells

    Sie müssen die Last .tflite Modell in den Speicher, die die Ausführung Graph des Modells enthält.

  2. Transformieren von Daten

    Roheingabedaten für das Modell stimmen im Allgemeinen nicht mit dem vom Modell erwarteten Eingabedatenformat überein. Beispielsweise müssen Sie möglicherweise die Größe eines Bilds ändern oder das Bildformat ändern, damit es mit dem Modell kompatibel ist.

  3. Laufende Inferenz

    In diesem Schritt wird die TensorFlow Lite-API verwendet, um das Modell auszuführen. Es umfasst einige Schritte wie das Erstellen des Interpreters und das Zuweisen von Tensoren, wie in den folgenden Abschnitten beschrieben.

  4. Ausgabe interpretieren

    Wenn Sie Ergebnisse aus der Modellinferenz erhalten, müssen Sie die Tensoren in einer sinnvollen Weise interpretieren, die für Ihre Anwendung nützlich ist.

    Ein Modell kann beispielsweise nur eine Liste von Wahrscheinlichkeiten zurückgeben. Es liegt an Ihnen, die Wahrscheinlichkeiten relevanten Kategorien zuzuordnen und sie Ihrem Endbenutzer zu präsentieren.

Unterstützte Plattformen

TensorFlow Inferenz - APIs sind für die gängigsten mobilen / Embedded - Plattformen wie vorgesehen Android , iOS und Linux , in mehreren Programmiersprachen.

In den meisten Fällen spiegelt das API-Design eine Präferenz für Leistung gegenüber Benutzerfreundlichkeit wider. TensorFlow Lite wurde für schnelle Inferenz auf kleinen Geräten entwickelt, daher sollte es keine Überraschung sein, dass die APIs versuchen, unnötige Kopien auf Kosten der Benutzerfreundlichkeit zu vermeiden. Ebenso war die Konsistenz mit den TensorFlow-APIs kein explizites Ziel, und es ist mit einigen Abweichungen zwischen den Sprachen zu rechnen.

In allen Bibliotheken ermöglicht Ihnen die TensorFlow Lite-API das Laden von Modellen, das Einspeisen von Eingaben und das Abrufen von Inferenzausgaben.

Android-Plattform

Unter Android kann die TensorFlow Lite-Inferenz entweder mit Java- oder C++-APIs durchgeführt werden. Die Java-APIs bieten Komfort und können direkt in Ihren Android-Aktivitätsklassen verwendet werden. Die C++-APIs bieten mehr Flexibilität und Geschwindigkeit, erfordern jedoch möglicherweise das Schreiben von JNI-Wrappern, um Daten zwischen Java- und C++-Schichten zu verschieben.

Siehe unten für Details über die Verwendung von C ++ und Java , oder folgen Sie dem Android Quickstart für ein Tutorial und Beispielcode.

TensorFlow Lite Android-Wrapper-Code-Generator

Für TensorFlow Lite - Modell mit erweiterten Metadaten , können Entwickler den TensorFlow Lite Android - Wrapper - Code - Generator verwenden , um plattformspezifische Wrapper - Code zu erstellen. Der Wrapper - Code beseitigt die Notwendigkeit , zu interagieren direkt mit ByteBuffer auf Android. Stattdessen können Entwickler mit dem TensorFlow Lite - Modell mit typisierte Objekte wie interagieren Bitmap und Rect . Weitere Informationen entnehmen Sie bitte den TensorFlow Lite Android - Wrapper - Code - Generator .

iOS-Plattform

Auf iOS - Geräten ist TensorFlow Lite verfügbar mit nativen iOS - Bibliotheken geschrieben in Swift und Objective-C . Sie können auch mit C - API direkt in Objective-C - Codes.

Siehe unten für Einzelheiten über die Verwendung von Swift , Objective-C und C - API , oder folgen Sie dem iOS Quickstart für ein Tutorial und Beispielcode.

Linux-Plattform

Auf Linux - Plattformen (einschließlich Raspberry Pi ), können Sie Rückschlüsse mit TensorFlow Lite APIs in ausführen C ++ und Python , wie in den folgenden Abschnitten dargestellt.

Ein Modell ausführen

Das Ausführen eines TensorFlow Lite-Modells umfasst einige einfache Schritte:

  1. Laden Sie das Modell in den Speicher.
  2. Bauen Sie sich ein Interpreter basierend auf einem vorhandenen Modell.
  3. Eingabe-Tensorwerte einstellen. (Passen Sie optional die Größe der Eingabetensoren an, wenn die vordefinierten Größen nicht erwünscht sind.)
  4. Inferenz aufrufen.
  5. Lesen Sie die Ausgangstensorwerte.

In den folgenden Abschnitten wird beschrieben, wie diese Schritte in jeder Sprache ausgeführt werden können.

Laden und Ausführen eines Modells in Java

Plattform: Android

Der Java - API für einen Schluß mit TensorFlow Lite läuft in erster Linie für den Einsatz mit Android entwickelt, so dass es als Android - Bibliothek Abhängigkeit vorhanden ist: org.tensorflow:tensorflow-lite .

In Java, werden Sie die verwenden Interpreter Klasse ein Modell und Antriebsmodell Inferenz zu laden. In vielen Fällen ist dies möglicherweise die einzige API, die Sie benötigen.

Sie können einen initialisieren Interpreter mit einer .tflite - Datei:

public Interpreter(@NotNull File modelFile);

Oder mit einem MappedByteBuffer :

public Interpreter(@NotNull MappedByteBuffer mappedByteBuffer);

In beiden Fällen müssen Sie ein gültiges TensorFlow Lite - Modell zur Verfügung stellen oder die API wirft IllegalArgumentException . Wenn Sie MappedByteBuffer einen initialisieren Interpreter , muss sie unverändert für die gesamte Lebensdauer des bleiben Interpreter .

Die bevorzugte Methode zum Ausführen von Inferenz für ein Modell ist die Verwendung von Signaturen - Verfügbar für Modelle, die ab Tensorflow 2.5 . konvertiert wurden

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");
}

Die runSignature Methode nimmt drei Argumente:

  • Eingänge: Karte für Eingänge von Eingangsnamen in der Signatur zu einem Eingabeobjekt.

  • Ausgänge: Karte für die Ausgabe Zuordnung von Ausgabenamen zur Ausgabe von Daten in Unterschrift.

  • Unterschrift Name [optional]: Unterschrift Name (kann leer gelassen werden , wenn das Modell einzelne Signatur).

Eine andere Möglichkeit, eine Inferenz auszuführen, wenn das Modell keine definierten Signaturen hat. Rufen Sie einfach Interpreter.run() . Beispielsweise:

try (Interpreter interpreter = new Interpreter(file_of_a_tensorflowlite_model)) {
  interpreter.run(input, output);
}

Die run() Methode nimmt nur einen Eingang und gibt nur einen Ausgang. Wenn Ihr Modell also mehrere Eingänge oder mehrere Ausgänge hat, verwenden Sie stattdessen:

interpreter.runForMultipleInputsOutputs(inputs, map_of_indices_to_outputs);

In diesem Fall wird jeder Eintrag in inputs entsprechen einen Eingang Tensor und map_of_indices_to_outputs abbildet Indizes Ausgabe Tensoren mit den entsprechenden Ausgangsdaten.

In beiden Fällen sollten die Tensorindizes den Werten entsprechen , die Sie zu dem gab TensorFlow Lite Converter , wenn Sie das Modell erstellt. Beachten Sie, dass die Reihenfolge der Tensoren in input , um die Bestellung der TensorFlow Lite Converter gegeben übereinstimmen müssen.

Die Interpreter - Klasse bietet auch komfortable Funktionen für Sie den Index jeden Modell Eingang oder Ausgang mit einem Operationsnamen zu erhalten:

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

Wenn opName keine gültige Operation in dem Modell ist, wirft es ein IllegalArgumentException .

Auch hüte dich , dass Interpreter besitzt Ressourcen. Um einen Speicherverlust zu vermeiden, müssen die Ressourcen nach der Verwendung freigegeben werden durch:

interpreter.close();

Ein Beispiel finden Sie Projekt mit Java, die Android Bildklassifizierungs- Probe .

Unterstützte Datentypen (in Java)

Um TensorFlow Lite verwenden zu können, müssen die Datentypen der Eingabe- und Ausgabetensoren einer der folgenden primitiven Typen sein:

  • float
  • int
  • long
  • byte

String - Typen werden ebenfalls unterstützt, aber sie sind anders als die primitiven Typen codiert. Insbesondere bestimmt die Form eines String-Tensors die Anzahl und Anordnung der Strings im Tensor, wobei jedes Element selbst ein String variabler Länge ist. In diesem Sinne kann die (byte) Größe des Tensors nicht von der Form und Art allein berechnet werden, und folglich können nicht - Strings als eine einzelne, flache vorgesehen sein ByteBuffer Argument.

Wenn andere Datentypen, einschließlich boxed Typen wie Integer und Float , verwendet werden, wird eine IllegalArgumentException werden geworfen.

Eingänge

Jeder Eingang sollte ein Array oder mehrdimensionales Array des unterstützten Urtyps oder ein roh ByteBuffer der entsprechenden Größe. Wenn die Eingabe ein Array oder ein mehrdimensionales Array ist, wird der zugehörige Eingabetensor zum Zeitpunkt der Inferenz implizit auf die Dimensionen des Arrays angepasst. Wenn die Eingabe ein ByteBuffer ist, sollte der Anrufer zuerst die Größe manuell den zugehörigen Eingang Tensor (via Interpreter.resizeInput() ) , bevor Inferenz ausgeführt wird .

Bei der Verwendung von ByteBuffer bevorzugt direkten Byte - Puffer, da dies das ermöglicht Interpreter unnötige Kopien zu vermeiden. Wenn die ByteBuffer ein direkter Byte - Puffer ist, muss seine Ordnung sein ByteOrder.nativeOrder() . Nachdem es für eine Modellinferenz verwendet wurde, muss es unverändert bleiben, bis die Modellinferenz abgeschlossen ist.

Ausgänge

Jede Ausgabe sollte ein Array oder mehrdimensionales Array der unterstützten primitiven Typen oder ein ByteBuffer der entsprechenden Größe sein. Beachten Sie, dass einige Modelle dynamische Ausgaben haben, bei denen die Form der Ausgabetensoren je nach Eingabe variieren kann. Dies lässt sich mit der bestehenden Java-Inferenz-API nicht einfach handhaben, aber geplante Erweiterungen werden dies ermöglichen.

Laden und Ausführen eines Modells in Swift

Plattform: iOS

Die Swift API ist verfügbar TensorFlowLiteSwift Pod von Cocoapods.

Zuerst müssen Sie importieren TensorFlowLite Modul.

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

Laden und Ausführen eines Modells in Objective-C

Plattform: iOS

Der Objective-C - TensorFlowLiteObjC API ist in verfügbar TensorFlowLiteObjC Pod von Cocoapods.

Zuerst müssen Sie importieren TensorFlowLite Modul.

@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... */ }

Verwenden der C-API in Objective-C-Code

Derzeit unterstützt die Objective-C-API keine Delegaten. Um den Einsatz Delegierten mit Objective-C - Code, müssen Sie direkt anrufen zugrunde liegenden C - API .

#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);

Laden und Ausführen eines Modells in C++

Plattformen: Android, iOS und Linux

In C ++ wird das Modell in gespeichert FlatBufferModel Klasse. Es kapselt ein TensorFlow Lite-Modell und Sie können es auf verschiedene Arten erstellen, je nachdem, wo das Modell gespeichert ist:

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);
};

Nun , da Sie das Modell als haben FlatBufferModel Objekt, können Sie es mit einem ausführen Interpreter . Ein einzelner FlatBufferModel kann von mehr als einem gleichzeitig verwendet werden Interpreter .

Die wichtigen Teile der Interpreter API sind in der gezeigten Code - Snippet unten. Es sollte angemerkt werden, dass:

  • Tensoren werden durch Ganzzahlen dargestellt, um String-Vergleiche (und jede feste Abhängigkeit von String-Bibliotheken) zu vermeiden.
  • Auf einen Interpreter darf nicht von gleichzeitigen Threads aus zugegriffen werden.
  • Speicherzuweisung für die Ein- und Ausgabe Tensoren muß durch den Aufruf ausgelöst wird AllocateTensors() direkt nach dem Tensor Ändern der Größe.

Die einfachste Verwendung von TensorFlow Lite mit C++ sieht so aus:

// 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);

Weitere Beispiel - Code finden Sie minimal.cc und label_image.cc .

Laden und Ausführen eines Modells in Python

Plattform: Linux

Der Python API zum Ausführen eine Inferenz in dem bereitgestellten tf.lite Modul. Von denen, müssen Sie meist nur tf.lite.Interpreter ein Modell zu laden und eine Folgerung auszuführen.

Das folgende Beispiel zeigt , wie Sie das Python - Interpreter verwenden , um eine laden .tflite Datei und starten Sie Inferenz mit zufälligen Eingangsdaten:

Dieses Beispiel wird empfohlen, wenn Sie von SavedModel mit einer definierten SignatureDef konvertieren. Erhältlich ab 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'])

Ein weiteres Beispiel, wenn für das Modell keine SignatureDefs definiert sind.

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)

Als Alternative das Modell als bereits konvertierte zum Laden .tflite Datei, können Sie Ihren Code mit dem kombinieren TensorFlow Lite Converter Python API ( tf.lite.TFLiteConverter ), so dass Sie Ihre TensorFlow Modell in das TensorFlow Lite - Format konvertieren und dann Inferenz ausführen:

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

Weitere Python Beispielcode finden label_image.py .

Tipp: Führen Sie help(tf.lite.Interpreter) in der Python - Terminal eine detaillierte Dokumentation über den Dolmetscher zu bekommen.

Unterstützte Operationen

TensorFlow Lite unterstützt mit einigen Einschränkungen eine Teilmenge von TensorFlow-Vorgängen. Die vollständige Auflistung der Operationen und Einschränkungen siehe TF Lite Ops Seite .