Mit ML Kit können Sie die Inferenz auf dem Gerät mit einem TensorFlow Lite-Modell ausführen.
Für diese API ist Android SDK-Level 16 (Jelly Bean) oder höher erforderlich.
Hinweis
- Falls noch nicht geschehen, fügen Sie Ihrem Android-Projekt Firebase hinzu.
- Fügen Sie die Abhängigkeiten für die ML Kit Android-Bibliotheken in die Gradle-Datei Ihres Moduls (auf App-Ebene, in der Regel
app/build.gradle
) ein:apply plugin: 'com.android.application' apply plugin: 'com.google.gms.google-services' dependencies { // ... implementation 'com.google.firebase:firebase-ml-model-interpreter:22.0.3' }
- Konvertieren Sie das TensorFlow-Modell, das Sie verwenden möchten, in das TensorFlow Lite-Format. Weitere Informationen finden Sie unter TOCO: TensorFlow Lite Optimizing Converter.
Modell hosten oder bündeln
Bevor Sie ein TensorFlow Lite-Modell für die Inferenz in Ihrer App verwenden können, müssen Sie es für ML Kit verfügbar machen. Für ML Kit können TensorFlow Lite-Modelle verwendet werden, die remote mit Firebase gehostet werden, im App-Binärpaket enthalten sind oder beides.
Wenn Sie ein Modell auf Firebase hosten, können Sie es aktualisieren, ohne eine neue App-Version zu veröffentlichen. Außerdem können Sie mit Remote Config und A/B Testing verschiedenen Nutzergruppen dynamisch unterschiedliche Modelle bereitstellen.
Wenn Sie das Modell nur über Firebase hosten und nicht in Ihre App einbinden, können Sie die ursprüngliche Downloadgröße Ihrer App verringern. Wenn das Modell jedoch nicht in Ihre App eingebunden ist, sind alle modellbezogenen Funktionen erst verfügbar, wenn Ihre App das Modell zum ersten Mal herunterlädt.
Wenn Sie Ihr Modell mit Ihrer App bündeln, können Sie dafür sorgen, dass die ML-Funktionen Ihrer App auch dann funktionieren, wenn das in Firebase gehostete Modell nicht verfügbar ist.
Modelle in Firebase hosten
So hosten Sie Ihr TensorFlow Lite-Modell auf Firebase:
- Klicken Sie im Bereich ML Kit der Firebase-Konsole auf den Tab Benutzerdefiniert.
- Klicken Sie auf Benutzerdefiniertes Modell hinzufügen (oder Weiteres Modell hinzufügen).
- Geben Sie einen Namen an, der zur Identifizierung Ihres Modells in Ihrem Firebase-Projekt verwendet wird, und laden Sie dann die TensorFlow Lite-Modelldatei hoch (die normalerweise auf
.tflite
oder.lite
endet). - Deklarieren Sie im Manifest Ihrer App, dass die INTERNET-Berechtigung 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 anhand des von Ihnen angegebenen Namens auf das Modell 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. Sie können die Gerätebedingungen festlegen, die erfüllt sein müssen, damit Ihre App versucht, das Modell zu aktualisieren (siehe unten).
Modelle mit einer App bündeln
Wenn Sie Ihr TensorFlow Lite-Modell mit Ihrer App bündeln möchten, kopieren Sie die Modelldatei (die normalerweise auf .tflite
oder .lite
endet) in den Ordner assets/
Ihrer App. Möglicherweise müssen Sie den Ordner zuerst erstellen. Klicken Sie dazu mit der rechten Maustaste auf den Ordner app/
und dann auf Neu > Ordner > Assets-Ordner.
Fügen Sie dann der Datei build.gradle
Ihrer App Folgendes hinzu, damit Gradle die Modelle beim Erstellen der App nicht komprimiert:
android {
// ...
aaptOptions {
noCompress "tflite" // Your model's file extension: "tflite", "lite", etc.
}
}
Die Modelldatei wird in das App-Paket aufgenommen und ist für ML Kit als Roh-Asset verfügbar.
Modell laden
Wenn Sie Ihr TensorFlow Lite-Modell in Ihrer App verwenden möchten, müssen Sie ML Kit zuerst mit den Speicherorten konfigurieren, an denen Ihr Modell verfügbar ist: remote über Firebase, im lokalen Speicher oder beides. Wenn Sie sowohl ein lokales als auch ein Remote-Modell angeben, können Sie das Remote-Modell verwenden, sofern es verfügbar ist, und auf das lokal gespeicherte Modell zurückgreifen, wenn das Remote-Modell nicht verfügbar ist.In Firebase gehostetes Modell konfigurieren
Wenn Sie Ihr Modell mit Firebase gehostet haben, erstellen Sie ein FirebaseCustomRemoteModel
-Objekt und geben Sie den Namen an, den Sie dem Modell beim Hochladen zugewiesen haben:
Java
FirebaseCustomRemoteModel remoteModel =
new FirebaseCustomRemoteModel.Builder("your_model").build();
Kotlin
val remoteModel = FirebaseCustomRemoteModel.Builder("your_model").build()
Starten Sie dann die Aufgabe zum Herunterladen des Modells und geben Sie die Bedingungen an, unter denen Sie das Herunterladen zulassen möchten. Wenn das Modell nicht auf dem Gerät vorhanden ist oder eine neuere Version des Modells verfügbar ist, wird das Modell asynchron von Firebase heruntergeladen:
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
val conditions = FirebaseModelDownloadConditions.Builder()
.requireWifi()
.build()
FirebaseModelManager.getInstance().download(remoteModel, conditions)
.addOnCompleteListener {
// Success.
}
Viele Apps starten den Downloadvorgang in ihrem Initialisierungscode, aber Sie können dies jederzeit tun, bevor Sie das Modell verwenden müssen.
Lokales Modell konfigurieren
Wenn Sie das Modell mit Ihrer App gebündelt haben, erstellen Sie ein FirebaseCustomLocalModel
-Objekt und geben Sie den Dateinamen des TensorFlow Lite-Modells an:
Java
FirebaseCustomLocalModel localModel = new FirebaseCustomLocalModel.Builder()
.setAssetFilePath("your_model.tflite")
.build();
Kotlin
val localModel = FirebaseCustomLocalModel.Builder()
.setAssetFilePath("your_model.tflite")
.build()
Interpreter aus Ihrem Modell erstellen
Nachdem Sie die Modellquellen konfiguriert haben, erstellen Sie ein FirebaseModelInterpreter
-Objekt aus einer der Quellen.
Wenn Sie nur ein lokal gebündeltes Modell haben, erstellen Sie einfach einen Interpreter aus Ihrem FirebaseCustomLocalModel
-Objekt:
Java
FirebaseModelInterpreter interpreter;
try {
FirebaseModelInterpreterOptions options =
new FirebaseModelInterpreterOptions.Builder(localModel).build();
interpreter = FirebaseModelInterpreter.getInstance(options);
} catch (FirebaseMLException e) {
// ...
}
Kotlin
val options = FirebaseModelInterpreterOptions.Builder(localModel).build()
val interpreter = FirebaseModelInterpreter.getInstance(options)
Wenn Sie ein Modell haben, das auf einem Remote-Server gehostet wird, müssen Sie prüfen, ob es heruntergeladen wurde, bevor Sie es ausführen. Sie können den Status des Modelldownloads mit der Methode isModelDownloaded()
des Modellmanagers prüfen.
Sie müssen dies zwar nur vor dem Ausführen des Interpreters bestätigen, aber wenn Sie sowohl ein remote gehostetes als auch ein lokal gebündeltes Modell haben, kann es sinnvoll sein, diese Prüfung beim Instanziieren des Modellinterpreters durchzuführen: Erstellen Sie einen Interpreter aus dem Remote-Modell, wenn es heruntergeladen wurde, und andernfalls aus dem 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
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-Modell haben, sollten Sie modellbezogene Funktionen deaktivieren, z. B. einen Teil der Benutzeroberfläche ausblenden oder ausgrauen, bis Sie bestätigen, dass das Modell heruntergeladen wurde. Dazu können Sie einen Listener an die download()
-Methode des Modellmanagers anhängen:
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
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 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 Dimensionen („Form“) der Arrays konfigurieren, die von Ihrem Modell verwendet werden.
Wenn Sie die Form und den Datentyp der Ein- und Ausgabe Ihres Modells nicht kennen, können Sie den TensorFlow Lite Python-Interpreter verwenden, um Ihr Modell zu untersuchen. 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 festgelegt haben, können Sie den Modellinterpreter Ihrer App konfigurieren, indem Sie ein FirebaseModelInputOutputOptions
-Objekt erstellen.
Ein Gleitkomma-Modell zur Bildklassifizierung kann beispielsweise ein Nx224x224x3-Array mit float
-Werten als Eingabe verwenden, das einen Batch von N 224x224-Bildern mit drei Kanälen (RGB) darstellt, und als Ausgabe eine Liste mit 1.000 float
-Werten erzeugen, die jeweils die Wahrscheinlichkeit darstellen, dass das Bild zu einer der 1.000 Kategorien gehört, die das Modell vorhersagt.
Für ein solches Modell würden Sie die Ein- und Ausgabe des Modellinterpreters so 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
val inputOutputOptions = FirebaseModelInputOutputOptions.Builder() .setInputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 224, 224, 3)) .setOutputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 5)) .build()
Inferenz für Eingabedaten durchführen
Um schließlich die 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.Wenn Sie beispielsweise ein Bildklassifizierungsmodell mit einer Eingabeform von [1 224 224 3] Gleitkommawerten haben, können Sie ein Eingabearray aus einem Bitmap
-Objekt generieren, 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
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 Ihren Eingabedaten und übergeben Sie es zusammen mit der Ein- und Ausgabespezifikation des Modells an die run
-Methode des Modellinterpreters:
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
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 getOutput()
-Methode des Objekts aufrufen, das an den Erfolgs-Listener übergeben wird. Beispiel:
Java
float[][] output = result.getOutput(0); float[] probabilities = output[0];
Kotlin
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 als Nächstes die Indexe des Ergebnisses den Labels zuordnen, die sie repräsentieren:
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
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 verfügbar machen, speichert ML Kit sie im standardmäßigen serialisierten Protobuf-Format im lokalen Speicher.
Theoretisch bedeutet das, dass jeder Ihr Modell kopieren kann. In der Praxis sind die meisten Modelle jedoch so anwendungsspezifisch und durch Optimierungen verschleiert, dass das Risiko ähnlich hoch ist wie das Risiko, dass Wettbewerber Ihren Code disassemblieren und wiederverwenden. Sie sollten sich dieses Risikos jedoch bewusst sein, bevor Sie ein benutzerdefiniertes Modell in Ihrer App verwenden.
Unter Android API‑Level 21 (Lollipop) und höher wird das Modell in ein Verzeichnis heruntergeladen, das vom automatischen Backup ausgeschlossen ist.
Unter Android-API-Level 20 und älter wird das Modell in ein Verzeichnis mit dem Namen com.google.firebase.ml.custom.models
im app-privaten internen Speicher heruntergeladen. Wenn Sie die Dateisicherung mit BackupAgent
aktiviert haben, können Sie dieses Verzeichnis ausschließen.