Se la tua app utilizza modelli TensorFlow Lite personalizzati, puoi utilizzare Firebase ML per distribuire i tuoi modelli. Distribuendo i modelli con Firebase, puoi ridurre le dimensioni iniziali del download della tua app e aggiornare i modelli ML della tua app senza rilasciare una nuova versione della tua app. Inoltre, con Remote Config e A/B Testing, puoi offrire dinamicamente diversi modelli a diversi gruppi di utenti.
Modelli TensorFlow Lite
I modelli TensorFlow Lite sono modelli ML ottimizzati per l'esecuzione 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 già fatto, aggiungi Firebase al tuo progetto Android .
- Nel file Gradle del tuo modulo (a livello di app) (di solito
<project>/<app-module>/build.gradle.kts
o<project>/<app-module>/build.gradle
), aggiungi la dipendenza per Firebase ML libreria Android downloader di modelli. Ti consigliamo di utilizzare la distinta base Android di Firebase per controllare il controllo delle versioni della libreria.Inoltre, come parte della configurazione del downloader di modelli Firebase ML, devi aggiungere l'SDK TensorFlow Lite alla tua app.
Kotlin+KTX
dependencies { // Import the BoM for the Firebase platform implementation(platform("com.google.firebase:firebase-bom:32.3.1")) // 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-ktx")
// Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0") }Utilizzando Firebase Android BoM , la tua app utilizzerà sempre versioni compatibili delle librerie Firebase Android.
(Alternativa) Aggiungi le dipendenze della libreria Firebase senza utilizzare la distinta base
Se scegli di non utilizzare Firebase BoM, devi specificare ogni versione della libreria Firebase nella relativa riga di dipendenza.
Tieni presente che se utilizzi più librerie Firebase nella tua app, ti consigliamo vivamente di utilizzare la distinta base per gestire le versioni della libreria, che garantisce che tutte le versioni siano compatibili.
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-ktx:24.1.3")
// Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0") }Java
dependencies { // Import the BoM for the Firebase platform implementation(platform("com.google.firebase:firebase-bom:32.3.1")) // 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 Firebase Android BoM , la tua app utilizzerà sempre versioni compatibili delle librerie Firebase Android.
(Alternativa) Aggiungi le dipendenze della libreria Firebase senza utilizzare la distinta base
Se scegli di non utilizzare Firebase BoM, devi specificare ogni versione della libreria Firebase nella relativa riga di dipendenza.
Tieni presente che se utilizzi più librerie Firebase nella tua app, ti consigliamo vivamente di utilizzare la distinta base per gestire le versioni della libreria, che garantisce che tutte le versioni siano compatibili.
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:24.1.3")
// 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 è richiesta l'autorizzazione INTERNET:
<uses-permission android:name="android.permission.INTERNET" />
1. Distribuisci il tuo modello
Distribuisci i tuoi modelli TensorFlow personalizzati utilizzando la console Firebase o gli SDK Firebase Admin Python e Node.js. Vedere Distribuire e gestire modelli personalizzati .
Dopo aver aggiunto un modello personalizzato al tuo progetto Firebase, puoi fare riferimento al modello nelle tue app utilizzando il nome che hai specificato. In qualsiasi momento, puoi distribuire un nuovo modello TensorFlow Lite e scaricare il nuovo modello sui dispositivi degli utenti chiamando
getModel()
(vedi sotto).2. Scarica il modello sul dispositivo e inizializza un interprete TensorFlow Lite
Per utilizzare il tuo 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 desideri scaricare sempre l'ultimo modello e le condizioni in base alle quali desideri consentire il download.Puoi scegliere tra tre comportamenti di download:
Tipo di download Descrizione MODELLO_LOCALE Ottieni il modello locale dal dispositivo. Se non è disponibile alcun modello locale, questo si comporta come LATEST_MODEL
. Utilizzare questo tipo di download se non si è interessati a controllare gli aggiornamenti del modello. Ad esempio, stai utilizzando Remote Config per recuperare i nomi dei modelli e carichi sempre i modelli con nuovi nomi (consigliato).LOCAL_MODEL_UPDATE_IN_BACKGROUND Ottieni il modello locale dal dispositivo e avvia l'aggiornamento del modello in background. Se non è disponibile alcun modello locale, questo si comporta come LATEST_MODEL
.ULTIMO_MODELLO Prendi l'ultimo modello. Se il modello locale è l'ultima versione, restituisce il modello locale. Altrimenti, scarica l'ultimo modello. Questo comportamento si bloccherà fino al download dell'ultima versione (non consigliato). Utilizzare questo comportamento solo nei casi in cui è esplicitamente necessaria la versione più recente. Devi disabilitare le funzionalità relative al modello, ad esempio disattivare o nascondere parte dell'interfaccia utente, finché non confermi che il modello è stato scaricato.
Kotlin+KTX
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 usare il modello.
3. Eseguire l'inferenza sui dati di input
Ottieni le forme di input e output del tuo 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
ofloat
. Prima di poter passare i dati a un modello o utilizzarne il risultato, è necessario conoscere il numero e le dimensioni ("forma") degli array utilizzati dal modello.Se hai creato tu stesso il modello 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 tuo modello, puoi utilizzare l'interprete TensorFlow Lite per ispezionare il tuo modello. Per esempio:
Pitone
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']))
Esempio di output:
1 input(s): [ 1 224 224 3] <class 'numpy.float32'> 1 output(s): [1 1000] <class 'numpy.float32'>
Eseguire l'interprete
Dopo aver determinato il formato dell'input e dell'output del modello, ottenere i dati di input ed eseguire le trasformazioni sui dati necessarie per ottenere un input della forma corretta per il modello.Ad esempio, se si dispone di un modello di classificazione delle immagini con una forma di input di
[1 224 224 3]
valori a virgola mobile, è possibile generare unByteBuffer
di input da un oggettoBitmap
come mostrato nell'esempio seguente:Kotlin+KTX
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); } }
Quindi, alloca un
ByteBuffer
abbastanza grande da contenere l'output del modello e passa il buffer di input e il buffer di output al metodorun()
dell'interprete TensorFlow Lite. Ad esempio, per una forma di output di[1 1000]
valori in virgola mobile:Kotlin+KTX
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 stai eseguendo la classificazione, come passaggio successivo, potresti mappare gli indici del risultato alle etichette che rappresentano:
Kotlin+KTX
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 a Firebase ML, Firebase ML li archivia nel formato protobuf serializzato standard nell'archivio 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 codice. Tuttavia, dovresti essere consapevole di questo rischio prima di usare un modello personalizzato nella tua app.
Sul livello API Android 21 (Lollipop) e versioni successive, il modello viene scaricato in una directory esclusa dal backup automatico .
Sul livello API Android 20 e versioni precedenti, il modello viene scaricato in una directory denominata
com.google.firebase.ml.custom.models
nella memoria interna privata dell'app. Se hai abilitato il backup dei file utilizzandoBackupAgent
, potresti scegliere di escludere questa directory.Salvo quando diversamente specificato, i contenuti di questa pagina sono concessi in base alla licenza Creative Commons Attribution 4.0, mentre gli esempi di codice sono concessi in base alla licenza Apache 2.0. Per ulteriori dettagli, consulta le norme del sito di Google Developers. Java è un marchio registrato di Oracle e/o delle sue consociate.
Ultimo aggiornamento 2023-09-26 UTC.
[] [] - Nel manifest della tua app, dichiara che è richiesta l'autorizzazione INTERNET: