Se la tua app utilizza modelli TensorFlow Lite personalizzati, puoi utilizzare Firebase ML per eseguire il deployment dei modelli. Se esegui il deployment dei modelli con Firebase, puoi ridurre le dimensioni del download iniziale della tua app e aggiornare i modelli di ML dell'app senza rilasciare una nuova versione. Inoltre, con Remote Config e A/B Testing, puoi pubblicare dinamicamente modelli diversi per diversi gruppi di utenti.
Modelli TensorFlow Lite
I modelli TensorFlow Lite sono modelli ML ottimizzati per essere eseguiti su dispositivi mobili. Per ottenere un modello TensorFlow Lite:
- Utilizza un modello predefinito, ad esempio uno dei modelli TensorFlow Lite ufficiali.
- Converti un modello TensorFlow, un modello Keras o una funzione concreta in TensorFlow Lite.
Prima di iniziare
- Se non l'hai ancora fatto, aggiungi Firebase al tuo progetto Android.
-
Nel file Gradle (a livello di app) del modulo
(di solito
<project>/<app-module>/build.gradle.kts
o<project>/<app-module>/build.gradle
), aggiungi la dipendenza per la libreria di download dei modelli Firebase ML per Android. Ti consigliamo di utilizzare Firebase Android BoM per controllare il controllo delle versioni della libreria.Inoltre, nell'ambito della configurazione del downloader di modelli Firebase ML, devi aggiungere l'SDK TensorFlow Lite alla tua app.
dependencies { // Import the BoM for the Firebase platform implementation(platform("com.google.firebase:firebase-bom:34.0.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") }Utilizzando la Firebase Android BoM, la tua app utilizzerà sempre versioni compatibili delle librerie Firebase Android.
(Alternativa) Aggiungi le dipendenze della libreria Firebase senza utilizzare BoM
Se scegli di non utilizzare la Firebase BoM, devi specificare ogni versione della libreria Firebase nella riga della dipendenza.
Tieni presente che se utilizzi più librerie Firebase nella tua app, ti consigliamo vivamente di utilizzare la BoM per gestire le versioni delle librerie, in modo da garantire la compatibilità di tutte le versioni.
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.0")
// Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0") } - Nel manifest della tua app, dichiara che è necessaria l'autorizzazione INTERNET:
<uses-permission android:name="android.permission.INTERNET" />
1. Esegui il deployment del modello
Esegui il deployment dei tuoi modelli TensorFlow personalizzati utilizzando la console Firebase o gli SDK Firebase Admin Python e Node.js. Consulta Eseguire il deployment e gestire modelli personalizzati.
Dopo aver aggiunto un modello personalizzato al tuo progetto Firebase, puoi fare riferimento al
modello nelle tue app usando il nome specificato. In qualsiasi momento, puoi eseguire il deployment di un nuovo modello TensorFlow Lite e scaricarlo sui dispositivi degli utenti chiamando getModel()
(vedi sotto).
2. Scarica il modello sul dispositivo e inizializza un interprete TensorFlow Lite
Per utilizzare il modello TensorFlow Lite nella tua app, utilizza prima l'SDK Firebase ML per scaricare l'ultima versione del modello sul dispositivo. Quindi, crea un'istanza di un interprete TensorFlow Lite con il modello.Per avviare il download del modello, chiama il metodo getModel()
del downloader del modello,
specificando il nome che hai assegnato al modello quando lo hai caricato, se
vuoi scaricare sempre l'ultimo modello e le condizioni in cui
vuoi consentire il download.
Puoi scegliere tra tre comportamenti di download:
Tipo di download | Descrizione |
---|---|
LOCAL_MODEL | Recupera il modello locale dal dispositivo.
Se non è disponibile alcun modello locale, questo
si comporta come LATEST_MODEL . Utilizza questo
tipo di download se non ti interessa
verificare la presenza di aggiornamenti del modello. Ad esempio,
utilizzi Remote Config per recuperare
i nomi dei modelli e carichi sempre i modelli
con nuovi nomi (opzione consigliata). |
LOCAL_MODEL_UPDATE_IN_BACKGROUND | Recupera il modello locale dal dispositivo e
inizia ad aggiornarlo in background.
Se non è disponibile alcun modello locale, questo
si comporta come LATEST_MODEL . |
LATEST_MODEL | Acquista l'ultimo modello. Se il modello locale è l'ultima versione, restituisce il modello locale. In caso contrario, scarica l'ultimo modello. Questo comportamento verrà bloccato finché non verrà scaricata l'ultima versione (non consigliato). Utilizza questo comportamento solo nei casi in cui hai esplicitamente bisogno dell'ultima versione. |
Devi disattivare le funzionalità correlate al modello, ad esempio oscurare o nascondere parte della tua UI, finché non confermi che il modello è stato scaricato.
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);
}
}
});
Molte app avviano l'attività di download nel codice di inizializzazione, ma puoi farlo in qualsiasi momento prima di dover utilizzare il modello.
3. Esegue l'inferenza sui dati di input
Ottenere le forme di input e output del modello
L'interprete del modello TensorFlow Lite prende come input e produce come output
uno o più array multidimensionali. Questi array contengono valori
byte
, int
, long
o float
. Prima di poter trasmettere dati a un modello o utilizzarne il risultato, devi conoscere
il numero e le dimensioni ("forma") degli array utilizzati dal modello.
Se hai creato il modello autonomamente o se il formato di input e output del modello è documentato, potresti già disporre di queste informazioni. Se non conosci la forma e il tipo di dati dell'input e dell'output del modello, puoi utilizzare l'interprete TensorFlow Lite per esaminare il modello. Ad esempio:
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']))
Output di esempio:
1 input(s): [ 1 224 224 3] <class 'numpy.float32'> 1 output(s): [1 1000] <class 'numpy.float32'>
Esegui l'interprete
Dopo aver determinato il formato dell'input e dell'output del modello, recupera i dati di input ed esegui le trasformazioni necessarie per ottenere un input della forma corretta per il modello.Ad esempio, se hai un modello di classificazione delle immagini con una forma di input di
[1 224 224 3]
valori in virgola mobile, puoi generare un input ByteBuffer
da un oggetto Bitmap
come mostrato nel seguente esempio:
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);
}
}
Poi, alloca un ByteBuffer
sufficientemente grande da contenere l'output del modello e
passa il buffer di input e il buffer di output al metodo
run()
dell'interprete TensorFlow Lite. Ad esempio, per una forma di output di valori
in virgola mobile [1 1000]
:
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);
Il modo in cui utilizzi l'output dipende dal modello che stai utilizzando.
Ad esempio, se esegui la classificazione, come passaggio successivo potresti mappare gli indici del risultato alle etichette che rappresentano:
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?
}
Appendice: Sicurezza del modello
Indipendentemente da come rendi disponibili i tuoi modelli TensorFlow Lite per Firebase ML, Firebase ML li memorizza nel formato protobuf serializzato standard nello spazio di archiviazione locale.
In teoria, questo significa che chiunque può copiare il tuo modello. Tuttavia, in pratica, la maggior parte dei modelli è così specifica per l'applicazione e offuscata dalle ottimizzazioni che il rischio è simile a quello dei concorrenti che disassemblano e riutilizzano il tuo codice. Tuttavia, devi essere consapevole di questo rischio prima di utilizzare un modello personalizzato nella tua app.
A partire dal livello API 21 (Lollipop) di Android, il modello viene scaricato in una directory esclusa dal backup automatico.
Nei livelli API Android 20 e precedenti, il modello viene scaricato in una directory
denominata com.google.firebase.ml.custom.models
nella memoria interna
privata dell'app. Se hai attivato il backup dei file utilizzando BackupAgent
,
potresti scegliere di escludere questa directory.