Déployer un modèle "boîte noire" sous la forme d'une API en 5min & 2 lignes de codes
Dans ce court article, je vais m'intéresser à ces modèles qu'on appelle "black box" et à leur déploiement concret en production.
Les modèles black box sont une catégorie de modèles de machine learning dont on a du mal à comprendre le fonctionnement, du fait de leur structure ou de leur complexité. Habituellement, on met dans cette catégorie tout ce qui ne revient pas à un modèle de la forme avec un coefficient associé à chacune des variables de .
Ils ont la réputation d'être un enfer à intégrer dans les environnements de production des entreprises, et c'est plutôt vrai si l'on envisage une intégration au sens de ré-écriture. En effet, beaucoup de boîtes ont des SI centralisés et rigides en termes de langages de programmation. Typiquement, on retrouve pas mal d'infrastructures basées sur du Java, chaque nouvelle brique à ajouter au SI doit alors être écrite en Java.
Imaginez devoir traduire un gros réseau de neurones profond ou un modèle à base d'arbres du type Gradient Boosting (comme celui-là) entraînés en R dans un autre langage ...
Pour rappel, un modèle XGBoost peut contenir des milliers d'arbres de décision et un réseau de neurones peut avoir un bon million de paramètres.

Heureusement, depuis quelques années déjà, les systèmes d'information commencent à changer d'architecture en aller de plus en plus vers la modularité. On tend vers un modèle dans lequel cohabitent toutes sortes d'applications et de programmes (appelés services) ayant adopté la même méthode de communication pour s'interroger entre eux et envoyer des données. On parle d'architecture orientée services (vous verrez pas mal le sigle SOA pour service oriented architecture).
On a alors un SI constitué de dizaines de services, qui font travaillent indépendamment les uns des autres, mais qui se comprennent et savent échanger des informations (ou des ordres).
Pour revenir à notre sujet premier, qu'est ce qui empêche de considérer un modèle black box entraîné avec R ou Python comme un service qui est ensuite interrogé par mes applications métier et retourne la réponse ?
Typiquement, j'ai développé un super modèle, mais mon IT me dit qu'il est impossible à intégrer dans le SI. Je peux alors adopter une approche "Prediction as a service", et faire de mon modèle un service indépendante, une API, interrogée ensuite par les applications métier (site web, fronts de vente, apps mobiles, etc.)
I. Qu'est ce qu'une API ?
Non, l'API n'est pas une bière à fermentation haute d'origine anglaise. API veut dire application programming interface et consiste en une manière efficace et standardisée de faire collaborer des services et programmes. Ici, nous parlons d'API RESTful.
Lorsque deux services communiquent, celui qui est en demande (celui qui interroge) est appelé client, celui qui répond est appelé serveur. Le client ne fait que recevoir le résultat du travail du serveur qui lui peut être amené à travailler (faire des calculs). Toutes les communications se font via le protocole HTTP, donc tout langage qui parle HTTP (c'est à dire absolument tout langage qui se respecte un minimum) peut interroger une API RESTful.
Voici un excellent article de ThinkR à ce sujet.
II. Commençons par faire un bon petit modèle "black box"
1. Les données
D'abord, les données. prenons le célèbre iris ! Celui-ci contient 4 mesures (longueur et largeur des pétales et des sépales) pour 3 espèces d'iris :
library(plotly)
plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length, color = ~Species , type = 'scatter', mode = 'markers')
2. La boîte noire !
On entraîne un réseau de neurones permettant de prédire l'espèce de la fleur à partir des mesures (en une ligne de code, magie de R) :
(Honte à moi, même pas de split train/test !)
library(caret)
blackbox <- train(Species~.,data = iris,
method = 'nnet',
trControl=trainControl(method="cv",number=5))
On vérifie rapidement la classe du modèle :
class(blackbox$finalModel)
Ainsi que ses performances :
print(blackbox)
97% de précision, c'est pas mal du tout ! :)
Testons la prédiction avec ce modèle, on obtient la probabilité prédite par le modèle d'appartenance à chaque espèce de l'individu. Ici, on est sur un Setosa (99% de chances) :
predict(object = final_model,iris[1,1:4])
On enregistre le modèle dans un objet Rds et on va pouvoir passer à la construction de notre API.
saveRDS(blackbox, file = "./model_neuralnet_iris.Rds")
III. Construction de l'API
1. Deux fichiers R pour une API avec Plumber

Pour monter notre API, nous allons utiliser le package plumber. Pour ce faire, il faut créer deux fichiers :
- Un premier appelé
iris_api.Rqui décrit l'API et les fonctions qu'elle expose (dans notre cas la fonction de prédiction associée au réseau de neurones) - Un second appelé
server.Rqui lit la description de l'API et démarre un serveur web simple qui fournit le service de prédiction
Contenu de server.R, assez simple et purement technique :
On crée ensuite le fichier iris_api.R contenant ceci :
# library(plumber)
# r <- plumb("./server.r")
# r$run(port=8000)