
La contribution de l’IA dans notre quotidien ne cesse de croître à travers les diverses applications rendues accessibles, comme la reconnaissance vocale, la détection de visages sur des images, les chatbots, etc. Ces technologies utilisent des algorithmes de Machine Learning pour établir des modèles prédictifs spécifiques aux besoins.
Le déploiement de l’IA sous forme d’application web ou mobile est une phase clé afin de mieux tirer profit de son apport. Nous parlons d’une API (service web) qui sera interrogée à chaque nouvelle donnée (nouvelle commande vocale, nouvelle image à identifier).
Dans cet article, nous vous présentons un cas concret de construction d’un modèle d’IA et de son déploiement via une application mobile, le tout en moins d’une heure chrono !
Azure Machine Learning Studio (AzureML) pour le modèle, Xamarin pour le déploiement
Il existe de nombreuses librairies de Machine Learning, qu’elles soient open-source ou payantes, sous forme d’API ou de logiciels. Dans le cas présent, nous utiliserons Azure Machine Learning Studio : c’est un outil permettant de créer un modèle de Machine Learning depuis un navigateur web via une interface graphique, il n’est donc pas nécessaire d’écrire une ligne de code !
AzureML studio contient les étapes essentielles du Machine Learning comme la sélection des données, leur nettoyage, l’apprentissage et la validation.
Xamarin est une suite d’outils de développement en C# pour des applications mobiles natives (Android, iOS, Windows). Il permet de développer à la fois des interfaces graphiques communes ou spécifiques à chaque système d’exploitation.
Le lien entre AzureML et Xamarin se fait grâce à une fonctionnalité particulièrement intéressante de AzureML: il s’agit de la possibilité de déployer un modèle de Machine Learning sous la forme d’un service web. Ainsi, AzureML fournit les templates des classes en C# prêtes à être utilisées dans Xamarin.
Exemple concret : identifier des arbres !
Nous présentons un exemple de Machine Learning plutôt ludique: nous souhaitons prédire l’année de plantation d’un arbre à Paris depuis ses caractéristiques (taille, circonférence et diamètre). Pour cela, nous utilisons des données issues du portail open-data de la ville de Paris (https://opendata.paris.fr/), qui recense tous les arbres parisiens. Nous décrirons dans ce qui suit les étapes pour reproduire cet exemple.
Construction du modèle avec Azure ML
L’utilisation de AzureML se fait via l’adresse https://studio.azureml.net. Une fois connecté, l’outil propose de créer des projets contenant l’expérience de machine learning. Dans notre cas, nous souhaitons prédire l’année de plantation d’un arbre.
L’expérience se compose d’un ensemble de traitements représentés par des briques. Chaque brique applique une action de transformation sur les données, les connexions représentent l’ordonnancement des briques et donc des transformations.
Nous ajoutons les différentes briques pour préparer les données et construire le modèle prédictif. Ainsi, l’expérience contient dans l’ordre les briques suivantes :
- Le jeu de données des arbres au format csv uploadé (1). Il est à noter que AzureML permet de lire plusieurs formats de fichier de données y compris des flux ou des bases de données.
- La sélection des colonnes utiles pour notre modèle (2). Nous avons retenus 4 colonnes décrivant l’espèce des arbres (exemple: chêne, platane, …), leur circonférence (en centimètres), leur hauteur (en mètres) et l’année de leur plantation qui sera la variable à prédire par le modèle.
- Le nettoyage des données (3) à travers des transformations comme la suppression des lignes d’arbres avec des données manquantes ou encore l’extraction de l’année depuis la date de plantation. La sortie du nettoyage est ensuite convertie au format dataset (4) afin d’établir le modèle prédictif.
- Le découpage de l’ensemble des données en deux sous-ensembles (5): un sous-ensemble d’apprentissage pour construire le modèle et un autre sous-ensemble de test pour évaluer le modèle. Ceci permet mesurer la performance de généralisation du modèle sur des données différentes à celles de l’apprentissage, et d’éviter le phénomène dit de “sur-apprentissage”.
- L’entraînement du modèle sur le sous-ensemble d’apprentissage (6). Nous avons utilisé l’algorithme Boosted Decision Tree Regressor (7), il présente l’avantage de combiner des informations hétérogènes ce qui correspond à la nature de nos variables (mesures, espèce, …) et de nécessiter un paramétrage minimal. L’algorithme Boosted Decision Tree Regressor produit un ensemble de règles regroupées sous forme d’arbre de décision. Dans notre cas, la décision consiste à estimer (ou régresser) l’année de plantation de l’arbre à partir d’un ensemble de conditions sur ses caractéristiques. On parle de régression puisque l’algorithme calcul une approximation de l’année (valeur quantitative).
- La brique scoring (8) permet de tester le modèle sur le sous-ensemble de test afin d’évaluer la qualité de notre modèle et d’estimer sa précision (9). Ainsi, le modèle est utilisé pour calculer les années de plantation. Ces estimations sont comparées aux années de plantation réelles afin de mesurer l’erreur du modèle. Cela nous a permis de constater que la marge d’erreur et de +/- six ans, ce qui est plutôt raisonnable.
- Afin d’utiliser le modèle sur de nouvelles données, le module de prédiction score model (11) prédit les années de plantation des arbres à partir de leur description. Le déploiement du modèle en tant que webservice s’effectue grâce à la brique webservice input (12) pour la collecte des données, et la brique webservice output (13) pour la restitution de l’année de plantation calculée. Le webservice consiste en une URL que l’on peut appeler depuis un client tel qu’un navigateur ou une application mobile.
Création de l’application mobile avec Xamarin
L’objectif est maintenant de déployer notre modèle sur une application mobile native. Nous développerons avec Xamarin une interface permettant d’interroger le service web de AzureML studio. Concrètement, l’application collecte des informations saisies sur l’espèce de l’arbre, sa circonférence et sa hauteur. En réponse, elle prédit sa date de plantation. Là aussi, l’effort de codage est minimal car AzureML studio produit le code en C# pour soumettre les données au service web et récupérer la réponse calculée. Ce qui nous permet de nous concentrer sur la création de l’application Xamarin elle même.
Pour commencer il faut créer un nouveau projet “Cross Plateform App (Xamarin)” dans Visual Studio.
Une fois le projet créé, vous devez obtenir l’arborescence suivante dans l’explorateur de solution :
Le premier projet est celui du code partagé, les autres projets sont spécifiques à chaque plateforme.
La puissance de Xamarin Forms nous permet d’écrire un seul code qui s’exécute sur toutes les plateformes mobiles. Il est toutefois possible d’écrire du code spécifique dans les projets dédiés lorsque cela s’avère nécessaire. Par exemple, la gestion de la caméra est complétement différente entre Android et iOS). Le code spécifique s’intègre ensuite facilement au code partagé par injection de dépendance.
Nous organisons notre code avec le design pattern recommandé pour les projets Xamarin : Model-View-ViewModel. Nous utilisons MainPage.xaml comme view, ajouter la classe Arbre comme Model et la classe ArbreViewModel comme ViewModel.
Comme pour les projet WPF, la View est représenté par un fichier XAML. Au moment de la préparation de cet article, Xamarin ne dispose pas encore d’éditeur graphique d’interface. Il faut donc éditer manuellement le XAML. Cette opération est toutefois simplifiée par les suggestions et la complétion automatique qu’offre Visual Studio.
NB : il est tout à fait possible d’écrire la View en tant que classe C#. Cependant, il est recommandé de le faire en XAML, pour plus de lisibilité et pour une meilleur séparation entre l’IHM et le code.
Le fichier MainPage.xaml est modifié comme suit :
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Tree" x:Class="Tree.MainPage"> <StackLayout> <Entry Text="{Binding Circonference}" Placeholder ="Circonference (cm)"/> <Entry Text="{Binding Hauteur}" Placeholder ="Hauteur (m) :"/> <Entry Text="{Binding Espece}" Placeholder ="Espèce"/> <Button Text="Envoyer" Clicked="OnSendClicked"/> <ListView x:Name="ArbreList" SeparatorVisibility="Default" SeparatorColor="Black" HasUnevenRows="True"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <Label Text="{Binding Circonference, Mode=OneWay, StringFormat='Circonference : {0}'}"/> <Label Text="{Binding Hauteur, Mode=OneWay, StringFormat='Hauteur : {0}'}"/> <Label Text="{Binding Espece, Mode=OneWay, StringFormat='Espèce : {0}'}"/> <Label Text="{Binding Annee, Mode=OneWay, StringFormat='Année de Plantation : {0}'}" TextColor="Blue" FontAttributes="Bold"/> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>
Dans cet exemple, les éléments de la vue sont entassés les uns sur les autres horizontalement grâce au StackLayout
La vue est composée de trois champs de saisie des propriétés de l’arbre, suivie d’un bouton d’envoi à l’API web d’AzureML et d’une liste pour afficher les requêtes envoyées avec leurs résultats (la prédiction de l’année de plantation).
Le lien entre les propriétés des éléments de la View et les propriétés de la ViewModel se fait par le mot clé Binding.
Dans l’exemple suivant, la propriété “Text” de l’élément de saisie est liée à la propriété Circonference de ArbreViewModel.
<Entry Text="{Binding Circonference}"
Le lien au niveau des objets se fait en C# dans la classe MainPage associée au XAML, cela définit mainpage.xaml.cs dont voici le code :
using System; using System.Collections.ObjectModel; using Xamarin.Forms; namespace Tree { public partial class MainPage : ContentPage { private ArbreViewModel ArbreViewModel { get; set; } = new ArbreViewModel(); private ObservableCollection<ArbreViewModel> ArbresList { get; set; } = new ObservableCollection<ArbreViewModel>(); public MainPage() { BindingContext = ArbreViewModel; InitializeComponent(); ArbreList.ItemsSource = ArbresList; } private async void OnSendClicked(object sender, EventArgs e) { var arbreVM = new ArbreViewModel(ArbreViewModel); ArbresList.Add(arbreVM); await arbreVM.ComputeAnnee(); } } }
L’objet ArbreViewModel est défini comme BindingContext de la vue. Ce qui permet de lier ces propriétés dans le XAML.
Une Liste de ArbreViewModel est définie par la suite comme source de données à la ListView du XAML.
NB : l’utilisation de ObservableCollection est très importante. Cette collection notifie des changements qui se produisent, ce qui permet à la vue de se mettre à jour.
Cette classe définit aussi la méthode appelée lors de l’appui sur le bouton : OnSendClicked. Elle ajoute un arbre à la liste et déclenche le calcul de l’année.
NB : le mot clé async permet l’exécution en mode asynchrone. Concrètement, après l’ajout de l’arbre à la liste et grâce au mot clé await, la méthode rend la main permettant le calcul de l’année. Ce traitement long (envoi de requête Http et attente de réponse du serveur) va se faire en arrière plan. Ceci est très important car il permet de ne pas freezer l’interface graphique. Il permet aussi d’empiler les requêtes sans attendre le résultat des précédentes.
Revenons au modèle maintenant. La classe Arbre, contient uniquement les propriétés de l’arbre:
Le ViewModel sert d’intermédiaire entre la vue et le modèle. Il présente les propriétés de ce dernier à la première.
Pour ce faire, il implémente la propriété INotifyPropertyChanged. À chaque fois qu’une propriété est modifiée, elle déclenche l’événement PropertyChanged pour notifier la vue. Voici le code partiel de la classe pour illustrer ce mécanisme:
public class ArbreViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string name) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } public string Circonference { get { return arbre.Circonference == 0 ? null : arbre.Circonference.ToString(); } set { int intVal; int.TryParse(value, out intVal); if (arbre.Circonference != intVal) { arbre.Circonference = intVal; OnPropertyChanged(nameof(Circonference)); } }
Le code de la méthode de calcule de l’année est déduit de l’exemple inclut dans la documentation du Web Service généré par AzureML. Notons qu’il faut écrire cette méthode de façon asynchrone pour les raisons expliquées précédemment:
public async Task ComputeAnnee() { . . . response = await client.PostAsync("", new StringContent(jsonReq, Encoding.UTF8, "application/json")); . . . }
NB : l’utilisation du code de communication avec le service AzureML a nécessité l’installation d’un nuget défini dans la documentation générée. L’installation de nuget n’est pas possible sur le projet partagé lui même. Il faut l’installer sur tous les projets des device cible pour qu’il soit accessible à partir du projet partagé.
Pour exécuter l’application sur Windows, il faut définir le projet UWP comme projet de démarrage puis lancer l’exécution. Voici ce que ça donne au démarrage:
Et après le lancement d’une requête :
Pour exécuter sur Android, il faut définir le projet Android comme projet par défaut. Connecter un téléphone Android au PC puis lancer l’exécution. Voici ce que ça donne au démarrage et après le lancement d’une requête:
Conclusion
Nous venons de créer -gratuitement- le contenu et l’interface d’une application IA mobile en quelques clics et quelques lignes de codes. Il est possible d’étendre l’usage à des sources de données plus évoluées comme l’utilisation de la caméra ou du microphone pour de la reconnaissance. L’exemple que nous avons présenté témoigne de la facilité et l’accessibilité grandissante des outils de l’IA pour tous, sans exiger un pré-requis fort en data science.