« Mobile First to AI First » : Du Machine Learning dans nos applications

Fin Octobre 2017, la Droidcon UK hébergeait un talk très intéressant : My app is smarter than your app d’Erik Hellman. Ce talk abordait l’importance du Machine Learning et qu’il était temps de l’accepter à bras ouverts dans le monde du mobile. Personnalisation, reconnaissance, aide utilisateur… Les usages peuvent être nombreux. Des API diverses et variées nous offrent la possibilité d’utiliser cette intelligence à distance. Mais dans un monde où les smartphones sont de plus en plus puissants, pourquoi ne pas travailler directement sur nos devices ? C’est ainsi que TensorFlow entre dans la danse.

TensorFlow ?

Le Machine Learning est le sujet phare ces derniers temps. Il s’agit de donner à une machine la capacité d’apprendre, de déduire des patterns depuis un jeu de données. Cette même machine sera alors capable ensuite d’analyser d’autres jeux de données pour en tirer des conclusions.

TensorFlow est une librairie open source de calcul numérique. Elle a été initialement développée pour les recherches de Google sur le Machine Learning.

Le site officiel de TensorFlow propose des possibilités d’usages : reconnaissance d’image, de caractères (Google Translate), vocale et gestuelle, ainsi que de la localisation d’objet et de la classification de textes. Cette librairie est aujourd’hui utilisée chez Airbnb, Ebay ou encore Twitter.

Comment ça marche

Le site et la documentation de TensorFlow n’étant pas des plus explicites, ce sont les trois codelabs TensorFlow for Poets qui permettent une première entrée en matière. Ces codelabs traitent de la construction du modèle jusqu’à son intégration dans une application Android. Ils se basent tous sur la capacité de reconnaissance d’image.

Le codeLab contient un script python qui utilise TensorFlow. A partir d’un jeu de photos de fleurs classées par espèces, le script déduit des patterns et produit au final deux fichiers : c’est la phase d’apprentissage. Le premier est un fichier de labels, contenant les noms de toutes les espèces. Le second est le modèle. Ce modèle permet donc de déduire l’espèce d’une fleur à partir d’une photo (si l’espèce de cette fleur est présente dans le fichier de labels).

Le codeLab nous invite ensuite à pousser ce modèle dans l’application Android fournie. Cette application permet de filmer des fleurs et d’en déduire l’espèce (prédiction). Alors que dans le script Python, TensorFlow apprenait pour produire le modèle, dans l’application, il lit ce modèle en y injectant l’image produite par la caméra.

En regardant le code, on se rend compte que le contenu du modèle (ici, la prédiction d’espèces de fleurs) est indépendant du fonctionnement de l’application. Donc si le modèle change (autre chose que des fleurs), l’application fonctionnera encore. Pour tester cette hypothèse, j’ai donc récupéré sur internet une centaine d’images de corgis. Il existe deux espèces de Corgis : Pembroke et Cardigan. Je les classe donc selon ces deux espèces.

J’ai lancé le script python utilisant TensorFlow (fourni par le codeLab, le même que pour les fleurs) qui m’a produit un modèle et un fichier de labels. J’ai poussé ce modèle dans l’application Android et ai relancé le tout sur mon device.

Le résultat est assez bluffant : TensorFlow donne une solution qu’il pense vraie à 99%. Je confirme, ceci est bel et bien un superbe Pembroke.

Mais en tant que développeuse mobile, c’est l’utilisation de la librairie TensorFlow au sein d’Android qui m'intéresse ici.

Intégrer TensorFlow dans nos Apps Android

Aujourd’hui, la méthode la plus simple pour intégrer du Machine Learning dans nos applications est de faire appel à des APIs. Le Google Cloud Platform regorge de reconnaissance d’images, de vidéos ou même de textes. On peut aussi penser héberger sa solution TensorFlow sur un serveur et y faire appel au besoin.

Mais la qualité du réseau est fluctuante. On se retrouve régulièrement dans des situations où le réseau est insuffisant voir manquant. On peut vouloir aussi être plus rapide qu’un échange avec un serveur, ou même être indépendant de tous serveurs. C’est dans ces problématiques qu’intégrer TensorFlow directement sur le device est une solution.

Google propose deux solutions de Machine Learning sur mobile : TensorFlow Mobile et son nouveau petit frère, TensorFlow Lite.

TensorFlow 1.0 a été annoncé le 15 février 2017. Il contenait sa version mobile : TensorFlow Mobile. Cette version est complète ; on peut y utiliser toutes les fonctionnalités disponibles dans TensorFlow.

TensorFlow Lite est arrivé le 14 novembre 2017. Il est considéré comme une évolution de TensorFlow Mobile. Considéré comme plus léger et plus rapide que ce dernier, il n’est néanmoins qu’en preview et ne dispose donc pas de toutes les fonctionnalités de TensorFlow.

Google préconise d’utiliser TensorFlow Mobile en production tant que TensorFlow Lite est en preview. Sur le Github du projet TensorFlow, la version Lite est toujours considérée comme une contribution.

Pour comprendre ces deux versions, il existe dans le codeLab TensorFlow for Poet 2 deux versions de la même application de reconnaissance d’images. L’une utilise TensorFlow Mobile, l’autre TensorFlow Lite. Dans les deux cas, le modèle est entraîné préalablement sur desktop (apprentissage), avant d’être intégré à l’application mobile (où il sera uniquement prédictif). Il est ici question de dépecer le code pour en extraire uniquement les principes de base, et ainsi comparer leur facilité d’utilisation.

Intégration

TensorFlow Mobile

Il suffit de tirer la librairie TensorFlow Android directement du jcenter:

repositories { jcenter() }

dependencies { compile 'org.tensorflow:tensorflow-android:1.4.0' }

TensorFlow Lite

Tensorflow Lite est encore en preview. Il faut donc le tirer depuis Bintray:

android {     [...]

aaptOptions {         noCompress "tflite"         noCompress "lite"     } } repositories {     maven {         url 'https://google.bintray.com/tensorflow'     } }

dependencies {     compile 'org.tensorflow:tensorflow-lite:0.1.1' }

La propriété noCompress du bloc aaptOptions précise que les extensions tflite et lite ne doivent pas être stockées compréssées dans l’APK.

Conclusion

L'intégration est simple d'un côté comme de l'autre, même si TensorFlow Lite est encore en preview.

Utilisation

TensorFlow Mobile

TensorFlow Mobile nécessite un modèle au format Protocol Buffer. Ce modèle est donc d’abord entraîné sur desktop et ensuite intégré dans les assets du projet Android.

Ici, on utilise l’objet TensorFlowInferenceInterface. On l’initialise en lui donnant le nom du modèle, présent dans les assets (nommé graph.pb dans cet exemple) :

val modelFileName = "file:///android_asset/graph.pb" inferenceInterface = TensorFlowInferenceInterface(assetManager, modelFileName)

Avant de lancer la prédiction, il faut “nourrir” notre objet TensorFlowInferenceInterface avec l’image que l’on veut analyser. Le bitmap de l’image est donc déjà transformé en tableau de pixels avant d’être transféré dans un tableau de float (imgValues):

bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight()); for (int i = 0; i < pixels.length; ++i) { final int val = pixels[i]; imgValues[i * 3 + 0] = (((val >> 16) & 0xFF) - imageMean) / imageStd; imgValues[i * 3 + 1] = (((val >> 8) & 0xFF) - imageMean) / imageStd; imgValues[i * 3 + 2] = ((val & 0xFF) - imageMean) / imageStd; }

Le tableau de float (imgValues) “nourrit” ensuite l’objet TensorFlowInferenceInterface:

inferenceInterface.feed(inputName, imgValues, 1, size, size, 3);

La commande run lance la prédiction de l’image contenue dans imgValues grâce au modèle graph.pb:

inferenceInterface.run(outputNames);

Enfin, grâce à la commande fetch, les probabilités de chaque possibilité contenue dans le modèle sont injectées dans le tableau de float outputs.

inferenceInterface.fetch(outputName, outputs);

Il suffit après de comparer les résultats avec le tableau de labels (chargé depuis label.txt), et en extraire, par exemple, la solution la plus probable :

labelList .mapIndexed { id, label -> Pair(label, outputs[id]) } .maxBy { it.second }?.first ?: "Unknown"

TensorFlow Lite

A la différence de TensorFlow Mobile, le modèle ingéré par TensorFlow Lite doit être en Flat Buffer. Un convertisseur est proposé pour transformer un modèle produit en Protocol Buffer en Flat Buffer.

Le classificateur TensorFlow Lite est appelé Interpreter. On le crée en lui injectant le modèle, mais à la différence de TensorFlow Mobile, il faut charger dans un ByteBuffer avant (lu depuis graph.lite) :

val modelFile = activity.assets.openFd("graph.lite").let { FileInputStream(it.fileDescriptor).channel.map( FileChannel.MapMode.READ_ONLY, it.startOffset, it.declaredLength ) } tflite = Interpreter(modelFile);

Ensuite, la détermination du résultat de TensorFlow Lite se fait en une seule commande. On transforme le bitmap en tableau de pixels avant de l’injecter dans un ByteBuffer. L’Interpreter prend alors ce ByteBuffer en premier paramètre et un tableau de float vide (ouputs) en second paramètre. La commande run remplit le tableau outputs avec les probabilités de chaque label (contenu dans label.txt).

val newBitmap = Bitmap.createScaledBitmap(bitmap, SIZE_X, SIZE_Y, false) newBitmap.getPixels(pixels, 0, newBitmap.width, 0, 0, newBitmap.width, newBitmap.height) pixels.forEach { pixel -> imgData.putFloat(((pixel shr 16 and 0xFF) - mean) / std) imgData.putFloat(((pixel shr 8 and 0xFF) - mean) / std) imgData.putFloat(((pixel and 0xFF) - mean) / std) } tflite.run(imgData, outputs)

Finalement, on fait concorder le tableau de labels avec le tableau de probabilités outputs. Ici, on récupère le label le plus probable :

labelList .mapIndexed { id, label -> Pair(label, outputs[0][id]) } .maxBy { it.second }?.first ?: "Unknown"

Conclusion

Les deux versions de TensorFlow pour Android sont plutôt simples à utiliser. Mais la victoire peut revenir à TensorFlow Lite pour deux raisons :

  • TensorFlow Mobile charge son modèle depuis les assets. On ne lui donne que le nom du modèle. Mais pour mettre à jour le modèle, il faut mettre à jour l’application. La version Lite prend le modèle déjà chargé dans un ByteBuffer. On a le contrôle de l’emplacement du modèle et donc la possibilité de le modifier à distance, sans mise à jour obligatoire de l’application.
  • TensorFlow Mobile a besoin de trois étapes pour avoir un résultat (Feed, Run, Fetch). TensorFlow Lite prédit en une seule étape (Run).

Performance

Les deux versions de l’application de reconnaissance d’images ont été testées en cold start sur un Sony Xperia sous Android 7.1.1

TensorFlow MobileTensorFlow Lite
Taille APK23,3 Mo8,7 Mo
Temps de prédictionenviron 175 msenviron 135 ms
Consommation CPUenviron 30%environ 30%
Consommation MémoireVarie entre 69 et 80 MbVarie entre 51 et 61 Mb

Les résultats sont largement en faveur de TensorFlow Lite avec un APK beaucoup plus léger et un temps de prédiction plus rapide et moins coûteux.

Conclusion

TensorFlow Lite est, comme promis par Google, plus performant et facile d’utilisation. Néanmoins, on peut regretter qu’il soit encore aujourd’hui en preview, et considéré comme une contribution de la librairie TensorFlow. Il est donc encore difficile d’imaginer TensorFlow Lite en production. Mais TensorFlow Mobile reste très gourmand pour la batterie d’un smartphone.

TensorFlow, et plus généralement le Machine Learning, offre de nombreuses possibilités. On pourrait imaginer personnaliser à l’extrême une application à son utilisateur, ou de façon plus raisonnable, prédire ses choix mineurs. Mais les exemples mobiles présentés par Google sont essentiellement de la reconnaissance d’image.

Dans un environnement offline ou d’interactions rapides avec l’utilisateur, embarquer TensorFlow directement sur le device peut apporter une nouvelle dimension à nos applications. Les use cases sont encore peu nombreux mais nous avons la conviction que des problématiques liées à l’intelligence de nos smartphones vont se développer d’ici peu.

Cet article était une introduction à l’utilisation de TensorFlow en tant que développeuse Android. Dans une seconde partie, je vous présenterai l’application de TensorFlow Mobile ou Lite dans un use case réel.