Persister et réutiliser les modèles
Introduction
Nous connaissons les différents types d’apprentissage ainsi que les types de modèles à disposition. Même si nous n’avons pas poussé très loin la phase d’optimisation, nous sommes capables de créer des modèles, de les entraîner sur des ensembles dédiés et de les utiliser sur de nouvelles données. Une fois que notre modèle est entraîné, il ne sera pas nécessaire de réitérer cette longue tâche d’éducation à chaque utilisation. C’est pourquoi nous aurons intérêt à le sauvegarder dans son état courant prêt à effectuer des prédictions. Cela nous permettra d’économiser du temps de chargement ainsi que des ressources de calcul. À chaque utilisation, nous n’aurons qu’à charger le modèle prêt à l’usage et à l’exploiter pour nos besoins courants.
La maîtrise de cette mécanique de persistance et de réutilisation des modèles nécessitera que nous passions par les étapes suivantes :
-
découverte des objets persistants et des objets sérialiseurs de Rubix ML ;
-
découverte des encodages des persisteurs dans Rubix ML ;
-
mise en pratique de la sauvegarde d’un modèle ;
-
mise en pratique du chargement d’un...
Les objets persistants et les sérialiseurs de Rubix ML
Dans Rubix ML, un modèle persistant (persistable en anglais) est un modèle qui peut être sauvegardé sur un support de stockage (comme un fichier ou une base de données) et rechargé ultérieurement pour une utilisation continue sans avoir besoin de ré-entraîner le modèle. Cela est particulièrement utile pour déployer des modèles en production, partager des modèles entraînés ou simplement conserver l’état d’un modèle pour une utilisation future. La persistance permet de sauvegarder non seulement la structure du modèle, mais aussi les paramètres appris pendant l’entraînement, ce qui inclut les poids, les biais et toute autre information nécessaire pour que le modèle fonctionne comme s’il venait d’être entraîné.
Dans la pratique, pour qu’un objet de modèle Rubix ML soit persistant, il doit implémenter l’interface Rubix\ML\Persistable. Concrètement, cela consiste à implémenter la méthode de prototype suivant :
public function revision() : string
Vous remarquerez que Rubix ML utilise le trait PHP nommé AutotrackRevisions pour cela. Une grande majorité des modèles que nous avons parcourus fait partie de cette catégorie, sauf les modèles...
Découverte des encodages et des persisteurs dans Rubix ML
Pour pouvoir stocker de la même manière tous les types de modèles persistants, chaque sérialiseur effectue ses travaux de sérialisation et de désérialisation en créant et en utilisant des objets de type Rubix\ML\Encoding.
Concrètement, ces objets sont comparables à des boîtes de stockage, ils contiennent un espace de stockage (via leur attribut $data) pour stocker toutes les caractéristiques sérialisées du modèle à sauvegarder. Ces boîtes de stockage ont une méthode saveTo($persister) qui leur permet d’être rangées dans des lieux de stockage à l’aide de sortes d’agents de manutention, nommés des persisteurs en Rubix ML.
Les persisteurs sont des objets qui respectent l’interface Rubix\ML\Persisters\Persister qui sont assimilables à des « magasiniers » ayant pour vocation de stocker et de récupérer des encodages dans des lieux de stockage (serveur FTP, disque dur local, bucket S3). Ils implémentent deux fonctions principales : save($encoding) et load():Encoding.
Pour le moment, Rubix ML ne fournit qu’un seul persisteur ; il s’agit de Rubix\ML\Persisters\Filesystem. Sa vocation est le stockage et la récupération des encodages dans le système de fichiers...
Mise en pratique de la sauvegarde d’un modèle
Pour illustrer toutes les connaissances que nous venons d’acquérir sur les notions de persistant, sérialiseur, encodage et persisteur, rien de mieux qu’un exemple pratique.
Créons un ensemble de données simple pour effectuer une tâche de classification. Par exemple, créons un ensemble de 5000 échantillons de points dans le plan tirés au sort. Nous décidons (purement arbitrairement) de labelliser avec la classe 0 les points dont l’abscisse est entre -2 et 2, et l’ordonnée également entre -2 et 2. Les autres points seront labellisés avec la classe 1.
Voici le code permettant une telle génération d’échantillons en PHP (le code est disponible dans le fichier /chap7/save/save.php du dépôt GitHub de ce livre :
$samples = [];
//Create a new dataset with data generated with the elements in
the square limited by y between -2 and 2 and x between -2 and 2
with class 0
for ($i = 0; $i < 5000; $i++) {
$x = rand(-700, 700) / 100;
$y = rand(-700, 700) / 100;
if ($x > -2 && $x < 2 && $y > -2 && $y < 2) {
$samples[] = [$x, $y, 0];
}else{
$samples[] = [$x...
Mise en pratique du chargement d’un modèle
Pour illustrer cette mise en pratique, mettons-nous dans la situation où un collègue nous informe qu’il dispose d’un modèle de classification performant répondant à notre problématique. Au lieu d’aller chercher de la data et de créer et ré-entraîner un modèle de zéro, nous préférons utiliser le modèle qu’il nous a gentiment fourni.
Voici un extrait de code qui nous permettrait de charger ce modèle pour l’exploiter ensuite :
$fileSystem = new Filesystem("../save/randomForest.rbx");
$encoding = $fileSystem->load();
$serializer = new RBX();
$estimator = $serializer->deserialize($encoding);
Revenons ensemble sur les différentes commandes composant cet extrait. En premier lieu, nous créons une instance du persisteur Filesystem avec le chemin du fichier du modèle qui nous a été fourni, à savoir ../save/randomForest.rbx. Pour récupérer un encodage de ce modèle, nous utilisons la méthode load() du persisteur précédent. Afin de pouvoir exploiter ce modèle empaqueté dans l’encodage, nous allons utiliser le sérialiseur RBX qui nous permettra de le déserialiser dans l’objet $estimator en utilisant la méthode deserialize().
Pour utiliser...
Solutions de déploiement des modèles en production
Une fois que notre modèle correspond à notre besoin et que nous souhaitons l’utiliser sur des environnements de production, deux situations peuvent se présenter :
-
Le modèle est colocalisé sur le même serveur que l’application qui l’utilise.
-
Le modèle est délocalisé sur un serveur différent de l’application qui l’utilise.
Voyons les solutions disponibles en fonction des deux cas.
Le modèle est colocalisé sur le même serveur que l’application qui l’utilise
Dans ce premier cas, celui de la colocalisation, se pose une deuxième question : l’application qui utilise le modèle est-elle développée en PHP ou non ?
-
Si oui, l’application utilisatrice est codée en PHP, alors nous n’aurons qu’à charger le modèle avec Rubix ML depuis l’endroit où il est stocké, comme nous l’avons appris précédemment.
-
Si non, nous allons devoir créer un service web de type API qui servira le modèle aux applications utilisatrices, quel que soit leur langage de développement, tout comme dans le cas où le modèle est délocalisé du serveur.
Le modèle est délocalisé sur un serveur différent de celui de l’application qui l’utilise
Dans ce cas, nous allons mettre en place un service web de type API qui pourra être appelé par n’importe quelle application externe codée en PHP ou non. Pour cela, soit nous pouvons créer une API directement de A à Z, soit nous pouvons utiliser un package PHP qui permet de créer un serveur à partir d’une librairie et qui sert simplement un modèle existant. La librairie Server créée par Andrew...