TensorFlow Lite-Modell für Inferenz mit ML Kit unter Android verwenden

Mit ML Kit können Sie On-Device-Inferenzen mit einem TensorFlow Lite-Modell ausführen.

Für diese API ist das Android SDK-Level 16 (Jelly Bean) oder höher erforderlich.

Hinweis

  1. Falls noch nicht geschehen, Fügen Sie Firebase zu Ihrem Android-Projekt hinzu.
  2. Abhängigkeiten für die ML Kit-Android-Bibliotheken zu Ihrem Modul hinzufügen Gradle-Datei auf App-Ebene (in der Regel app/build.gradle):
    apply plugin: 'com.android.application'
    apply plugin: 'com.google.gms.google-services'
    
    dependencies {
      // ...
    
      implementation 'com.google.firebase:firebase-ml-model-interpreter:22.0.3'
    }
  3. Konvertieren Sie das gewünschte TensorFlow-Modell in das TensorFlow Lite-Format. Weitere Informationen finden Sie unter TOCO: TensorFlow Lite Optimization Converter.

Modell hosten oder bündeln

Bevor Sie ein TensorFlow Lite-Modell für Inferenzen in Ihrer App verwenden können, müssen Sie muss das Modell für ML Kit verfügbar gemacht werden. ML Kit kann TensorFlow Lite-Modelle verwenden, die mit Firebase aus der Ferne gehostet, im App-Binärcode gebündelt oder beides sind.

Wenn Sie ein Modell auf Firebase hosten, können Sie es aktualisieren, ohne ein neue App-Version und du kannst Remote Config und A/B Testing für Folgendes verwenden: verschiedenen Gruppen von Nutzern dynamisch verschiedene Modelle bereitstellen.

Wenn Sie das Modell nur durch das Hosting mit Firebase und nicht mit Ihrer App bündeln, können Sie die anfängliche Downloadgröße Ihrer App reduzieren. Wenn das Modell nicht in Ihrer App enthalten ist, modellbezogene Funktionen sind erst verfügbar, wenn Ihre App die um ein neues Modell zu erstellen.

Wenn Sie Ihr Modell mit Ihrer App bündeln, können Sie dafür sorgen, dass die ML-Features Ihrer App funktionieren auch, wenn das von Firebase gehostete Modell nicht verfügbar ist.

Modelle in Firebase hosten

So hosten Sie Ihr TensorFlow Lite-Modell in Firebase:

  1. Klicken Sie in der Firebase-Konsole im Abschnitt ML Kit auf den Tab Benutzerdefiniert aus.
  2. Klicken Sie auf Benutzerdefiniertes Modell hinzufügen oder Weitere Modelle hinzufügen.
  3. Geben Sie einen Namen an, mit dem das Modell in Firebase identifiziert wird und laden Sie dann die TensorFlow Lite-Modelldatei hoch, die in der Regel auf .tflite oder .lite).
  4. Deklarieren Sie im Manifest Ihrer App, dass die Berechtigung INTERNET erforderlich ist:
    <uses-permission android:name="android.permission.INTERNET" />

Nachdem Sie Ihrem Firebase-Projekt ein benutzerdefiniertes Modell hinzugefügt haben, können Sie in Ihren Apps auf das Modell mit dem angegebenen Namen verweisen. Sie können jederzeit ein neues TensorFlow Lite-Modell hochladen. Ihre App lädt das neue Modell herunter und verwendet es beim nächsten Neustart der App. Sie können festlegen, Bedingungen erfüllt, damit Ihre App versucht, das Modell zu aktualisieren (siehe unten).

Modelle mit einer App bündeln

Um Ihr TensorFlow Lite-Modell mit Ihrer App zu bündeln, kopieren Sie die Modelldatei (in der Regel mit den Endziffern .tflite oder .lite) in den Ordner assets/ Ihrer App verschieben. (Möglicherweise benötigen Sie um den Ordner zu erstellen, indem Sie mit der rechten Maustaste auf den Ordner app/ klicken und dann Neu > Ordner > Asset-Ordner.

Fügen Sie dann der Datei build.gradle Ihrer App Folgendes hinzu, damit Gradle funktioniert. werden die Modelle beim Erstellen der App nicht komprimiert:

android {

    // ...

    aaptOptions {
        noCompress "tflite"  // Your model's file extension: "tflite", "lite", etc.
    }
}

Die Modelldatei ist im App-Paket enthalten und für ML Kit verfügbar als unbearbeitetes Asset.

Modell laden

Um Ihr TensorFlow Lite-Modell in Ihrer App zu verwenden, konfigurieren Sie zuerst ML Kit mit Standorte, an denen Ihr Modell verfügbar ist: remote mit Firebase, in lokalen Speicher oder beides. Wenn Sie sowohl ein lokales als auch ein Remote-Modell angeben, können Sie das Remote-Modell verwenden, falls verfügbar, und auf das lokal gespeichertes Modell verwenden, wenn das Remote-Modell nicht verfügbar ist.

Ein von Firebase gehostetes Modell konfigurieren

Wenn Sie Ihr Modell bei Firebase gehostet haben, erstellen Sie eine FirebaseCustomRemoteModel und geben Sie den Namen an, den Sie dem Modell beim Hochladen zugewiesen haben:

Java

FirebaseCustomRemoteModel remoteModel =
        new FirebaseCustomRemoteModel.Builder("your_model").build();

Kotlin+KTX

val remoteModel = FirebaseCustomRemoteModel.Builder("your_model").build()

Starten Sie dann den Modelldownload und geben Sie die Bedingungen an, unter denen Sie den Download erlauben möchten. Wenn das Modell nicht auf dem Gerät installiert ist oder ein neueres Modell Version des Modells verfügbar ist, lädt die Aufgabe asynchron das aus Firebase verwenden:

Java

FirebaseModelDownloadConditions conditions = new FirebaseModelDownloadConditions.Builder()
        .requireWifi()
        .build();
FirebaseModelManager.getInstance().download(remoteModel, conditions)
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                // Success.
            }
        });

Kotlin+KTX

val conditions = FirebaseModelDownloadConditions.Builder()
    .requireWifi()
    .build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
    .addOnCompleteListener {
        // Success.
    }

Viele Apps starten die Download-Aufgabe im Initialisierungscode, aber Sie können bevor Sie das Modell verwenden.

Lokales Modell konfigurieren

Wenn Sie das Modell mit Ihrer App gebündelt haben, erstellen Sie eine FirebaseCustomLocalModel. -Objekt und geben Sie den Dateinamen des TensorFlow Lite-Modells an:

Java

FirebaseCustomLocalModel localModel = new FirebaseCustomLocalModel.Builder()
        .setAssetFilePath("your_model.tflite")
        .build();

Kotlin+KTX

val localModel = FirebaseCustomLocalModel.Builder()
    .setAssetFilePath("your_model.tflite")
    .build()

Interpreter aus Ihrem Modell erstellen

Nachdem Sie die Modellquellen konfiguriert haben, erstellen Sie eine FirebaseModelInterpreter Objekt aus einem von ihnen.

Wenn Sie nur ein lokal gebündeltes Modell haben, erstellen Sie einfach einen Dolmetscher in Ihrem Objekt FirebaseCustomLocalModel:

Java

FirebaseModelInterpreter interpreter;
try {
    FirebaseModelInterpreterOptions options =
            new FirebaseModelInterpreterOptions.Builder(localModel).build();
    interpreter = FirebaseModelInterpreter.getInstance(options);
} catch (FirebaseMLException e) {
    // ...
}

Kotlin+KTX

val options = FirebaseModelInterpreterOptions.Builder(localModel).build()
val interpreter = FirebaseModelInterpreter.getInstance(options)

Wenn Sie ein extern gehostetes Modell haben, müssen Sie prüfen, die Sie vor der Ausführung heruntergeladen haben. Sie können den Status des Modelldownloads mit der Methode isModelDownloaded() des Modellmanagers.

Sie müssen dies nur vor der Ausführung des Dolmetschers bestätigen. Wenn Sie ein remote gehostetes und ein lokal gebündeltes Modell haben, sinnvoll, diese Prüfung beim Instanziieren des Modellinterpreters durchzuführen: Interpreter aus dem Remote-Modell, falls es heruntergeladen wurde, und aus dem modellieren.

Java

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
        .addOnSuccessListener(new OnSuccessListener<Boolean>() {
            @Override
            public void onSuccess(Boolean isDownloaded) {
                FirebaseModelInterpreterOptions options;
                if (isDownloaded) {
                    options = new FirebaseModelInterpreterOptions.Builder(remoteModel).build();
                } else {
                    options = new FirebaseModelInterpreterOptions.Builder(localModel).build();
                }
                FirebaseModelInterpreter interpreter = FirebaseModelInterpreter.getInstance(options);
                // ...
            }
        });

Kotlin+KTX

FirebaseModelManager.getInstance().isModelDownloaded(remoteModel)
    .addOnSuccessListener { isDownloaded -> 
    val options =
        if (isDownloaded) {
            FirebaseModelInterpreterOptions.Builder(remoteModel).build()
        } else {
            FirebaseModelInterpreterOptions.Builder(localModel).build()
        }
    val interpreter = FirebaseModelInterpreter.getInstance(options)
}

Wenn Sie nur ein remote gehostetes Modell haben, sollten Sie die modellbezogenen wie z. B. das Ausgrauen oder Ausblenden eines Teils der Benutzeroberfläche, bis bestätigen Sie, dass das Modell heruntergeladen wurde. Hängen Sie hierzu einen Listener an. zur download()-Methode des Modellmanagers hinzu:

Java

FirebaseModelManager.getInstance().download(remoteModel, conditions)
        .addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void v) {
              // Download complete. Depending on your app, you could enable
              // the ML feature, or switch from the local model to the remote
              // model, etc.
            }
        });

Kotlin+KTX

FirebaseModelManager.getInstance().download(remoteModel, conditions)
    .addOnCompleteListener {
        // Download complete. Depending on your app, you could enable the ML
        // feature, or switch from the local model to the remote model, etc.
    }

Eingabe und Ausgabe des Modells angeben

Konfigurieren Sie als Nächstes die Ein- und Ausgabeformate des Modellinterpreters.

Ein TensorFlow Lite-Modell übernimmt als Eingabe und erzeugt als Ausgabe eine oder mehrere multidimensionale Arrays. Diese Arrays enthalten entweder byte, int-, long- oder float-Werte. Sie müssen ML Kit mit der Anzahl und den Dimensionen („Form“) der Arrays konfigurieren, die in Ihrem Modell verwendet werden.

Wenn Sie die Form und den Datentyp der Eingabe und Ausgabe Ihres Modells nicht kennen, können Sie Ihr Modell mit dem Python-Interpreter von TensorFlow Lite überprüfen. Beispiel:

import tensorflow as tf

interpreter = tf.lite.Interpreter(model_path="my_model.tflite")
interpreter.allocate_tensors()

# Print input shape and type
print(interpreter.get_input_details()[0]['shape'])  # Example: [1 224 224 3]
print(interpreter.get_input_details()[0]['dtype'])  # Example: <class 'numpy.float32'>

# Print output shape and type
print(interpreter.get_output_details()[0]['shape'])  # Example: [1 1000]
print(interpreter.get_output_details()[0]['dtype'])  # Example: <class 'numpy.float32'>

Nachdem Sie das Format der Ein- und Ausgabe Ihres Modells bestimmt haben, können Sie den Modellinterpreter Ihrer App konfigurieren, indem Sie einen FirebaseModelInputOutputOptions-Objekt.

Ein Gleitkomma-Bildklassifizierungsmodell kann beispielsweise Nx224x224x3-Array mit float-Werten, die eine Gruppe von N 224 x 224 Drei-Kanal-Bilder (RGB) und produzieren als Ausgabe eine Liste mit 1.000 float-Werte, die jeweils die Wahrscheinlichkeit darstellen, zu der das Bild gehört einer der 1.000 Kategorien, die das Modell vorhersagt.

Für ein solches Modell konfigurieren Sie die Eingabe und Ausgabe des Modellinterpreters wie unten gezeigt:

Java

FirebaseModelInputOutputOptions inputOutputOptions =
        new FirebaseModelInputOutputOptions.Builder()
                .setInputFormat(0, FirebaseModelDataType.FLOAT32, new int[]{1, 224, 224, 3})
                .setOutputFormat(0, FirebaseModelDataType.FLOAT32, new int[]{1, 5})
                .build();

Kotlin+KTX

val inputOutputOptions = FirebaseModelInputOutputOptions.Builder()
        .setInputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 224, 224, 3))
        .setOutputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 5))
        .build()

Inferenzen auf Eingabedaten durchführen

Um schließlich Inferenzen mit dem Modell durchzuführen, rufen Sie Ihre Eingabedaten ab und führen Sie alle Transformationen an den Daten durch, die erforderlich sind, um ein Eingabearray der richtigen Form für Ihr Modell zu erhalten.

Wenn Sie z. B. ein Bildklassifizierungsmodell mit der Eingabeform [1 224 224 3] Gleitkommazahlen ist, könnten Sie ein Eingabearray aus einer Bitmap-Objekt, wie im folgenden Beispiel gezeigt:

Java

Bitmap bitmap = getYourInputImage();
bitmap = Bitmap.createScaledBitmap(bitmap, 224, 224, true);

int batchNum = 0;
float[][][][] input = new float[1][224][224][3];
for (int x = 0; x < 224; x++) {
    for (int y = 0; y < 224; y++) {
        int pixel = bitmap.getPixel(x, y);
        // Normalize channel values to [-1.0, 1.0]. This requirement varies by
        // model. For example, some models might require values to be normalized
        // to the range [0.0, 1.0] instead.
        input[batchNum][x][y][0] = (Color.red(pixel) - 127) / 128.0f;
        input[batchNum][x][y][1] = (Color.green(pixel) - 127) / 128.0f;
        input[batchNum][x][y][2] = (Color.blue(pixel) - 127) / 128.0f;
    }
}

Kotlin+KTX

val bitmap = Bitmap.createScaledBitmap(yourInputImage, 224, 224, true)

val batchNum = 0
val input = Array(1) { Array(224) { Array(224) { FloatArray(3) } } }
for (x in 0..223) {
    for (y in 0..223) {
        val pixel = bitmap.getPixel(x, y)
        // Normalize channel values to [-1.0, 1.0]. This requirement varies by
        // model. For example, some models might require values to be normalized
        // to the range [0.0, 1.0] instead.
        input[batchNum][x][y][0] = (Color.red(pixel) - 127) / 255.0f
        input[batchNum][x][y][1] = (Color.green(pixel) - 127) / 255.0f
        input[batchNum][x][y][2] = (Color.blue(pixel) - 127) / 255.0f
    }
}

Erstellen Sie dann ein FirebaseModelInputs-Objekt mit Ihrem Eingabedaten an und übergeben Sie diese sowie die Eingabe- und Ausgabespezifikation des Modells an den Methode des Modellinterpretersrun:

Java

FirebaseModelInputs inputs = new FirebaseModelInputs.Builder()
        .add(input)  // add() as many input arrays as your model requires
        .build();
firebaseInterpreter.run(inputs, inputOutputOptions)
        .addOnSuccessListener(
                new OnSuccessListener<FirebaseModelOutputs>() {
                    @Override
                    public void onSuccess(FirebaseModelOutputs result) {
                        // ...
                    }
                })
        .addOnFailureListener(
                new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        // Task failed with an exception
                        // ...
                    }
                });

Kotlin+KTX

val inputs = FirebaseModelInputs.Builder()
        .add(input) // add() as many input arrays as your model requires
        .build()
firebaseInterpreter.run(inputs, inputOutputOptions)
        .addOnSuccessListener { result ->
            // ...
        }
        .addOnFailureListener { e ->
            // Task failed with an exception
            // ...
        }

Wenn der Aufruf erfolgreich ist, können Sie die Ausgabe abrufen, indem Sie die Methode getOutput() aufrufen. des Objekts, das an den Erfolgs-Listener übergeben wird. Beispiel:

Java

float[][] output = result.getOutput(0);
float[] probabilities = output[0];

Kotlin+KTX

val output = result.getOutput<Array<FloatArray>>(0)
val probabilities = output[0]

Wie Sie die Ausgabe verwenden, hängt vom verwendeten Modell ab.

Bei der Klassifizierung könnten Sie als nächsten Schritt ordnen Sie die Indexe des Ergebnisses den von ihnen dargestellten Labels zu:

Java

BufferedReader reader = new BufferedReader(
        new InputStreamReader(getAssets().open("retrained_labels.txt")));
for (int i = 0; i < probabilities.length; i++) {
    String label = reader.readLine();
    Log.i("MLKit", String.format("%s: %1.4f", label, probabilities[i]));
}

Kotlin+KTX

val reader = BufferedReader(
        InputStreamReader(assets.open("retrained_labels.txt")))
for (i in probabilities.indices) {
    val label = reader.readLine()
    Log.i("MLKit", String.format("%s: %1.4f", label, probabilities[i]))
}

Anhang: Modellsicherheit

Unabhängig davon, wie Sie Ihre TensorFlow Lite-Modelle für ML Kit speichert sie im standardisierten, serialisierten protobuf-Format lokalen Speicher.

Theoretisch bedeutet dies, dass jeder Ihr Modell kopieren kann. Sie können jedoch in der Praxis sind die meisten Modelle so anwendungsspezifisch Optimierungen vorzunehmen, bei denen das Risiko dem der Konkurrenz beim Auseinanderbauen und Ihren Code wiederverwenden. Sie sollten sich jedoch über dieses Risiko im Klaren sein, bevor Sie ein benutzerdefiniertes Modell in Ihrer App erstellen.

Unter Android API-Level 21 (Lollipop) und höher wird das Modell Verzeichnis, das ist aus der automatischen Sicherung ausgeschlossen werden.

Unter Android API-Level 20 und älter wird das Modell in ein Verzeichnis heruntergeladen namens com.google.firebase.ml.custom.models in app-private internen Speicher. Wenn Sie die Dateisicherung mit BackupAgent aktiviert haben, können Sie dieses Verzeichnis ausschließen.