Si votre application utilise des modèles TensorFlow Lite personnalisés, vous pouvez utiliser Firebase ML pour les déployer. En déployant des modèles avec Firebase, vous pouvez réduire la taille de téléchargement initiale de votre application et mettre à jour ses modèles de ML sans publier une nouvelle version de votre application. De plus, avec Remote Config et A/B Testing, vous pouvez diffuser dynamiquement différents modèles auprès de différents ensembles d'utilisateurs.
Modèles TensorFlow Lite
Les modèles TensorFlow Lite sont des modèles de ML optimisés pour s'exécuter sur des appareils mobiles. Pour obtenir un modèle TensorFlow Lite:
- Utilisez un modèle prédéfini, tel que l'un des modèles TensorFlow Lite officiels.
- Convertissez un modèle TensorFlow, un modèle Keras ou une fonction concrète en TensorFlow Lite.
Avant de commencer
- Si ce n'est pas encore fait, ajoutez Firebase à votre projet Android.
-
Dans votre fichier Gradle de votre module (au niveau de l'application) (généralement
<project>/<app-module>/build.gradle.kts
ou<project>/<app-module>/build.gradle
), ajoutez la dépendance pour la bibliothèque de téléchargement de modèles Firebase ML pour Android. Nous vous recommandons d'utiliser Firebase Android BoM pour contrôler le contrôle des versions de la bibliothèque.En outre, lors de la configuration du téléchargeur de modèles Firebase ML, vous devez ajouter le SDK TensorFlow Lite à votre application.
dependencies { // Import the BoM for the Firebase platform implementation(platform("com.google.firebase:firebase-bom:33.7.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") }En utilisant Firebase Android BoM, votre application utilisera toujours des versions compatibles des bibliothèques Firebase Android.
(Alternative) Ajoutez des dépendances de bibliothèque Firebase sans utiliser BoM.
Si vous choisissez de ne pas utiliser Firebase BoM, vous devez spécifier chaque version de la bibliothèque Firebase dans sa ligne de dépendance.
Notez que si vous utilisez plusieurs bibliothèques Firebase dans votre application, nous vous recommandons vivement d'utiliser BoM pour gérer les versions de la bibliothèque, ce qui garantit que toutes les versions sont compatibles.
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:25.0.1")
// Also add the dependency for the TensorFlow Lite library and specify its version implementation("org.tensorflow:tensorflow-lite:2.3.0") } - Dans le fichier manifeste de votre application, déclarez que l'autorisation INTERNET est requise:
<uses-permission android:name="android.permission.INTERNET" />
1. Déployer le modèle
Déployez vos modèles TensorFlow personnalisés à l'aide de la console Firebase ou des SDK Python et Node.js Firebase Admin. Consultez la section Déployer et gérer des modèles personnalisés.
Une fois que vous avez ajouté un modèle personnalisé à votre projet Firebase, vous pouvez le référencer dans vos applications à l'aide du nom que vous avez spécifié. Vous pouvez à tout moment déployer un nouveau modèle TensorFlow Lite et le télécharger sur les appareils des utilisateurs en appelant getModel()
(voir ci-dessous).
2. Télécharger le modèle sur l'appareil et initialiser un interpréteur TensorFlow Lite
Pour utiliser votre modèle TensorFlow Lite dans votre application, commencez par utiliser le SDK Firebase ML pour télécharger la dernière version du modèle sur l'appareil. Ensuite, instanciez un interpréteur TensorFlow Lite avec le modèle.Pour démarrer le téléchargement du modèle, appelez la méthode getModel()
du téléchargeur de modèles, en spécifiant le nom que vous avez attribué au modèle lorsque vous l'avez importé, si vous souhaitez toujours télécharger le dernier modèle et les conditions dans lesquelles vous souhaitez autoriser le téléchargement.
Vous avez le choix entre trois comportements de téléchargement:
Type de téléchargement | Description |
---|---|
LOCAL_MODEL | Obtenez le modèle local à partir de l'appareil.
Si aucun modèle local n'est disponible, ce comportement est identique à LATEST_MODEL . Utilisez ce type de téléchargement si vous ne souhaitez pas vérifier les mises à jour du modèle. Par exemple, vous utilisez Remote Config pour récupérer les noms de modèles et vous importez toujours des modèles sous de nouveaux noms (recommandé). |
LOCAL_MODEL_UPDATE_IN_BACKGROUND | Obtenez le modèle local à partir de l'appareil et commencez à le mettre à jour en arrière-plan.
Si aucun modèle local n'est disponible, ce comportement est identique à LATEST_MODEL . |
LATEST_MODEL | Obtenez le dernier modèle. Si le modèle local est la dernière version, renvoie le modèle local. Sinon, téléchargez le dernier modèle. Ce comportement bloquera l'application jusqu'à ce que la dernière version soit téléchargée (non recommandé). N'utilisez ce comportement que lorsque vous avez explicitement besoin de la dernière version. |
Vous devez désactiver les fonctionnalités liées au modèle (par exemple, griser ou masquer une partie de votre UI) jusqu'à ce que vous confirmiez que le modèle a été téléchargé.
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);
}
}
});
De nombreuses applications démarrent la tâche de téléchargement dans leur code d'initialisation, mais vous pouvez le faire à tout moment avant d'avoir besoin d'utiliser le modèle.
3. Effectuer des inférences sur les données d'entrée
Obtenir les formes d'entrée et de sortie de votre modèle
L'interpréteur de modèle TensorFlow Lite utilise une ou plusieurs matrices multidimensionnelles en entrée et en produit une ou plusieurs en sortie. Ces tableaux contiennent des valeurs byte
, int
, long
ou float
. Avant de pouvoir transmettre des données à un modèle ou d'utiliser son résultat, vous devez connaître le nombre et les dimensions ("shape") des tableaux que votre modèle utilise.
Si vous avez créé le modèle vous-même ou si le format d'entrée et de sortie du modèle est documenté, vous disposez peut-être déjà de ces informations. Si vous ne connaissez pas la forme et le type de données des entrées et des sorties de votre modèle, vous pouvez utiliser l'interprète TensorFlow Lite pour inspecter votre modèle. Exemple :
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']))
Exemple de résultat :
1 input(s): [ 1 224 224 3] <class 'numpy.float32'> 1 output(s): [1 1000] <class 'numpy.float32'>
Exécuter l'interpréteur
Une fois que vous avez déterminé le format des entrées et des sorties de votre modèle, obtenez vos données d'entrée et effectuez les transformations nécessaires pour obtenir une entrée de la bonne forme pour votre modèle.Par exemple, si vous disposez d'un modèle de classification d'images avec une forme d'entrée de valeurs à virgule flottante [1 224 224 3]
, vous pouvez générer une ByteBuffer
d'entrée à partir d'un objet Bitmap
, comme illustré dans l'exemple suivant:
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);
}
}
Ensuite, allouez un ByteBuffer
suffisamment grand pour contenir la sortie du modèle et transmettez le tampon d'entrée et le tampon de sortie à la méthode run()
de l'interpréteur TensorFlow Lite. Par exemple, pour une forme de sortie de valeurs à virgule flottante [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);
La manière dont vous utilisez la sortie dépend du modèle que vous utilisez.
Par exemple, si vous effectuez une classification, vous pouvez ensuite mapper les indices du résultat sur les libellés qu'ils représentent:
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?
}
Annexe: Sécurité du modèle
Quelle que soit la manière dont vous mettez vos modèles TensorFlow Lite à la disposition de Firebase ML, Firebase ML les stocke au format protobuf sérialisé standard dans l'espace de stockage local.
En théorie, cela signifie que n'importe qui peut copier votre modèle. Toutefois, en pratique, la plupart des modèles sont tellement spécifiques à l'application et masqués par des optimisations que le risque est semblable à celui de vos concurrents qui désassemblent et réutilisent votre code. Toutefois, vous devez être conscient de ce risque avant d'utiliser un modèle personnalisé dans votre application.
Sous Android API 21 (Lollipop) ou version ultérieure, le modèle est téléchargé dans un répertoire exclu de la sauvegarde automatique.
Sous Android API 20 ou version antérieure, le modèle est téléchargé dans un répertoire nommé com.google.firebase.ml.custom.models
dans l'espace de stockage interne privé de l'application. Si vous avez activé la sauvegarde de fichiers à l'aide de BackupAgent
, vous pouvez choisir d'exclure ce répertoire.