Mit Version 22.0.2 der firebase-ml-model-interpreter Bibliothek wird die neue
getLatestModelFile() Methode eingeführt, mit der der Speicherort benutzerdefinierter
Modelle auf dem Gerät abgerufen werden kann. Mit dieser Methode können Sie direkt ein TensorFlow Lite
Interpreter Objekt instanziieren, das Sie anstelle des
FirebaseModelInterpreter Wrappers verwenden können.
Dies ist der bevorzugte Ansatz. Da die TensorFlow Lite Interpreter-Version nicht mehr an die Firebase-Bibliotheksversion gekoppelt ist, haben Sie mehr Flexibilität beim Upgrade auf neue Versionen von TensorFlow Lite oder bei der Verwendung benutzerdefinierter TensorFlow Lite-Builds.
Auf dieser Seite wird beschrieben, wie Sie von FirebaseModelInterpreter zu dem
TensorFlow Lite Interpreter migrieren.
1. Projektabhängigkeiten aktualisieren
Aktualisieren Sie die Abhängigkeiten Ihres Projekts, um Version 22.0.2 (oder höher) der
firebase-ml-model-interpreter Bibliothek und die tensorflow-lite
Bibliothek einzuschließen:
Vorher
implementation("com.google.firebase:firebase-ml-model-interpreter:22.0.1")
Nachher
implementation("com.google.firebase:firebase-ml-model-interpreter:22.0.2")
implementation("org.tensorflow:tensorflow-lite:2.0.0")
2. TensorFlow Lite-Interpreter anstelle von FirebaseModelInterpreter erstellen
Anstatt einen FirebaseModelInterpreter zu erstellen, rufen Sie den Speicherort des Modells auf
dem Gerät mit getLatestModelFile() ab und verwenden Sie ihn, um einen TensorFlow Lite
Interpreter zu erstellen.
Vorher
Kotlin
val remoteModel = FirebaseCustomRemoteModel.Builder("your_model").build()
val options = FirebaseModelInterpreterOptions.Builder(remoteModel).build()
val interpreter = FirebaseModelInterpreter.getInstance(options)
Java
FirebaseCustomRemoteModel remoteModel =
new FirebaseCustomRemoteModel.Builder("your_model").build();
FirebaseModelInterpreterOptions options =
new FirebaseModelInterpreterOptions.Builder(remoteModel).build();
FirebaseModelInterpreter interpreter = FirebaseModelInterpreter.getInstance(options);
Nachher
Kotlin
val remoteModel = FirebaseCustomRemoteModel.Builder("your_model").build()
FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
.addOnCompleteListener { task ->
val modelFile = task.getResult()
if (modelFile != null) {
// Instantiate an org.tensorflow.lite.Interpreter object.
interpreter = Interpreter(modelFile)
}
}
Java
FirebaseCustomRemoteModel remoteModel =
new FirebaseCustomRemoteModel.Builder("your_model").build();
FirebaseModelManager.getInstance().getLatestModelFile(remoteModel)
.addOnCompleteListener(new OnCompleteListener<File>() {
@Override
public void onComplete(@NonNull Task<File> task) {
File modelFile = task.getResult();
if (modelFile != null) {
// Instantiate an org.tensorflow.lite.Interpreter object.
Interpreter interpreter = new Interpreter(modelFile);
}
}
});
3. Code zur Vorbereitung von Eingaben und Ausgaben aktualisieren
Mit FirebaseModelInterpreter geben Sie die Eingabe- und Ausgabegrößen des Modells an
indem Sie beim Ausführen des Interpreters ein FirebaseModelInputOutputOptions Objekt an ihn übergeben.
Für den TensorFlow Lite-Interpreter weisen Sie stattdessen ByteBuffer Objekte
mit der richtigen Größe für die Eingabe und Ausgabe Ihres Modells zu.
Wenn Ihr Modell beispielsweise eine Eingabegröße von [1 224 224 3] float Werten
und eine Ausgabegröße von [1 1000] float Werten hat, nehmen Sie die folgenden Änderungen vor:
Vorher
Kotlin
val inputOutputOptions = FirebaseModelInputOutputOptions.Builder()
.setInputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 224, 224, 3))
.setOutputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, 1000))
.build()
val input = ByteBuffer.allocateDirect(224*224*3*4).order(ByteOrder.nativeOrder())
// Then populate with input data.
val inputs = FirebaseModelInputs.Builder()
.add(input)
.build()
interpreter.run(inputs, inputOutputOptions)
.addOnSuccessListener { outputs ->
// ...
}
.addOnFailureListener {
// Task failed with an exception.
// ...
}
Java
FirebaseModelInputOutputOptions inputOutputOptions =
new FirebaseModelInputOutputOptions.Builder()
.setInputFormat(0, FirebaseModelDataType.FLOAT32, new int[]{1, 224, 224, 3})
.setOutputFormat(0, FirebaseModelDataType.FLOAT32, new int[]{1, 1000})
.build();
float[][][][] input = new float[1][224][224][3];
// Then populate with input data.
FirebaseModelInputs inputs = new FirebaseModelInputs.Builder()
.add(input)
.build();
interpreter.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
// ...
}
});
Nachher
Kotlin
val inBufferSize = 1 * 224 * 224 * 3 * java.lang.Float.SIZE / java.lang.Byte.SIZE
val inputBuffer = ByteBuffer.allocateDirect(inBufferSize).order(ByteOrder.nativeOrder())
// Then populate with input data.
val outBufferSize = 1 * 1000 * java.lang.Float.SIZE / java.lang.Byte.SIZE
val outputBuffer = ByteBuffer.allocateDirect(outBufferSize).order(ByteOrder.nativeOrder())
interpreter.run(inputBuffer, outputBuffer)
Java
int inBufferSize = 1 * 224 * 224 * 3 * java.lang.Float.SIZE / java.lang.Byte.SIZE;
ByteBuffer inputBuffer =
ByteBuffer.allocateDirect(inBufferSize).order(ByteOrder.nativeOrder());
// Then populate with input data.
int outBufferSize = 1 * 1000 * java.lang.Float.SIZE / java.lang.Byte.SIZE;
ByteBuffer outputBuffer =
ByteBuffer.allocateDirect(outBufferSize).order(ByteOrder.nativeOrder());
interpreter.run(inputBuffer, outputBuffer);
4. Code zur Ausgabeverarbeitung aktualisieren
Anstatt die Ausgabe des Modells mit der FirebaseModelOutputs
Methode des getOutput()Objekts abzurufen, konvertieren Sie die ByteBufferAusgabe in eine Struktur, die für Ihren Anwendungsfall geeignet ist.
Wenn Sie beispielsweise eine Klassifizierung durchführen, können Sie Änderungen wie die folgenden vornehmen:
Vorher
Kotlin
val output = result.getOutput(0)
val probabilities = output[0]
try {
val reader = BufferedReader(InputStreamReader(assets.open("custom_labels.txt")))
for (probability in probabilities) {
val label: String = reader.readLine()
println("$label: $probability")
}
} catch (e: IOException) {
// File not found?
}
Java
float[][] output = result.getOutput(0);
float[] probabilities = output[0];
try {
BufferedReader reader = new BufferedReader(
new InputStreamReader(getAssets().open("custom_labels.txt")));
for (float probability : probabilities) {
String label = reader.readLine();
Log.i(TAG, String.format("%s: %1.4f", label, probability));
}
} catch (IOException e) {
// File not found?
}
Nachher
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?
}