Flutter : Classification d'image avec TensorFlow Lite
TensorFlow est un outil d'apprentissage automatique (machine learning, ou ML pour les intimes). Vous avez peut-être déjà lu l'article de Thomas parlant de la classification d'image avec TensorFlow et de l'entrainement du modèle.
Pour ma part, je vais vous parler de TensorFlow Lite que j'ai récemment découvert. TensorFlow Lite est, comme le dit le site officiel, "un ensemble d’outils permettant aux développeurs d’exécuter des modèles TensorFlow sur des appareils mobiles, embarqué et IoT. Il permet une inférence de machine learning sur le périphérique avec une faible latence et une petite taille binaire". Autrement dit, TensorFlow fournit des modèles pré-entrainés (mais vous pouvez également utiliser vos propres modèles) et permet de les exécuter sur des appareils de type mobiles, embarqués ou microcontrollers.
Plugin tflite
En découvrant l'existance de TensorFlow Lite je me suis tout de suite dit :
"Cool, comme c'est un produit Google, tout comme Flutter, il devrait y avoir un plugin permettant d'utiliser TensorFlow Lite dans une application Flutter !"
Vous n'imaginez pas mon désespoir en voyant qu'il n'existait pas de librairie officielle pour Flutter. Heureusement, après de plus ou moins longues recherches, je suis tombée sur ce plugin non-officiel : tflite. J'ai donc choisi de l'utiliser pour ce test.
Dans cet article, nous allons créer une petite application utilisant la classification d'image. Autrement dit, nous allons créer une application reconnaissant le contenu d'une image.
Vous ne connaissez pas Flutter ? Par un heureux hasard, je peux vous rediriger vers l'article expliquant ce que c'est :)
Initialisation
Ajoutons tout d'abord une dépendance vers tflite dans notre projet (que vous avez bien évidement créé préalablement). C'est dans le fichier pubspec.yaml que ça se passe :
tflite: ^1.0.4
Puis, modifions le fichier build.gradle (android/app/build.gradle) pour ajouter les lignes suivantes dans le bloc `android` :
aaptOptions { noCompress 'tflite' noCompress 'lite' }
Ensuite, nous avons besoin de nos fameux modèles pré-entrainés. Pour cela, ajoutons un dossier Assets à la racine du projet puis copions-y les modèles choisis et téléchargés ici.
Nous pouvons maintenant référencer notre modèles (et labels associés) dans le fichier pubspec.yaml ainsi :
assets: - assets/mobilenet_v1_1.0_224.txt - assets/mobilenet_v2_1.0_224.tflite
Bien entendu, remplacez les valeurs par vos noms de fichiers.
Nous sommes maintenant fin prêts, place à l'utilisation de nos modèles.
Utilisation dès modèles
Afin d'avoir une image à classifier, nous utiliserons l'appareil photo afin de capturer une image pour ensuite l'analyser. Pour initialiser votre application en utilisant l'appareil photo, vous pouvez vous référer à la documentation officielle.
Une fois la photo prise, nous allons l'afficher dans une page nommée DisplayPictureScreen (pour suivre la documentation de la caméra). Contrairement à la documentation officielle, nous allons avoir besoin de gérer un état (state) de la page pour afficher les résultats de la classification. C'est donc ici (dans la classe DisplayPictureScreenState) que nous allons traiter notre photo.
Avant cela, il faut initialiser tflite en chargeant les modèles à l'aide de la méthode suivante :
Future loadModel() async { Tflite.close(); try { String res = await Tflite.loadModel( model: "assets/2/mobilenet_v2_1.0_224.tflite", labels: "assets/1/mobilenet_v1_1.0_224.txt", ); print(res); } on PlatformException { print('Failed to load model.'); } }
Puis nous allons traiter l'image avec la méthode :
Future recognizeImage(String imagePath) async { var recognitions = await Tflite.runModelOnImage( path: imagePath ); recognitions.sort((a, b) => b["confidence"].compareTo(a["confidence"])); recognitions.forEach((f) => f["confidence"] = f["confidence"] * 100); setState(() { _recognitions = recognitions; }); }
Cette méthode (ou plutôt Future) appelle la méthode runModelOnImage du plugin tflite puis trie les résultats de façon à avoir le résultat le plus probable (suivant l'indice de confiance) en premier et convertit l'indice de confiance en pourcentage (je trouve ça plus lisible).
Il ne nous reste plus qu'à appeler ces méthodes au bon moment pour analyser notre photo puis afficher les résultats.
Pour cela, j'ai choisi de les appeler dans la méthode initState :
@override void initState() { super.initState(); loadModel(); recognizeImage(widget.imagePath); }
Et enfin, affichons nos résultats dans la méthode build :
@override Widget build(BuildContext context) { List<Widget> stackChildren = []; stackChildren.add(Center( child: Column( children: _recognitions != null ? _recognitions.map((res) { return Text( "${res["label"]}: ${res["confidence"].toStringAsFixed(1)}%", style: TextStyle( color: Colors.white, fontSize: 20.0, ), ); }).toList() : [], ), )); return Scaffold( appBar: AppBar(title: Text('Display the Picture')), // The image is stored as a file on the device. Use the `Image.file` // constructor with the given path to display the image. body: Column(children: <Widget>[ Image.file(File(widget.imagePath)), Column(children: stackChildren) ]), ); }
Et voilà les résultats quelque peu aléatoires que j'ai pu obtenir :
TADA ! Vous avez vu mon beau PC lave-vaisselle ? :)
Pour améliorer les résultats vous pouvez tester avec d'autres modèles fournis par TensorFlow, ou encore créer vos propres modèles.
Conclusion
Pour conclure, je me suis beaucoup amusée à développer cette petite application (ok je l'admets, ce sont surtout les résultats que j'ai trouvé amusants). L'arrivée de TensorFlow Lite va permettre d'avoir des applications mobiles très puissantes. Le plugin tflite est très bien pour découvrir TensorFlow sur Flutter, mais l'impossibilité d'utiliser des modèles quantifiés (qui sont à l'occasion plus légers) est bloquante. J'ai hâte de voir des plugins (plus complets) arriver pour Flutter, ou encore Xamarin Forms.
Commentaires