Verwenden Sie ein TensorFlow Lite-Modell für Inferenz mit ML Kit auf Android

Sie können ML Kit verwenden On-Device - Inferenz mit einem auszuführen TensorFlow Lite - Modell.

Diese API erfordert Android SDK Level 16 (Jelly Bean) oder neuer.

Bevor Sie beginnen

  1. Wenn Sie nicht bereits haben, fügen Sie Firebase zu dem Android - Projekt .
  2. Fügen Sie die Abhängigkeiten für die ML Kit Android - Bibliotheken zu Ihrem Modul (app-Ebene) Gradle Datei ( 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 TensorFlow-Modell, das Sie verwenden möchten, in das TensorFlow Lite-Format. Siehe TOKO: TensorFlow Lite Optimizing Converter .

Hosten oder bündeln Sie Ihr Modell

Bevor Sie ein TensorFlow Lite-Modell für Inferenz in Ihrer App verwenden können, müssen Sie das Modell für ML Kit verfügbar machen. ML Kit kann TensorFlow Lite-Modelle verwenden, die remote mit Firebase gehostet, mit der App-Binärdatei gebündelt werden oder beides.

Durch das Hosten eines Modells auf Firebase können Sie das Modell aktualisieren, ohne eine neue App-Version zu veröffentlichen, und Sie können Remote Config und A/B-Tests verwenden, um verschiedene Modelle dynamisch für verschiedene Benutzergruppen bereitzustellen.

Wenn Sie das Modell nur bereitstellen, indem Sie es mit Firebase hosten, und es nicht mit Ihrer App bündeln, können Sie die anfängliche Downloadgröße Ihrer App reduzieren. Beachten Sie jedoch, dass alle modellbezogenen Funktionen erst dann verfügbar sind, wenn Ihre App das Modell zum ersten Mal herunterlädt, wenn das Modell nicht mit Ihrer App gebündelt ist.

Indem Sie Ihr Modell mit Ihrer App bündeln, können Sie sicherstellen, dass die ML-Funktionen Ihrer App auch dann funktionieren, wenn das von Firebase gehostete Modell nicht verfügbar ist.

Modelle auf Firebase hosten

So hosten Sie Ihr TensorFlow Lite-Modell auf Firebase:

  1. Im ML Kit Abschnitt der Firebase - Konsole , klicken Sie auf die Registerkarte Benutzerdefinierte.
  2. Klicken Sie auf Hinzufügen benutzerdefiniertes Modell (oder ein anderes Modell hinzufügen).
  3. Geben Sie einen Namen, Ihr Modell in Ihrem Projekt Firebase verwendet wird zu identifizieren, dann laden Sie die TensorFlow Lite Modell - Datei ( in der Regel in endend .tflite oder .lite ).
  4. In Ihrem App Manifest erklärt , dass INTERNET Genehmigung 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 mit dem von Ihnen angegebenen Namen auf das Modell verweisen. Sie können jederzeit ein neues TensorFlow Lite-Modell hochladen, und Ihre App lädt das neue Modell herunter und verwendet es beim nächsten Neustart der App. Sie können die Gerätebedingungen definieren, die Ihre App benötigt, um zu versuchen, das Modell zu aktualisieren (siehe unten).

Modelle mit einer App bündeln

Um Ihr TensorFlow Lite - Modell mit Ihren App zu bündeln, kopieren Sie die Modell - Datei ( in der Regel in endend .tflite oder .lite ) zu Ihrer App assets/ Ordner. (Möglicherweise müssen Sie den Ordner zuerst mit der rechten Maustaste auf die erstellen app/ Ordner, dann auf Neu> Ordner> Assets Ordner.)

Dann fügen Sie den folgenden zu Ihrer App build.gradle Datei , um sicherzustellen , Gradle nicht die Modelle komprimieren , wenn die App Aufbau:

android {

    // ...

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

Die Modelldatei wird in das App-Paket aufgenommen und steht ML Kit als Rohmaterial zur Verfügung.

Laden Sie das Modell

Um Ihr TensorFlow Lite-Modell in Ihrer App zu verwenden, konfigurieren Sie zuerst ML Kit mit den Standorten, an denen Ihr Modell verfügbar ist: remote über Firebase, im lokalen Speicher oder beides. Wenn Sie sowohl ein lokales als auch ein Remotemodell angeben, können Sie das Remotemodell verwenden, sofern verfügbar, und auf das lokal gespeicherte Modell zurückgreifen, wenn das Remotemodell nicht verfügbar ist.

Konfigurieren Sie ein von Firebase gehostetes Modell

Wenn Sie Ihr Modell mit Firebase gehostet, erstellen Sie ein FirebaseCustomRemoteModel Objekt unter Angabe des Namens Sie das Modell zugewiesen , wenn Sie es hochgeladen:

Java

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

Kotlin+KTX

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

Starten Sie dann die Modell-Download-Aufgabe und geben Sie die Bedingungen an, unter denen Sie das Herunterladen zulassen möchten. Wenn sich das Modell nicht auf dem Gerät befindet oder eine neuere Version des Modells verfügbar ist, lädt die Aufgabe das Modell asynchron von Firebase herunter:

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 in ihrem Initialisierungscode, aber Sie können dies jederzeit tun, bevor Sie das Modell verwenden müssen.

Konfigurieren Sie ein lokales Modell

Wenn Sie das Modell mit Ihrer App gebündelt, erstellen Sie ein FirebaseCustomLocalModel Objekt, den Dateinamen des TensorFlow Lite - Modell festgelegt wird :

Java

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

Kotlin+KTX

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

Erstellen Sie einen Interpreter aus Ihrem Modell

Nachdem Sie Ihr Modell Quellen zu konfigurieren, ein erstellen FirebaseModelInterpreter Objekt aus einer von ihnen.

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

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 remote gehostetes Modell haben, müssen Sie überprüfen, ob es heruntergeladen wurde, bevor Sie es ausführen. Sie können den Status des Task - Modell Download Prüfen Sie die Modellmanager mit isModelDownloaded() Methode.

Obwohl Sie dies nur bestätigen müssen, bevor Sie den Interpreter ausführen, kann es sinnvoll sein, diese Prüfung bei der Instanziierung des Modellinterpreters durchzuführen, wenn Sie sowohl ein remote gehostetes Modell als auch ein lokal gebündeltes Modell haben: Erstellen Sie einen Interpreter aus dem Remote-Modell, wenn es wurde heruntergeladen und ansonsten vom lokalen Modell.

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 über ein remote gehostetes Modell verfügen, sollten Sie modellbezogene Funktionen deaktivieren, beispielsweise einen Teil Ihrer Benutzeroberfläche ausblenden oder ausblenden, bis Sie bestätigen, dass das Modell heruntergeladen wurde. Sie können dies tun , indem Sie einen Listener zum Modell Manager Anbringen download() Methode:

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

Geben Sie die Eingabe und Ausgabe des Modells an

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

Ein TensorFlow Lite-Modell verwendet als Eingabe und erzeugt als Ausgabe ein oder mehrere mehrdimensionale Arrays. Diese Arrays enthalten entweder byte , int , long oder float Werte. Sie müssen ML Kit mit der Anzahl und den Abmessungen ("Form") der Arrays konfigurieren, die Ihr Modell verwendet.

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

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 Ihres Modells Eingang und Ausgang bestimmt haben, können Sie Ihre App-Modell Interpreter konfigurieren , indem Sie eine Erstellung von FirebaseModelInputOutputOptions Objekt.

Zum Beispiel kann ein Gleitkommawert Bildklassifikationsmodell eine als Eingabe könnte nehmen N x224x224x3 Array von float - Werten, die eine Charge von N 224x224 Dreikanal (RGB) Bilder, und erzeugt als Ausgabe eine Liste von 1000 float Werten, die jeweils die Wahrscheinlichkeit, dass das Bild zu einer der 1000 Kategorien gehört, die das Modell vorhersagt.

Für ein solches Modell würden Sie die Ein- und Ausgabe des Modellinterpreters wie unten gezeigt konfigurieren:

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()

Inferenz auf Eingabedaten durchführen

Um schließlich eine Inferenz 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 mit der richtigen Form für Ihr Modell zu erhalten.

Zum Beispiel, wenn man ein Bildklassifikationsmodell mit einer Eingangs Form von [1 224 224 3] Gleitkommawerte, könnte man ein Eingangsarray von einer Erzeugung 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 Eingabedaten, und gibt ihnen und das Ein- und Ausgabespezifikation des Modells zum Modell Interpreter ‚s run - Methode:

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 erhalten , indem Sie den Aufruf getOutput() Methode des Objekts , das für den Erfolg Zuhörer übergeben wird. Beispielsweise:

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.

Wenn Sie beispielsweise eine Klassifizierung durchführen, können Sie im nächsten Schritt die Indizes des Ergebnisses den Bezeichnungen zuordnen, die sie darstellen:

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 dem ML Kit zur Verfügung stellen, speichert ML Kit sie im standardmäßigen serialisierten Protobuf-Format im lokalen Speicher.

Theoretisch bedeutet dies, dass jeder Ihr Modell kopieren kann. In der Praxis sind die meisten Modelle jedoch so anwendungsspezifisch und durch Optimierungen verschleiert, dass das Risiko ähnlich ist wie bei Konkurrenten, die Ihren Code zerlegen und wiederverwenden. Sie sollten sich dieses Risikos jedoch bewusst sein, bevor Sie ein benutzerdefiniertes Modell in Ihrer App verwenden.

Auf Android - API - Ebene 21 (Lollipop) und neuere, wird das Modell in ein Verzeichnis heruntergeladen, das wird von den automatischen Sicherung ausgeschlossen .

Auf Android - API - Ebene 20 und älter, wird das Modell auf ein Verzeichnis mit dem Namen heruntergeladen com.google.firebase.ml.custom.models in app-privaten internem Speicher. Wenn Sie Datei - Backup mit aktiviert BackupAgent , könnten Sie mit diesem Verzeichnis auszuschließen.