Travaux pratiques - Emploi d’AutoGluon sur des données multimodales

[Diapositives du cours]

(correspond à 1 séance de TP)

Références externes utiles :

L’objectif de cette séance de TP est d’introduire l’utilisation d’AutoGluon pour trouver automatiquement des modèles prédictifs à partir de données multimodales, où chaque observation comporte une image, des données tabulaires et un court texte, pour des problèmes de classification. Nous examinons un problème considéré dans le tutoriel d’AutoGluon.

Données PetFinder.my

Le problème à résoudre et les données proviennent de la compétition Kaggle PetFinder.my Adoption Prediction. L’objectif est de prédire la rapidité à laquelle un animal de compagnie est adopté, à partir de données multimodales décrivant ces animaux. Dans la base complète il y a plus de 150 000 animaux de compagnie (observations).

Pour chaque observation on dispose des données suivantes :

  • PetID - Unique hash ID of pet profile

  • AdoptionSpeed - Categorical speed of adoption. Lower is faster. This is the value to predict. See below section for more info.

  • Type - Type of animal (1 = Dog, 2 = Cat)

  • Name - Name of pet (Empty if not named)

  • Age - Age of pet when listed, in months

  • Breed1 - Primary breed of pet (Refer to BreedLabels dictionary)

  • Breed2 - Secondary breed of pet, if pet is of mixed breed (Refer to BreedLabels dictionary)

  • Gender - Gender of pet (1 = Male, 2 = Female, 3 = Mixed, if profile represents group of pets)

  • Color1 - Color 1 of pet (Refer to ColorLabels dictionary)

  • Color2 - Color 2 of pet (Refer to ColorLabels dictionary)

  • Color3 - Color 3 of pet (Refer to ColorLabels dictionary)

  • MaturitySize - Size at maturity (1 = Small, 2 = Medium, 3 = Large, 4 = Extra Large, 0 = Not Specified)

  • FurLength - Fur length (1 = Short, 2 = Medium, 3 = Long, 0 = Not Specified)

  • Vaccinated - Pet has been vaccinated (1 = Yes, 2 = No, 3 = Not Sure)

  • Dewormed - Pet has been dewormed (1 = Yes, 2 = No, 3 = Not Sure)

  • Sterilized - Pet has been spayed / neutered (1 = Yes, 2 = No, 3 = Not Sure)

  • Health - Health Condition (1 = Healthy, 2 = Minor Injury, 3 = Serious Injury, 0 = Not Specified)

  • Quantity - Number of pets represented in profile

  • Fee - Adoption fee (0 = Free)

  • State - State location in Malaysia (Refer to StateLabels dictionary

  • RescuerID - Unique hash ID of rescuer

  • VideoAmt - Total uploaded videos for this pet

  • PhotoAmt - Total uploaded photos for this pet

  • Description - Profile write-up for this pet. The primary language used is English, with some in Malay or Chinese

  • Images - a photo of the pet(s) in the profile.

Nous retrouvons donc des variables nominales, quelques variables quantitatives, un texte (description) et une photo.

La variable AdoptionSpeed, à prédire, peut prendre les valeurs suivantes :

  • 0 - Animal de compagnie (pet) adopté le jour où il a été listé.

  • 1 - Animal de compagnie adopté entre 1 et 7 jours après avoir été listé.

  • 2 - Animal de compagnie adopté entre 8 et 30 jours après avoir été listé.

  • 3 - Animal de compagnie adopté entre 31 et 99 jours après avoir été listé.

  • 4 - Pas adopté après 100 jours (catégorie non représentée).

Dans l’exemple que nous examinons avec AutoGluon il y a seulement 700 observations (600 pour l’apprentissage, 100 pour l’évaluation) et deux classes : adoption rapide (1, correspondant aux étiquettes 0 et 1 des données initiales) ou lente (0, correspondant aux autres étiquettes).

Nous préparons d’abord les bibliothèques de base et faisons l’initialisation du générateur pseudo-aléatoire :

import os
import numpy as np
import warnings
warnings.filterwarnings('ignore')
np.random.seed(123)

Il est ensuite nécessaire de récupérer les données, ici sur AWS et non directement sur Kaggle (car les classes ont été redéfinies) :

download_dir = './ag_automm_tutorial'
zip_file = 'https://automl-mm-bench.s3.amazonaws.com/petfinder_for_tutorial.zip'
from autogluon.core.utils.loaders import load_zip
load_zip.unzip(zip_file, unzip_dir=download_dir)

Nous pouvons charger les données tabulaires (format CSV) :

import pandas as pd
dataset_path = download_dir + '/petfinder_for_tutorial'
train_data = pd.read_csv(f'{dataset_path}/train.csv', index_col=0)
test_data = pd.read_csv(f'{dataset_path}/test.csv', index_col=0)
label_col = 'AdoptionSpeed'

et ensuite préparer les chemins d’accès aux images (qui seront également chargées lors de l’apprentissage et de l’évaluation) :

image_col = 'Images'
train_data[image_col] = train_data[image_col].apply(lambda ele: ele.split(';')[0])
test_data[image_col] = test_data[image_col].apply(lambda ele: ele.split(';')[0])


def path_expander(path, base_folder):
    path_l = path.split(';')
    return ';'.join([os.path.abspath(os.path.join(base_folder, path)) for path in path_l])

train_data[image_col] = train_data[image_col].apply(lambda ele: path_expander(ele, base_folder=dataset_path))
test_data[image_col] = test_data[image_col].apply(lambda ele: path_expander(ele, base_folder=dataset_path))

Nous pouvons examiner une des observations (un animal de compagnie),

example_row = train_data.iloc[10]
print(example_row)

voir sa description textuelle complète

print(example_row['Description'])

et l’image qui le représente :

example_image = example_row[image_col]

from IPython.display import Image, display
pil_img = Image(filename=example_image)
display(pil_img)

Apprentissage

Nous pouvons maintenant procéder à l’apprentissage d’un modèle qui cherche à prédire la rapidité d’adoption à partir des données disponibles constituées de variables quantitatives et nominales, d’une description textuelle et d’une image.

Pour un premier essai, nous utilisons une durée d’apprentissage de seulement 3 minutes. Dans des essais ultérieurs vous pourrez l’augmenter afin de voir l’impact sur les performances.

from autogluon.multimodal import MultiModalPredictor
predictor = MultiModalPredictor(label=label_col)
predictor.fit(
    train_data=train_data,
    time_limit=180, # seconds
)

Evaluation

Nous pouvons maintenant évaluer le modèle obtenu sur les données de test. La métrique employée est l’aire sous la courbe ROC (Area Under Curve ou AUC), entre 0 et 1 ; plus elle est proche de 1, meilleures sont les performances.

scores = predictor.evaluate(test_data, metrics=["roc_auc"])
print(scores)

Il est également possible de voir, pour quelques observations (par exemple celles entre 10 et 20), les probabilités prédites d’appartenance à chcune des deux classes :

probas = predictor.predict_proba(test_data.drop(columns=label_col))
probas[10:20]

Ainsi que la classe prédite pour chacune des observations considérées (celles entre 10 et 20 ici) :

predictions = predictor.predict(test_data.drop(columns=label_col))
predictions[10:20]

Chaque observation est affectée à la classe de probabilité maximale.

Questions

Question :

Pour les observation de l’échantillon considéré plus haut (predictions[10:20]) on constate que les probabilités associées aux deux classes (adoption rapide ou adoption lente) peuvent être plus proches (par ex. 0.506714 contre 0.493287) ou plus différentes (par ex. 0.034472 contre 0.965528). Pouvons-nous interpréter ces différences d’écart ?

Correction :

Si pour une observation les probabilités pour les deux classes sont proches, cela indique que le classement de cette observation dans une des classes est difficile pour le modèle ; on peut aussi considérer que la confiance dans la prédiction est faible. En revanche, si les probabilités sont différentes alors le classement est facile pour le modèle ; on peut considérer que la confiance dans la prédiction est élevée. Il faut toutefois noter que des modèles peuvent être très confiants dans des prédictions qui s’avèrent être erronées.

Question :

Augmentez la limite supérieure sur la durée d’apprentissage à 6 minutes (360 secondes). Constatez-vous une évolution significative des performances sur les données de test ?

Correction :

Pour ces données la limite initiale de 3 minutes semble suffire, une limite supérieure ne permet pas d’obtenir de meilleures performances. En effet, en regardant l’exécution on constate que l’arrêt de l’apprentissage se produit lorsque l’erreur sur des données de validation commence à augmenter, or cela arrive avant 3 minutes.

Question :

Ajoutez d’autres métriques pour évaluer les performances, comme le taux de bon classement (accuracy) et relancez l’évaluation. Voir la documentation.

Correction :

scores = predictor.evaluate(test_data, metrics=["accuracy","roc_auc"])
print(scores)

Question :

Relisez en mémoire le modèle sauvegardé par AutoGluon à la fin de l’apprentissage et testez ce modèle sur les données de test.

Correction :

model_path = "/home/jovyan/MonDossier/AutogluonModels/chemin_à_préciser_voir_plus_haut_fin_apprentissage"
predictor.save(model_path)
loaded_predictor = MultiModalPredictor.load(model_path)
scoresLoaded = loaded_predictor.evaluate(test_data, metrics=["accuracy","roc_auc"])
print(scoresLoaded)