ML Kit, le couteau suisse du Machine Learning sur mobile

Lors de la dernière Google I/O, Google a présenté une nouvelle boîte à outils intégrée dans Firebase : ML Kit. Elle doit vous aider, et même vous pousser à utiliser un peu plus de Machine Learning dans vos apps.

ML Kit ?

ML Kit se divise en deux parties : API et do it yourself (intégrer son propre modèle). La partie API repose sur Google Cloud Vision avec l’avantage d’être disponible via le cloud ou directement en local. ML Kit embarque 5 modèles :

  • Reconnaissance de caractères (disponible en local et sur le cloud)
  • Détection de visage (uniquement en local)
  • Lecture de codes-barres (uniquement en local)
  • Ajout de libellés à des images (disponible en local et sur le cloud)
  • Reconnaissance de points de repère (uniquement sur le cloud)

Ces 5 modèles sont basés sur de la détection / reconnaissance d’image. Mais on peut imaginer de futurs modèles sur le texte (langage naturel) ou encore la détection de son.

Le premier codeLab de découverte de ML Kit utilise la reconnaissance de caractères (et il est aussi disponible pour iOS). Les performances via le cloud semblent meilleures que celle en local. La documentation de Google Cloud Vision contient aussi le pricing (1000 appels par mois gratuitement, puis 1,50$/K) : l’addition peut vite être salée.

Mais c’est la deuxième partie sur laquelle nous allons nous attarder : on peut charger son propre modèle Tensorflow Lite dans Firebase et le récupérer sur le cloud.

Voir toujours plus grand : du Corgi au Labrador

Création du modèle

Mon dernier article traitait de corgis, je passe au niveau supérieur : reconnaître 120 races de chiens. Pour créer mon modèle, j’ai de nouveau pris le script du codeLab, et au lieu du dossier de fleurs, j’ai mis le dataset de l’Université de Stanford. Ce dataset est d’autant plus pratique qu’il est trié exactement comme le script le veut : les différentes photos de chiens triées par race, une race par dossier.

Après entraînement, je me retrouve avec le graph.pb (modèle Tensorflow, en Protocol Buffers) et le label.txt. Le but ici est d’intégrer le modèle au sein de ML Kit, et ce dernier accepte les modèles Tensorflow Lite (donc en Flat Buffers).

Pour utiliser un modèle dans une app, il faut le freeze : lui enlever les noeuds d’apprentissage qui ne sont d’aucune utilité pour notre modèle de prédiction. Ce processus allège et optimise le graphe. Tensorflow Lite nous donne l’outil Toco pour faire tout ça.

Sauf que Toco est un outil qui évolue encore, ce qui le rend instable. Il n’est du coup pas utilisable directement :

Pas de problème, on va utiliser Bazel pour utiliser Toco :

bazel run tensorflow/contrib/lite/toco:toco -- \ --input_file=$TENSORFLOW/Dog Breed Models/tf_files/retrained_graph.pb \ --output_file=$TENSORFLOW/Dog Breed Models/tf_files/optimized_graph.lite \ --input_format=TENSORFLOW_GRAPHDEF \ --output_format=TFLITE \ --input_shap=1,224,224,3 \ --input_array=input \ --output_array=final_result \ --inference_type=FLOAT \ --input_type=FLOAT

La technique de quantification permet de stocker et calculer des nombres dans un format plus compact. Tensorflow Lite utilise une quantification qui représente un nombre sur 8 bits. Un modèle quantifié est plus rapide et moins consommateur et donc idéal pour le mobile. Ce modèle n’est pas quantifié car c’est en fait un modèle ré-entraîné sur MobileNet, dont la version quantifiée ne peut pas être ré-entraînée (ce bug est connu et en cours de résolution). Mais on a un modèle !

Utilisation de ML Kit

La deuxième étape est de créer un projet ML Kit sur Firebase. Et c’est très simple : après avoir créé un projet Firebase, il suffit d’importer le modèle.

Construire son App Android

Enfin, on crée notre projet Android et on ajoute le google-services.json fourni par Firebase. Le build.gradle du projet a seulement besoin de la dépendance pour Firebase :

classpath 'com.google.gms:google-services:3.2.0'

Et dans le build.gradle de l’app, ce que demande Tensorflow Lite, ML Kit et Firebase :

android {    [...]    aaptOptions {        noCompress "tflite"    } }

dependencies {   [...]    implementation 'com.google.firebase:firebase-core:15.0.2'    implementation 'com.google.firebase:firebase-ml-model-interpreter:15.0.0' }

apply plugin: 'com.google.gms.google-services'

Dans l’interface ML Kit de Firebase, seul le modèle a été chargé, pas les labels. Il faut donc penser à ajouter les labels aux assets. Et le modèle aussi, si on veut y avoir accès en absence de connexion réseau.

Et enfin, on peut s’attaquer au code Android. Pour utiliser ML Kit, il faut préalablement initialiser un Interpreter. D’abord les options:

dataOptions = FirebaseModelInputOutputOptions.Builder() .setInputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, IMG_SIZE, IMG_SIZE, 3))             .setOutputFormat(0, FirebaseModelDataType.FLOAT32, intArrayOf(1, labels.size))             .build()

On utilise des DataType de type FLOAT32 car notre modèle n’est pas quantifié. Mon image est carrée donc IMG_SIZE correspond à la hauteur et la largeur.

La source locale (dans les assets) et la source distante (sur Firebase) :

val localSource = FirebaseLocalModelSource.Builder(ASSET)                 .setAssetFilePath("$MODEL_NAME.tflite")                 .build()

val conditions = FirebaseModelDownloadConditions.Builder().requireWifi().build() val cloudSource = FirebaseCloudModelSource.Builder(MODEL_NAME)                 .enableModelUpdates(true)                 .setInitialDownloadConditions(conditions)                 .setUpdatesDownloadConditions(conditions)                 .build()

La source distante demande des conditions. Ces conditions peuvent être d’être connecté au wifi, d’être en recharge ou/et d’être en veille. Les modèles peuvent être conséquents, et leur téléchargement doit être maîtrisé.

Maintenant, on instancie le Manager avec ces sources et on crée l’Interpreter.

FirebaseModelManager.getInstance().apply {                registerLocalModelSource(localSource)                registerCloudModelSource(cloudSource)            }

interpreter = FirebaseModelInterpreter.getInstance(                FirebaseModelOptions.Builder()                    .setCloudModelName(MODEL_NAME)                    .setLocalModelName(ASSET)                    .build()             )

Finalement, pour reconnaître la race du chien sur notre image, comme pour TF Lite, on transforme notre bitmap en ByteBuffer :

private fun fromBitmapToByteBuffer(bitmap: Bitmap): ByteBuffer {        val imgData = ByteBuffer.allocateDirect(4 * IMG_SIZE * IMG_SIZE * 3).apply {            order(ByteOrder.nativeOrder())            rewind()        }

val pixels = IntArray(IMG_SIZE * IMG_SIZE)        Bitmap.createScaledBitmap(bitmap, IMG_SIZE, IMG_SIZE, false).apply {            getPixels(pixels, 0, width, 0, 0, width, height)        }

pixels.forEach {            imgData.putFloat(((it shr 16 and 0xFF) - MEAN) / STD)            imgData.putFloat(((it shr 8 and 0xFF) - MEAN) / STD)            imgData.putFloat(((it and 0xFF) - MEAN) / STD)        }

return imgData    }

L’Interpreter prend en paramètre ce ByteBuffer (inclut dans un FirebaseModelInputs) et les options déclarées plus tôt.

val inputs= FirebaseModelInputs.Builder().add(fromBitmapToByteBuffer(bitmap)).build() interpreter     ?.run(inputs, dataOptions)     ?.addOnSuccessListener {         val output = it.getOutput<Array<FloatArray>>(0)         val label = labels                        .mapIndexed { index, label ->                            Pair(label, output[0][index])                        }                        .sortedByDescending { it.second }                        .first()

view?.displayDogBreed(label.first, label.second*100)      }      ?.addOnFailureListener {          view?.displayError()      }

Evidemment, j’ai testé cette app sur deux Corgis :

Et c’est tout bon! Même si le pourcentage sur le Corgi Cardigan (53%) est assez faible, c’est tout de même ce qu’il pense être le mieux.

Le code est disponible ici. Si vous désirez utiliser ce code, vous devez créer votre projet Firebase, récupérer le google-services.json et ajouter votre clé SHA-1.

Tensorflow Lite ou ML Kit ?

La comparaison Tensorflow Mobile et Tensorflow Lite dans cet article m’avait amené à la conclusion que Tensorflow Lite était plus optimisé mais malheureusement moins stable que Tensorflow Mobile. ML Kit embarque Tensorflow Lite pour interagir avec nos modèles, ceux qui peut poser problème sur sa stabilité.

ML Kit permet d’accéder à son propre modèle en ligne. On a donc plusieurs choix d’utilisation :

  • Mettre uniquement son modèle en ligne et ne pas l’embarquer dans l’application. On évite alors de dédoubler les modèles, mais le premier chargement est long (temps de téléchargement du modèle). La condition setInitialDownloadConditions peut être plus permissive pour faciliter le téléchargement d’une première version du modèle (attention toutefois à la taille de votre modèle : télécharger plusieurs Mo sans wifi peut être contraignant pour votre utilisateur). L’exemple est démontré sur cette branche.
  • Mettre son modèle en ligne et l’embarquer dans l’application. Le modèle est alors, après téléchargement, présent deux fois dans l’application. En contrepartie, la première utilisation se fait sans accroche.

Le code via ML Kit est plus long et complexe que Tensorflow Lite (vous pouvez trouver la même application que ci-dessus avec Tensorflow Lite ici). Dans les deux cas, votre modèle tournera en local. L’intérêt de ML Kit est de pouvoir mettre à jour son modèle, via Firebase. Les données suivantes comparent l’utilisation de ML Kit (cloud uniquement et modèle embarqué) à Tensorflow Lite. Les applications sont quasi identiques : seul l’objet de prédiction (Interpreter) change. Les données proviennent d’un One Plus 3T sous Android 8.0.0, avec un modèle pesant 5,8 Mo.

ML Kit<br><br>(modèle uniquement sur Firebase)ML Kit<br><br>(modèle embarqué)Tensorflow Lite
Taille de l’APK5,3 Mo11 Mo10,1 Mo
Taille de l’App (usage)19,09 Mo24,61 Mo21,16 Mo
Consommation CPU32 %32 %27 %

ML Kit embarque, en plus de Tensorflow Lite, 5 fonctionnalités de Google Cloud Vision. Il n’est donc pas étonnant qu’il pèse un peu plus lourd que Tensorflow Lite seul. C’est cependant l’utilisation CPU qu’il faut surveiller : ML Kit semble plus gourmand en moyenne que Tensorflow Lite seul.

Conclusion

Alors que Tensorflow Lite peine encore à être stable, Google sort ML Kit. La partie API, bien que chère, offre la puissance de Cloud Vision, déjà reconnue.

Lors de mes tests, d’un jour à l’autre, il m’était impossible d’accéder à mon modèle en ligne sur Firebase : pas de panique, ML Kit est encore en bêta. Par contre, ce qui est assez dérangeant, c’est la qualité des codeLabs et de la documentation : ils ne sont pas au niveau d’un acteur comme Google ni d’un outil comme ML Kit.

L’intérêt de ML Kit est de pouvoir mettre à jour son modèle, simplement en passant une nouvelle version à Firebase : c’est selon moi, une qualité essentielle qui manquait à Tensorflow Lite pour être poussée en production. Pouvoir faire évoluer son modèle régulièrement sans pénaliser l’utilisateur avec des mises à jour imposantes est un plus non négligeable. Cette boîte à outils du Machine learning mobile est un peu vide, mais déjà convaincante pour intégrer de l’intelligence dans nos applications. Elle abstrait légèrement Tensorflow Lite sans en perdre les avantages, et nous donne en plus les paramètres pour gérer nos modèles simplement (conditions de mise à jours du modèles, mise à disposition de plusieurs sources de modèle, etc).

J’ai la conviction que ce couteau suisse de l’intelligence n’en n’est qu’à son initialisation et qu’il pourrait devenir un standard dans l’utilisation du Machine Learning dans nos apps. Soyons patients, d’autres features vont sûrement bientôt arriver.