Wenn Ihre App benutzerdefinierte TensorFlow Lite-Modelle verwendet, können Sie Firebase ML verwenden, um Ihre Modelle bereitzustellen. Durch die Bereitstellung von Modellen mit Firebase können Sie die anfängliche Downloadgröße Ihrer App reduzieren und die ML-Modelle Ihrer App aktualisieren, ohne eine neue Version Ihrer App zu veröffentlichen. Mit Remote Config und A/B Testing können Sie außerdem verschiedenen Nutzergruppen dynamisch unterschiedliche Modelle bereitstellen.
TensorFlow Lite-Modelle
TensorFlow Lite-Modelle sind ML-Modelle, die für die Ausführung auf mobilen Geräten optimiert sind. So erhalten Sie ein TensorFlow Lite-Modell:
- Verwenden Sie ein vordefiniertes Modell, z. B. eines der offiziellen TensorFlow Lite-Modelle.
- Konvertieren Sie ein TensorFlow-Modell, ein Keras-Modell oder eine konkrete Funktion in TensorFlow Lite.
Hinweis
- Falls noch nicht geschehen, fügen Sie Ihrem Android-Projekt Firebase hinzu.
-
Fügen Sie in der Gradle-Datei Ihres Moduls (auf Anwendungsebene)
(in der Regel
<project>/<app-module>/build.gradle.ktsoder<project>/<app-module>/build.gradle) die Abhängigkeit für die Firebase ML Bibliothek zum Herunterladen von Modellen für Android hinzu. Wir empfehlen, die Firebase Android BoM zu verwenden, um die Bibliotheksversionierung zu steuern.Außerdem müssen Sie im Rahmen der Einrichtung des Firebase ML Modell-Downloaders das TensorFlow Lite SDK zu Ihrer App hinzufügen.
dependencies { // Import the BoM for the Firebase platform implementation(platform("com.google.firebase:firebase-bom:34.11.0")) // Add the dependency for the Firebase ML model downloader library // When using the BoM, you don't specify versions in Firebase library dependencies implementation("com.google.firebase:firebase-ml-modeldownloader")
// Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0") }Mit der Firebase Android BoM, haben Sie immer eine kompatible Version der Firebase Android-Bibliotheken in Ihrer App.
(Alternative) Firebase-Bibliotheksabhängigkeiten ohne Verwendung der BoM
Wenn Sie die Firebase BoM nicht verwenden möchten, müssen Sie jede Firebase-Bibliotheksversion in der entsprechenden Abhängigkeitszeile angeben.
Wenn Sie in Ihrer App mehrere Firebase-Bibliotheken verwenden, empfehlen wir dringend, die BoM zur Verwaltung der Bibliotheksversionen zu verwenden, um sicherzustellen, dass alle Versionen kompatibel sind.
dependencies { // Add the dependency for the Firebase ML model downloader library // When NOT using the BoM, you must specify versions in Firebase library dependencies implementation("com.google.firebase:firebase-ml-modeldownloader:26.0.1")
// Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0") } - Deklarieren Sie im Manifest Ihrer App, dass die Berechtigung „INTERNET“ erforderlich ist:
<uses-permission android:name="android.permission.INTERNET" />
1. Modell bereitstellen
Sie können Ihre benutzerdefinierten TensorFlow-Modelle entweder über die Firebase Konsole oder die Firebase Admin SDKs für Python und Node.js bereitstellen. Weitere Informationen finden Sie unter Benutzerdefinierte Modelle bereitstellen und verwalten.
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 bereitstellen
und das neue Modell auf die Geräte der Nutzer herunterladen, indem Sie
getModel() aufrufen (siehe unten).
2. Modell auf das Gerät herunterladen und einen TensorFlow Lite-Interpreter initialisieren
Wenn Sie Ihr TensorFlow Lite-Modell in Ihrer App verwenden möchten, laden Sie zuerst mit dem Firebase ML SDK die neueste Version des Modells auf das Gerät herunter. Instanziieren Sie dann einen TensorFlow Lite-Interpreter mit dem Modell.Rufen Sie zum Starten des Modell-Downloads die Methode getModel() des Modell-Downloaders auf und geben Sie den Namen an, den Sie dem Modell beim Hochladen zugewiesen haben, ob Sie immer das neueste Modell herunterladen möchten und unter welchen Bedingungen das Herunterladen zulässig sein soll.
Sie können zwischen drei Download-Verhaltensweisen wählen:
| Downloadtyp | Beschreibung |
|---|---|
| LOCAL_MODEL | Das lokale Modell vom Gerät abrufen.
Wenn kein lokales Modell verfügbar ist, verhält sich diese Option wie LATEST_MODEL. Verwenden Sie diesen Downloadtyp, wenn Sie nicht nach Modellaktualisierungen suchen möchten. Sie verwenden beispielsweise Remote Config, um Modellnamen abzurufen, und laden Modelle immer unter neuen Namen hoch (empfohlen). |
| LOCAL_MODEL_UPDATE_IN_BACKGROUND | Das lokale Modell vom Gerät abrufen und das Modell im Hintergrund aktualisieren.
Wenn kein lokales Modell verfügbar ist, verhält sich diese Option wie LATEST_MODEL. |
| LATEST_MODEL | Das neueste Modell abrufen. Wenn das lokale Modell die neueste Version ist, wird das lokale Modell zurückgegeben. Andernfalls wird das neueste Modell heruntergeladen. Dieses Verhalten blockiert, bis die neueste Version heruntergeladen wurde (nicht empfohlen). Verwenden Sie dieses Verhalten nur, wenn Sie ausdrücklich die neueste Version benötigen. |
Sie sollten modellbezogene Funktionen deaktivieren, z. B. Teile der Benutzeroberfläche ausgrauen oder ausblenden, bis Sie bestätigt haben, dass das Modell heruntergeladen wurde.
Kotlin
val conditions = CustomModelDownloadConditions.Builder()
.requireWifi() // Also possible: .requireCharging() and .requireDeviceIdle()
.build()
FirebaseModelDownloader.getInstance()
.getModel("your_model", DownloadType.LOCAL_MODEL_UPDATE_IN_BACKGROUND,
conditions)
.addOnSuccessListener { model: CustomModel? ->
// Download complete. Depending on your app, you could enable the ML
// feature, or switch from the local model to the remote model, etc.
// The CustomModel object contains the local path of the model file,
// which you can use to instantiate a TensorFlow Lite interpreter.
val modelFile = model?.file
if (modelFile != null) {
interpreter = Interpreter(modelFile)
}
}
Java
CustomModelDownloadConditions conditions = new CustomModelDownloadConditions.Builder()
.requireWifi() // Also possible: .requireCharging() and .requireDeviceIdle()
.build();
FirebaseModelDownloader.getInstance()
.getModel("your_model", DownloadType.LOCAL_MODEL_UPDATE_IN_BACKGROUND, conditions)
.addOnSuccessListener(new OnSuccessListener<CustomModel>() {
@Override
public void onSuccess(CustomModel model) {
// Download complete. Depending on your app, you could enable the ML
// feature, or switch from the local model to the remote model, etc.
// The CustomModel object contains the local path of the model file,
// which you can use to instantiate a TensorFlow Lite interpreter.
File modelFile = model.getFile();
if (modelFile != null) {
interpreter = new Interpreter(modelFile);
}
}
});
Viele Apps starten die Downloadaufgabe in ihrem Initialisierungscode, Sie können dies aber auch jederzeit tun, bevor Sie das Modell verwenden müssen.
3. Inferenz für Eingabedaten ausführen
Eingabe- und Ausgabegrößen Ihres Modells abrufen
Der TensorFlow Lite-Modell-Interpreter verwendet ein oder mehrere mehrdimensionale Arrays als Eingabe und erzeugt ein oder mehrere mehrdimensionale Arrays als Ausgabe. Diese Arrays enthalten entweder
byte, int, long oder float
Werte. Bevor Sie Daten an ein Modell übergeben oder das Ergebnis verwenden können, müssen Sie
die Anzahl und die Dimensionen („Größe“) der Arrays kennen, die Ihr Modell verwendet.
Wenn Sie das Modell selbst erstellt haben oder das Eingabe- und Ausgabeformat des Modells dokumentiert ist, haben Sie diese Informationen möglicherweise bereits. Wenn Sie die Größe und den Datentyp der Eingabe und Ausgabe Ihres Modells nicht kennen, können Sie das Modell mit dem TensorFlow Lite-Interpreter untersuchen. Beispiel:
Python
import tensorflow as tf interpreter = tf.lite.Interpreter(model_path="your_model.tflite") interpreter.allocate_tensors() # Print input shape and type inputs = interpreter.get_input_details() print('{} input(s):'.format(len(inputs))) for i in range(0, len(inputs)): print('{} {}'.format(inputs[i]['shape'], inputs[i]['dtype'])) # Print output shape and type outputs = interpreter.get_output_details() print('\n{} output(s):'.format(len(outputs))) for i in range(0, len(outputs)): print('{} {}'.format(outputs[i]['shape'], outputs[i]['dtype']))
Beispielausgabe:
1 input(s): [ 1 224 224 3] <class 'numpy.float32'> 1 output(s): [1 1000] <class 'numpy.float32'>
Interpreter ausführen
Nachdem Sie das Format der Eingabe und Ausgabe Ihres Modells bestimmt haben, rufen Sie Ihre Eingabedaten ab und führen Sie alle Transformationen an den Daten aus, die erforderlich sind, um eine Eingabe mit der richtigen Größe für Ihr Modell zu erhalten.Wenn Sie beispielsweise ein Bildklassifizierungsmodell mit einer Eingabegröße von [1 224 224 3] Gleitkommawerten haben, können Sie wie im folgenden Beispiel gezeigt einen Eingabe-ByteBuffer aus einem Bitmap-Objekt generieren:
Kotlin
val bitmap = Bitmap.createScaledBitmap(yourInputImage, 224, 224, true)
val input = ByteBuffer.allocateDirect(224*224*3*4).order(ByteOrder.nativeOrder())
for (y in 0 until 224) {
for (x in 0 until 224) {
val px = bitmap.getPixel(x, y)
// Get channel values from the pixel value.
val r = Color.red(px)
val g = Color.green(px)
val b = Color.blue(px)
// Normalize channel values to [-1.0, 1.0]. This requirement depends on the model.
// For example, some models might require values to be normalized to the range
// [0.0, 1.0] instead.
val rf = (r - 127) / 255f
val gf = (g - 127) / 255f
val bf = (b - 127) / 255f
input.putFloat(rf)
input.putFloat(gf)
input.putFloat(bf)
}
}
Java
Bitmap bitmap = Bitmap.createScaledBitmap(yourInputImage, 224, 224, true);
ByteBuffer input = ByteBuffer.allocateDirect(224 * 224 * 3 * 4).order(ByteOrder.nativeOrder());
for (int y = 0; y < 224; y++) {
for (int x = 0; x < 224; x++) {
int px = bitmap.getPixel(x, y);
// Get channel values from the pixel value.
int r = Color.red(px);
int g = Color.green(px);
int b = Color.blue(px);
// Normalize channel values to [-1.0, 1.0]. This requirement depends
// on the model. For example, some models might require values to be
// normalized to the range [0.0, 1.0] instead.
float rf = (r - 127) / 255.0f;
float gf = (g - 127) / 255.0f;
float bf = (b - 127) / 255.0f;
input.putFloat(rf);
input.putFloat(gf);
input.putFloat(bf);
}
}
Weisen Sie dann einen ByteBuffer zu, der groß genug ist, um die Ausgabe des Modells zu enthalten, und übergeben Sie den Eingabe- und Ausgabepuffer an die Methode run() des TensorFlow Lite-Interpreters. Beispiel für eine Ausgabegröße von [1 1000] Gleitkommawerten:
Kotlin
val bufferSize = 1000 * java.lang.Float.SIZE / java.lang.Byte.SIZE
val modelOutput = ByteBuffer.allocateDirect(bufferSize).order(ByteOrder.nativeOrder())
interpreter?.run(input, modelOutput)
Java
int bufferSize = 1000 * java.lang.Float.SIZE / java.lang.Byte.SIZE;
ByteBuffer modelOutput = ByteBuffer.allocateDirect(bufferSize).order(ByteOrder.nativeOrder());
interpreter.run(input, modelOutput);
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 Indexe des Ergebnisses den Labels zuordnen, die sie darstellen:
Kotlin
modelOutput.rewind()
val probabilities = modelOutput.asFloatBuffer()
try {
val reader = BufferedReader(
InputStreamReader(assets.open("custom_labels.txt")))
for (i in probabilities.capacity()) {
val label: String = reader.readLine()
val probability = probabilities.get(i)
println("$label: $probability")
}
} catch (e: IOException) {
// File not found?
}
Java
modelOutput.rewind();
FloatBuffer probabilities = modelOutput.asFloatBuffer();
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(getAssets().open("custom_labels.txt")));
for (int i = 0; i < probabilities.capacity(); i++) {
String label = reader.readLine();
float probability = probabilities.get(i);
Log.i(TAG, String.format("%s: %1.4f", label, probability));
}
} catch (IOException e) {
// File not found?
}
Anhang: Modellsicherheit
Unabhängig davon, wie Sie Ihre TensorFlow Lite-Modelle für Firebase ML verfügbar machen, werden sie inFirebase ML im standardmäßigen serialisierten Protobuf-Format in lokalen Speicher gespeichert.
Theoretisch kann also jeder Ihr Modell kopieren. 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 von der automatischen Sicherung ausgeschlossen ist.
Unter Android API-Level 20 und älter wird das Modell in ein Verzeichnis
namens com.google.firebase.ml.custom.models im privaten
internen Speicher der App heruntergeladen. Wenn Sie die Dateisicherung mit BackupAgent,
aktiviert haben, können Sie dieses Verzeichnis ausschließen.