Azure Custom Vison en action
La plateforme Azure propose de nombreux services cognitifs prêts à l'emploi, permettant d'enrichir facilement vos applications avec des fonctionnalités innovantes.
Dans cet article, nous allons voir comment utiliser le service Custom Vision. Nous allons entrainer un modèle pour l'apprendre à reconnaitre certains types de manteaux. Nous testerons ensuite ce modèle et enfin nous verrons comment l'utiliser au sein d'une application.
Prérequis
La partie concernant le notebook peut se faire, entre autres, avec :
- Le Service Microsoft Azure Notebooks
- La machine virtuelle « Data Science » proposée depuis le portail Azure
Dans cet article, nous allons utiliser la machine virtuelle « Data Science »,
Création d'une machine virtuelle « Data Science »
- Connectez vous sur le portail Azure : https://portal.azure.com
- Cliquez sur « Create a resource », puis recherchez la machine virtuelle « Data Science »
Sélectionnez la machine « Data Science Virtual Machine for Linux (Ubuntu) » puis cliquez sur le bouton « Create »
Remplissez les informations de création de la machine virtuelle
A la fin du process cliquez sur le bouton « Create »
Maintenant que la machine virtuelle est créée, nous allons nous connecter sur son server Jupyter. La connexion se fait avec une URL de type :
https://<Your_VM_IPAddress>:8000
Dans le cas de mon exemple cette adresse sera :
L'adresse IP de la machine se trouve sur le portail Azure :
Il se peut que la fenêtre suivante s'affiche. Cliquez sur « Details » puis sur « Go on the web page »
Dans la fenêtre de connexion, entrez le nom et le mot de passe que vous avez utilisés lors de la création de la machine virtuelle :
Après quelques secondes, vous devez arriver sur la page d'accueil du serveur Jupyter.
Nous allons créer un dossier pour faciliter notre travail. Cliquez sur « New » puis sur « Folder »
Cochez la case à gauche du dossier nouvellement créé (le dossier se nomme « Untitled Folder »), puis cliquez sur le bouton « rename » un haut de la page.
Renommez le dossier puis cliquez sur le bouton « Rename »
Création du notebook
Entrez dans le dossier précédemment créé. Cliquez sur le bouton « New » puis sur « Python 3 »
Une fois le Notebook créé, cliquez sur « Untitled » et donnez-lui un nom. Cliquez sur « Rename »
Téléchargement des images
Dans la première cellule du Notebook, copiez le code ci-dessous pour récupérer les images d'entrainements et de tests.
! curl -O https://canadastore.blob.core.windows.net/franmerpictures/Pictures.zip
Puis cliquez sur « Run » dans la barre d'outils (ou utilisez la combinaison de touche « Shift Enter » ou « Ctrl Enter »). Pour le reste de l'article, après avoir copié le code dans les cellules, pensez bien à exécuter le code
Si tout se passe bien, le fichier Pictures.zip doit apparaître dans votre dossier
Nous allons maintenant décompresser le fichier. Utilisez la commande-ci-dessous :
! unzip Pictures.zip
Attention : l'astérisque présent entre les crochets, signifie que le code est en cours d'exécution. Il est de bon aloi d'attendre qu'il disparaisse avant d'exécuter le code d'une autre cellule.
Trois nouveaux dossiers ont dû apparaître :
Affichage d'une image
Nous allons afficher une image et de voir comment faire des manipulations simples avec. Nous allons utiliser la librairie « matplotlib ». La documentation détaillée de cette librairie se trouve ici : https://matplotlib.org/.
Copiez le code ci-dessous dans une nouvelle cellule :
#Afficher une image / Display a picture
# Importation de librairie matplotlib / Import the matplotlib libraries
import matplotlib.pyplot as plt
import matplotlib.image as im
img = im.imread('hardshell_jackets/10116634x1038116_zm.jpeg')
imgplot = plt.imshow(img)
Il se peut que lors de la première exécution, le message ci-dessous apparaît. Cela n'aura aucune incidence sur la suite des résultats.
Récupérer des informations de l'image
Une image est intrinsèquement un tableau de valeurs de pixels (picture element) et il est important de pouvoir récupérer certaines informations concernant une image, afin de pouvoir les utiliser avec des algorithmes de reconnaissance d'objet. Ci-dessous, un exemple de code permettant de récupérer certaines informations.
#Information sur l'image / Picture's information
print ("Picture Shape: ")
print(img.shape)
#Total number of pixels is accessed by img.size:
print ("Number of pixels: ")
print (img.size)
#Image datatype is obtained by img.dtype:
print("Picture data type:")
print(img.dtype)
Intégration avec le service cognitif « Custom Vision »
Microsoft propose de nombreux services cognitifs dont la liste complète est disponible via le lien suivant : https://azure.microsoft.com/en-us/services/cognitive-services/directory/
De plus, ces services peuvent être appelés en tant que service web afin de retourner les résultats d'une prédiction.
Dans cet exemple, nous allons utiliser le service « Custom Vision ». Ce service est disponible via le lien suivant : https://customvision.ai/.
Mais avant, il nous reste des petites préparations à faire au niveau de notre Notebook.
Installation du SDK Custom Vision
Dans un premier temps nous allons vérifier la présence de « pip » et de sa mise à jour. « pip » est un outil permettant l'installation de packages Python. Dans une nouvelle cellule du Notebook, copiez le code suivant :
#installation de pip / pip installation
import sys
! {sys.executable} -m pip freeze
! {sys.executable} -m pip --version
! {sys.executable} -m pip install --upgrade pip
Depuis votre notebook, entrez la commande suivante : (nous utilisons donc « pip » pour installer le package du service cognitif « Custom vision ») :
#Installation du SDK Custom Vision / Install the Custom Vision SDK
! {sys.executable} -m pip install azure-cognitiveservices-vision-customvision
Configuration du service cognitif « Custom Vision »
Nous allons maintenant créer un service « Custom vision » en suivant le lien suivant :
Une fois sur la page d'accueil, cliquez sur « Sign in »
Vous avez la possibilité de tester gratuitement nos services cognitifs. Vous pouvez choisir de cliquer sur « Continue with trial » ou cliquez sur « Sign up for Azure ». Pour notre exemple, nous allons choisir « Continue with trial » :
Une fois le service créé, récupérez les informations de votre service en cliquant sur l'engrenage en haut à droite de la fenêtre
Puis récupérez les valeurs de vos clefs
Revenez dans votre Notebook Jupyter pour y assigner les valeurs de vos clefs dans les 2 variables ci-dessous et exécutez le code :
# Assignez les clefs de votre service "Custom Vision" aux variables / Assign your Custom service keys to variables
training_key = 'c5926d0852854f459c85facff519c759'
prediction_key = '32446a7de71b496798d38fded67fc2da'
Création d'un projet Custom Vision
A partir du Notebook, nous allons créer un projet dans le service cognitif « Custom Vision ». Dans une nouvelle cellule, copiez le code ci-dessous et exécutez-le :
from azure.cognitiveservices.vision.customvision.training import training_api
from azure.cognitiveservices.vision.customvision.training.models import ImageUrlCreateEntry
trainer = training_api.TrainingApi(training_key)
# Create a new project
print ("Creating project...")
project = trainer.create_project("MyProject")
Si vous retournez sur l'interface web du « Custom Vison » service, vous devez y trouver un nouveau projet :
Création des labels
Avant d'ajouter des images dans le service, nous allons créer nos premiers labels afin d'identifier les images.
Ajoutez le code suivant dans une nouvelle cellule et exécutez le code :
# Création des labels les images / Add tags for pictures
print("Creating tags")
hardshell_tag = trainer.create_tag(project.id,"Hardshell")
insulated_tag = trainer.create_tag(project.id,"Insulated")
print("Tags created")
Chargement des images
Maintenant nous allons importer les images dans notre projet « Custom Vision » et ajouter les labels en même temps. Copiez et exécutez le code ci-dessous dans une nouvelle cellule :
# Téléchargez les images / Upload pictures
import os
print("Adding hardshell images...")
hardshell_folder = "jacket_images/hardshell_jackets"
for file in os.listdir(os.fsencode("jacket_images/hardshell_jackets")):
with open(hardshell_folder + "/" + os.fsdecode(file),mode="rb") as Hardshell_img_data:
trainer.create_images_from_data(project.id,Hardshell_img_data,[hardshell_tag.id])
print("Adding insulated images...")
insulated_folder = "jacket_images/insulated_jackets"
for file2 in os.listdir(os.fsencode("jacket_images/insulated_jackets")):
with open(insulated_folder + "/" + os.fsdecode(file2),mode="rb") as insulated_img_data:
trainer.create_images_from_data(project.id,insulated_img_data,[insulated_tag.id])
print("Done !")
Vérifier la présence des images dans l'interface web du service cognitif et que les images possèdent le bon label.
Entrainement du projet
Après avoir ajouté les images et défini les différents labels, nous pouvons maintenant entrainer un model permettant d'identifier nos images.
Dans une nouvelle cellule, copiez et exécutez le code ci-dessous :
#Entrainement du projet / Train the project
import time
print("Training....")
iteration = trainer.train_project(project.id)
print (iteration.status)
while (iteration.status != "Completed"):
iteration = trainer.get_iteration(project.id,iteration.id)
print("Training status: " + iteration.status)
time.sleep(1)
# Set this iteration of the project as the default.
trainer.update_iteration(project.id,iteration.id,is_default=True)
print("Done!")
Si on vérifie dans l'interface web du service cognitif, une première itération de notre model a été créée.
Test du model
Maintenant que le modèle a été entrainé, nous allons le tester avec un autre set d'images
Dans un premier temps, nous allons créer une fonction pour convertir les images et envoyer une valeur de données au point de terminaison du service cognitif.
Pour faire cette conversion, nous allons créer une fonction. Copiez le code ci-dessous dans une nouvelle cellule :
def read_image_data(img_path):
import numpy as np
from io import BytesIO
import matplotlib.pyplot as plt
# Load the numpy array
#imgArray = np.load(img_path)
imgArray = im.imread(img_path)
# Write the array data to a stream
imageStream = BytesIO()
plt.imsave(imageStream, imgArray)
# Read the stream from the beginning
imageStream.seek(0)
return imageStream.read()
print ('read_image_data function created!')
Nous allons utiliser le modèle que nous avons entrainer pour réaliser des prédictions sur des images de tests. Nous allons aussi utiliser la fonction créée précédemment pour convertir les images avant de les envoyer au modèle.
Dans une nouvelle cellule de votre Notebook, copiez le code ci-dessous :
import os
import time
import numpy as np
#Importation du point de terminaison de prédiction / Import the prediction endpoint
from azure.cognitiveservices.vision.customvision.prediction import prediction_endpoint
from azure.cognitiveservices.vision.customvision.prediction.prediction_endpoint import models
#Création d'une instance du point de terminaison de prédiction
#Create an instance of the prediction endpoint
predictor = prediction_endpoint.PredictionEndpoint(prediction_key)
#Boucle sur l'ensemble des images / Loop through the test images
folder = 'Test'
files = os.listdir(folder)
i=1
x = np.linspace(0,10)
y = np.sin(x)
for file in sorted(files):
#Les images sont traitées dans l'ordre / process files in order
#Récupération du chemin de l'image et lecture des données / Get the file path and read the image data
img_path = os.path.join(folder,file) #Test pour savoir si c'est un fichier ou un dossier
if os.path.isfile(img_path):
print("File name: " + file)
img = im.imread(img_path)
plt.imshow(img)
plt.show()
#plt.plot(x,y)
#plt.figure(i+1)
img_data = read_image_data(img_path)
#Récupération des prédictions pour les images / Get the predicted tags for the image
results = predictor.predict_image(project.id, img_data, iteration.id)
fig = plt.figure()
#Affichage des labels et des probabilités / Display the tag name and probability for each prediction
for prediction in results.predictions:
print ("\t" + prediction.tag_name + ": {0:.2f}%".format(prediction.probability * 100))
print('\n')
#Pause technique :) / Technical Delay
time.sleep(0.25)
i=i+1
Notre model nous retourne donc des prédictions sur les images afin de tenter d'identifier si les images analysées sont des manteaux ou non, et si oui, quel type de manteau. Ci-dessous des exemples avec des images de tests
Utilisation du service cognitif avec Visual Studio
Maintenant que notre modèle fonction, il est peut-être aussi intéressant d'utiliser l'API du service cognitif afin d'intégrer les prédictions dans une application. Ci-dessous, une illustration rapide d'intégration du service cognitif dans une application.
Démarrez Visual Studio 2017 et créez un projet de type « Console App ».
Une fois le projet créé, dans le menu « Tools / NuGet Package Manager / Manage NuGet Packages for solution… » de Visual studio, et ajoutez les packages du Custom Vision comme illustré ci-dessous :
Rajoutez les 2 packages suivants :
Puis dans le fichier program.cs rajoutez le code ci-dessous. Remplacez les clefs par celles de votre projet du service cognitif
using Microsoft.Cognitive.CustomVision.Prediction;
using Microsoft.Cognitive.CustomVision.Training;
using Microsoft.Cognitive.CustomVision.Training.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
namespace myTutorialCustomVision
{
class
Program
{
//private static MemoryStream testImage;
static
void Main(string[] args)
{
var projectID = "<YourProjectID>";
var trainingKey = "<YourTrainingKey>";
var predictionKey = "<YourPredictionKey>";
string imagesPath = @"..\..\..\myTutorialCustomVision\Images";
string[] imageFiles = Directory.GetFiles(imagesPath, "*.jpg");
TrainingApi trainingApi = new TrainingApi() { ApiKey = trainingKey };
var project = trainingApi.GetProjects();
Guid myGuid = project[0].Id;
var iterations = trainingApi.GetIterations(Guid.Parse(projectID));
var validIterations = iterations.Where(iter => iter.Status == "Completed");
var lastIterationTrained = validIterations.OrderBy(iter => iter.LastModified).Last();
Iteration lastIteration = trainingApi.GetIteration(myGuid, lastIterationTrained.Id);
lastIteration.IsDefault = true;
trainingApi.UpdateIteration(myGuid, lastIteration.Id, lastIteration);
foreach (var image in imageFiles)
{
FileStream fileStream = new FileStream(image, FileMode.Open, FileAccess.Read);
PredictionEndpoint endpoint = new PredictionEndpoint() { ApiKey = predictionKey };
Console.WriteLine("Making a prediction for picture: " + Path.GetFileName(image));
var result = endpoint.PredictImage(myGuid, fileStream);
foreach (var c in result.Predictions)
{
Console.WriteLine($"\t{c.Tag}: {c.Probability:P1}");
}
}
Console.ReadKey();
}
}
}
Test de l'application
Pour tester l'application et les prédictions, j'ai rajouté un dossier Images dans le « Solution Explorer » et j'ai copié 2 images dans ce dossier
Résultat
L'application va retourner, pour chacune des images, une prédiction pour chacun des labels.
Il se peut que vous obteniez l'erreur « Operation returned an invalid status code '429' » si vous réalisez le test avec une grande quantité d'images. Souvent cette erreur vient du fait que votre service est soit en version d'essai soit sous-dimensionné. Pour corriger le problème, il suffit juste de changer le « Pricing tier » dans la page web du service custom vision, dans la partie « Account »,