Créer un modèle de ML financier avec l'outil de simulation What-If et Vertex AI

1. Présentation

Dans cet atelier, vous allez utiliser l'outil What-If pour analyser un modèle XGBoost entraîné sur des données financières. Après avoir analysé le modèle, vous le déploierez dans la nouvelle plate-forme Vertex AI de Cloud.

Objectifs de l'atelier

Vous allez apprendre à effectuer les opérations suivantes :

  • Entraîner un modèle XGBoost sur un ensemble de données public sur les prêts hypothécaires dans un notebook hébergé
  • Analyser le modèle à l'aide de l'outil What-If
  • Déployer le modèle XGBoost dans Vertex AI

Le coût total d'exécution de cet atelier sur Google Cloud est d'environ 1 $.

2. Présentation de Vertex AI

Cet atelier utilise la toute dernière offre de produits d'IA de Google Cloud. Vertex AI simplifie l'expérience de développement en intégrant toutes les offres de ML de Google Cloud. Auparavant, les modèles entraînés avec AutoML et les modèles personnalisés étaient accessibles depuis des services distincts. La nouvelle offre regroupe ces deux types de modèles mais aussi d'autres nouveaux produits en une seule API. Vous pouvez également migrer des projets existants vers Vertex AI. Pour envoyer un commentaire, consultez la page d'assistance.

Vertex AI comprend de nombreux produits différents qui permettent de gérer les workflows de ML de bout en bout. Cet atelier se concentre sur les produits mis en évidence ci-dessous: Prediction et Notebooks.

Présentation des produits Vertex

3. Présentation rapide de XGBoost

XGBoost est un framework de machine learning qui utilise des arbres de décision et un boosting de gradient pour créer des modèles prédictifs. Il assemble plusieurs arbres de décision en fonction du score associé aux différents nœuds feuilles d'un arbre.

Le diagramme ci-dessous est une visualisation d'un modèle d'arbre de décision simple qui évalue si un match sportif doit être joué en fonction des prévisions météorologiques:

Exemple de modèle en arbre

Pourquoi utilisons-nous XGBoost pour ce modèle ? Il a été démontré que les réseaux de neurones traditionnels fonctionnent mieux avec les données non structurées telles que les images et le texte. En revanche, les arbres de décision fonctionnent souvent très bien avec les données structurées, comme l'ensemble de données sur les prêts hypothécaires que nous utiliserons dans cet atelier de programmation.

4. Configurer votre environnement

Pour suivre cet atelier de programmation, vous aurez besoin d'un projet Google Cloud Platform dans lequel la facturation est activée. Pour créer un projet, suivez ces instructions.

Étape 1 : Activez l'API Compute Engine

Accédez à Compute Engine et cliquez sur Activer si ce n'est pas déjà fait. Vous en aurez besoin pour créer votre instance de notebook.

Étape 2: Activez l'API Vertex AI

Accédez à la section Vertex de la console Cloud, puis cliquez sur Activer l'API Vertex AI.

Tableau de bord Vertex

Étape 3: Créez une instance Notebooks

Dans la section Vertex de la console Cloud, cliquez sur "Notebooks" :

Sélectionner des notebooks

Sélectionnez ensuite Nouvelle instance. Sélectionnez ensuite le type d'instance TensorFlow Enterprise 2.3 sans GPU:

Instance TFE

Utilisez les options par défaut, puis cliquez sur Créer. Une fois l'instance créée, sélectionnez Ouvrir JupyterLab.

Étape 4: Installez XGBoost

Une fois votre instance JupyterLab ouverte, vous devez ajouter le package XGBoost.

Pour ce faire, sélectionnez "Terminal" dans le lanceur d'applications:

Exécutez ensuite la commande suivante pour installer la dernière version de XGBoost compatible avec Vertex AI:

pip3 install xgboost==1.2

Une fois l'opération terminée, ouvrez une instance de notebook Python 3 à partir du lanceur. Vous êtes prêt à commencer à utiliser votre notebook.

Étape 5: Importez des packages Python

Dans la première cellule de votre notebook, ajoutez les importations suivantes et exécutez la cellule. Vous pouvez l'exécuter en appuyant sur la flèche vers la droite dans le menu supérieur ou en appuyant sur Commande+Entrée:

import pandas as pd
import xgboost as xgb
import numpy as np
import collections
import witwidget

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.utils import shuffle
from witwidget.notebook.visualization import WitWidget, WitConfigBuilder

5. Télécharger et traiter des données

Nous allons utiliser un ensemble de données sur les prêts hypothécaires provenant de ffiec.gov pour entraîner un modèle XGBoost. Nous avons effectué un prétraitement de l'ensemble de données d'origine et créé une version plus petite que vous pouvez utiliser pour entraîner le modèle. Le modèle prédit si une demande de prêt hypothécaire particulière sera approuvée ou non.

Étape 1: Téléchargez l'ensemble de données prétraité

Nous avons mis à votre disposition une version de l'ensemble de données dans Google Cloud Storage. Vous pouvez le télécharger en exécutant la commande gsutil suivante dans votre notebook Jupyter:

!gsutil cp 'gs://mortgage_dataset_files/mortgage-small.csv' .

Étape 2: Lire l'ensemble de données avec Pandas

Avant de créer notre DataFrame Pandas, nous allons créer une dict du type de données de chaque colonne afin que Pandas lise correctement notre ensemble de données:

COLUMN_NAMES = collections.OrderedDict({
 'as_of_year': np.int16,
 'agency_code': 'category',
 'loan_type': 'category',
 'property_type': 'category',
 'loan_purpose': 'category',
 'occupancy': np.int8,
 'loan_amt_thousands': np.float64,
 'preapproval': 'category',
 'county_code': np.float64,
 'applicant_income_thousands': np.float64,
 'purchaser_type': 'category',
 'hoepa_status': 'category',
 'lien_status': 'category',
 'population': np.float64,
 'ffiec_median_fam_income': np.float64,
 'tract_to_msa_income_pct': np.float64,
 'num_owner_occupied_units': np.float64,
 'num_1_to_4_family_units': np.float64,
 'approved': np.int8
})

Nous allons ensuite créer un DataFrame en lui transmettant les types de données que nous avons spécifiés ci-dessus. Il est important de mélanger nos données au cas où l'ensemble de données d'origine serait ordonné d'une manière spécifique. Pour ce faire, nous utilisons un utilitaire sklearn appelé shuffle, que nous avons importé dans la première cellule:

data = pd.read_csv(
 'mortgage-small.csv',
 index_col=False,
 dtype=COLUMN_NAMES
)
data = data.dropna()
data = shuffle(data, random_state=2)
data.head()

data.head() permet de prévisualiser les cinq premières lignes de l'ensemble de données dans Pandas. Après avoir exécuté la cellule ci-dessus, vous devriez obtenir un résultat semblable à celui-ci:

Aperçu de l'ensemble de données sur les prêts hypothécaires

Voici les fonctionnalités que nous utiliserons pour entraîner notre modèle. Si vous faites défiler l'écran jusqu'à la fin, vous verrez la dernière colonne approved, qui est la prédiction. La valeur 1 indique qu'une application spécifique a été approuvée, et 0 qu'elle a été refusée.

Pour afficher la distribution des valeurs approuvées / refusées dans l'ensemble de données et créer un tableau numpy des libellés, exécutez la commande suivante:

# Class labels - 0: denied, 1: approved
print(data['approved'].value_counts())

labels = data['approved'].values
data = data.drop(columns=['approved'])

Environ 66% de l'ensemble de données contient des applications approuvées.

Étape 3: Créer une colonne factice pour les valeurs catégorielles

Cet ensemble de données contient un mélange de valeurs catégorielles et numériques, mais XGBoost nécessite que toutes les caractéristiques soient numériques. Au lieu de représenter les valeurs catégorielles à l'aide de l'encodage one-hot, nous allons utiliser la fonction get_dummies de Pandas pour notre modèle XGBoost.

get_dummies prend une colonne avec plusieurs valeurs possibles et la convertit en une série de colonnes contenant uniquement des valeurs 0 et 1. Par exemple, si une colonne "couleur" avait les valeurs possibles "bleu" et "rouge", get_dummies la transformerait en deux colonnes appelées "couleur_bleu" et "couleur_rouge", avec toutes les valeurs booléennes 0 et 1.

Pour créer des colonnes fictives pour nos caractéristiques catégorielles, exécutez le code suivant:

dummy_columns = list(data.dtypes[data.dtypes == 'category'].index)
data = pd.get_dummies(data, columns=dummy_columns)

data.head()

Cette fois, lorsque vous prévisualiserez les données, vous verrez des éléments individuels (comme purchaser_type sur l'image ci-dessous) répartis sur plusieurs colonnes:

Colonnes fictives Pandas

Étape 4: Répartir les données en ensembles d'entraînement et de test

La répartition entraînement / test est un concept important en machine learning. Nous allons utiliser la majorité de nos données pour entraîner notre modèle, et nous allons mettre de côté le reste pour tester notre modèle sur des données qu'il n'a jamais vues auparavant.

Ajoutez le code suivant à votre notebook, qui utilise la fonction Scikit-learn train_test_split pour diviser nos données:

x,y = data.values,labels
x_train,x_test,y_train,y_test = train_test_split(x,y)

Vous êtes maintenant prêt à créer et à entraîner votre modèle.

6. Créer, entraîner et évaluer un modèle XGBoost

Étape 1: Définissez et entraînez le modèle XGBoost

Créer un modèle dans XGBoost est simple. Nous utiliserons la classe XGBClassifier pour créer le modèle. Il nous suffit de transmettre le bon paramètre objective pour notre tâche de classification spécifique. Dans ce cas, nous utilisons reg:logistic, car nous avons un problème de classification binaire et nous voulons que le modèle renvoie une seule valeur comprise dans la plage (0,1): 0 pour "non approuvé" et 1 pour "approuvé".

Le code suivant crée un modèle XGBoost:

model = xgb.XGBClassifier(
    objective='reg:logistic'
)

Vous pouvez entraîner le modèle avec une seule ligne de code, en appelant la méthode fit() et en lui transmettant les données d'entraînement et les étiquettes.

model.fit(x_train, y_train)

Étape 2: Évaluer la justesse de votre modèle

Nous pouvons maintenant utiliser notre modèle entraîné pour générer des prédictions sur nos données de test à l'aide de la fonction predict().

Nous utiliserons ensuite la fonction accuracy_score() de Scikit-learn pour calculer la justesse de notre modèle en fonction de ses performances sur nos données de test. Nous lui transmettrons les valeurs de vérité terrain ainsi que les valeurs prédites par le modèle pour chaque exemple de notre ensemble de test:

y_pred = model.predict(x_test)
acc = accuracy_score(y_test, y_pred.round())
print(acc, '\n')

Vous devriez constater une justesse d'environ 87%, mais celle-ci varie légèrement, car le machine learning présente toujours une part de hasard.

Étape 3: Enregistrez votre modèle

Pour déployer le modèle, enregistrez-le dans un fichier local en exécutant le code suivant:

model.save_model('model.bst')

7. Interpréter votre modèle à l'aide de l'outil What-If

Étape 1: Créez la visualisation de l'outil d'analyse des scénarios

Pour connecter l'outil What-if à votre modèle local, vous devez lui transmettre un sous-ensemble de vos exemples de test, ainsi que les valeurs de vérité terrain pour ces exemples. Créons un tableau Numpy de 500 exemples de test avec leurs étiquettes de vérité terrain:

num_wit_examples = 500
test_examples = np.hstack((x_test[:num_wit_examples],y_test[:num_wit_examples].reshape(-1,1)))

Pour instancier l'outil de simulation What-If, il suffit de créer un objet WitConfigBuilder et de lui transmettre le modèle à analyser.

Comme l'outil What-If attend une liste de scores pour chaque classe de notre modèle (dans ce cas, deux), nous allons utiliser la méthode predict_proba de XGBoost avec l'outil What-If:

config_builder = (WitConfigBuilder(test_examples.tolist(), data.columns.tolist() + ['mortgage_status'])
  .set_custom_predict_fn(model.predict_proba)
  .set_target_feature('mortgage_status')
  .set_label_vocab(['denied', 'approved']))
WitWidget(config_builder, height=800)

Notez que le chargement de la visualisation prendra une minute. Lorsque la page se charge, le résultat suivant doit s'afficher:

Vue initiale de l'outil What-If

L'axe Y indique la prédiction du modèle, 1 étant une prédiction approved à forte confiance et 0 une prédiction denied à forte confiance. L'axe X correspond simplement à la répartition de tous les points de données chargés.

Étape 2: Explorez les points de données individuels

La vue par défaut de l'outil What-If est l'onglet Éditeur de points de données. Vous pouvez cliquer sur un point de données individuel pour afficher ses caractéristiques, modifier ses valeurs et voir l'impact de ce changement sur la prédiction du modèle pour ce point de données.

Dans l'exemple ci-dessous, nous avons choisi un point de données proche du seuil de 0,5. La demande de prêt hypothécaire associée à ce point de données particulier provient de la CFPB. Nous avons remplacé cette caractéristique par 0 et remplacé la valeur de agency_code_Department of Housing and Urban Development (HUD) par 1 pour voir ce qu'il adviendrait de la prédiction du modèle si ce prêt provenait plutôt du HUD:

Comme vous pouvez le voir dans la section en bas à gauche de l'outil de simulation What-If, la modification de cette caractéristique a considérablement réduit la prédiction approved du modèle de 32%. Cela peut indiquer que l'agence d'où provient un prêt a un impact important sur les résultats du modèle, mais nous devrons procéder à davantage d'analyses pour en être sûr.

En bas à gauche de l'interface utilisateur, vous pouvez également voir la valeur de vérité terrain pour chaque point de données et la comparer à la prédiction du modèle:

Étape 3: Analyse contrefactuelle

Ensuite, cliquez sur n'importe quel point de données et déplacez le curseur Afficher le point de données contrefactuel le plus proche vers la droite:

Cette option affiche le point de données qui présente les valeurs des caractéristiques les plus similaires à celles de l'original que vous avez sélectionné, mais avec une prédiction opposée. Vous pouvez ensuite faire défiler les valeurs des éléments géographiques pour voir où les deux points de données diffèrent (les différences sont mises en surbrillance en vert et en gras).

Étape 4: Examiner les graphiques de dépendance partielle

Pour voir comment chaque caractéristique affecte globalement les prédictions du modèle, cochez la case Graphiques de dépendance partielle et assurez-vous que Graphiques de dépendance partielle globaux est sélectionné:

Nous pouvons voir ici que les prêts provenant du département du Logement et du Développement urbain ont une probabilité légèrement plus élevée d'être refusés. Le graphique est de cette forme, car le code de l'agence est une fonctionnalité booléenne. Les valeurs ne peuvent donc être que 0 ou 1.

applicant_income_thousands est une caractéristique numérique. Dans le graphique de dépendance partielle, nous pouvons voir qu'un revenu plus élevé augmente légèrement la probabilité d'approbation d'une demande, mais seulement jusqu'à environ 200 000 $. Au-delà de 200 000 $, cette caractéristique n'a aucune incidence sur la prédiction du modèle.

Étape 5: Examinez les performances globales et l'équité

Accédez ensuite à l'onglet Performances et équité. Il affiche les statistiques de performances globales sur les résultats du modèle pour l'ensemble de données fourni, y compris les matrices de confusion, les courbes PR et les courbes ROC.

Sélectionnez mortgage_status comme élément de vérité terrain pour afficher une matrice de confusion:

Cette matrice de confusion indique les prédictions correctes et incorrectes de notre modèle en pourcentage du total. Si vous additionnez les carrés Oui réel / Oui prédit et Non réel / Non prédit, vous devriez obtenir la même justesse que votre modèle (dans ce cas, environ 87 %). Toutefois, votre modèle peut varier légèrement, car l'entraînement des modèles de ML comporte un élément de hasard.

Vous pouvez également tester le curseur de seuil, en augmentant et en diminuant le score de classification positive que le modèle doit renvoyer avant de décider de prédire approved pour le prêt, et voir comment cela modifie la précision, les faux positifs et les faux négatifs. Dans ce cas, la précision est maximale autour d'un seuil de 0,55.

Ensuite, dans le menu déroulant Catégoriser par situé à gauche, sélectionnez loan_purpose_Home_purchase:

Vous pouvez maintenant voir les performances des deux sous-ensembles de vos données: le segment "0" indique les prêts qui ne sont pas destinés à l'achat d'une maison, et le segment "1" les prêts destinés à l'achat d'une maison. Vérifiez la précision, le taux de faux positifs et le taux de faux négatifs entre les deux segments pour identifier les différences de performances.

Si vous développez les lignes pour examiner les matrices de confusion, vous pouvez constater que le modèle prédit "approuvé" pour environ 70% de demandes de prêt pour les achats immobiliers et seulement 46% des prêts qui ne concernent pas les achats immobiliers (les pourcentages exacts varient selon votre modèle):

Si vous sélectionnez Parité démographique dans les boutons d'option de gauche, les deux seuils seront ajustés afin que le modèle prédise approved pour un pourcentage similaire de candidats dans les deux segments. Quel impact cela a-t-il sur la précision, les faux positifs et les faux négatifs de chaque tranche ?

Étape 6: Explorer la distribution des fonctionnalités

Enfin, accédez à l'onglet Fonctionnalités de l'outil What-If. La distribution des valeurs pour chaque élément de votre ensemble de données s'affiche:

Cet onglet vous permet de vérifier que votre ensemble de données est équilibré. Par exemple, il semble que très peu de prêts de l'ensemble de données proviennent de la Farm Service Agency. Pour améliorer la précision du modèle, nous pourrions envisager d'ajouter d'autres prêts de cette agence si les données sont disponibles.

Nous n'avons décrit ici que quelques idées d'exploration de l'outil What-If. N'hésitez pas à continuer à jouer avec l'outil. Il y a encore beaucoup de choses à explorer !

8. Déployer le modèle dans Vertex AI

Notre modèle fonctionne localement, mais il serait bien que nous puissions effectuer des prédictions à partir de n'importe quel endroit (et pas seulement dans ce notebook). À cette étape, nous allons le déployer dans le cloud.

Étape 1: Créez un bucket Cloud Storage pour notre modèle

Commençons par définir quelques variables d'environnement que nous utiliserons tout au long de l'atelier de programmation. Remplacez les valeurs ci-dessous par le nom de votre projet Google Cloud, le nom du bucket Cloud Storage que vous souhaitez créer (il doit être unique) et le nom de la version de la première version de votre modèle:

# Update the variables below to your own Google Cloud project ID and GCS bucket name. You can leave the model name we've specified below:
GCP_PROJECT = 'your-gcp-project'
MODEL_BUCKET = 'gs://storage_bucket_name'
MODEL_NAME = 'xgb_mortgage'

Nous sommes maintenant prêts à créer un bucket de stockage pour stocker notre fichier de modèle XGBoost. Nous allons diriger Vertex AI vers ce fichier lors du déploiement.

Exécutez cette commande gsutil dans votre notebook pour créer un bucket de stockage régional:

!gsutil mb -l us-central1 $MODEL_BUCKET

Étape 2: Copiez le fichier de modèle dans Cloud Storage

Nous allons maintenant copier notre fichier de modèle enregistré XGBoost dans Cloud Storage. Exécutez la commande gsutil suivante:

!gsutil cp ./model.bst $MODEL_BUCKET

Accédez au navigateur de stockage dans la console Cloud pour vérifier que le fichier a bien été copié:

Étape 3: Créer le modèle et le déployer sur un point de terminaison

Nous sommes presque prêts à déployer le modèle dans le cloud. Dans Vertex AI, un modèle peut contenir plusieurs points de terminaison. Nous allons d'abord créer un modèle, puis un point de terminaison dans ce modèle et le déployer.

Commencez par créer votre modèle à l'aide de la CLI gcloud:

!gcloud beta ai models upload \
--display-name=$MODEL_NAME \
--artifact-uri=$MODEL_BUCKET \
--container-image-uri=us-docker.pkg.dev/cloud-aiplatform/prediction/xgboost-cpu.1-2:latest \
--region=us-central1

Le paramètre artifact-uri indique l'emplacement de stockage dans lequel vous avez enregistré votre modèle XGBoost. Le paramètre container-image-uri indique à Vertex AI quel conteneur prédéfini utiliser pour la diffusion. Une fois cette commande terminée, accédez à la section "Modèles" de la console Vertex pour obtenir l'ID de votre nouveau modèle. Vous pouvez la consulter ici:

Obtenir l'ID du modèle dans la console

Copiez cet ID et enregistrez-le dans une variable:

MODEL_ID = "your_model_id"

Il est maintenant temps de créer un point de terminaison dans ce modèle. Pour ce faire, exécutez la commande gcloud suivante:

!gcloud beta ai endpoints create \
--display-name=xgb_mortgage_v1 \
--region=us-central1

Une fois l'opération terminée, l'emplacement de votre point de terminaison devrait s'afficher dans la sortie de notre notebook. Recherchez la ligne indiquant que le point de terminaison a été créé avec un chemin semblable à celui-ci: projects/project_ID/locations/us-central1/endpoints/endpoint_ID.. Remplacez ensuite les valeurs ci-dessous par les ID de votre point de terminaison créé ci-dessus:

ENDPOINT_ID = "your_endpoint_id"

Pour déployer votre point de terminaison, exécutez la commande gcloud ci-dessous:

!gcloud beta ai endpoints deploy-model $ENDPOINT_ID \
--region=us-central1 \
--model=$MODEL_ID \
--display-name=xgb_mortgage_v1 \
--machine-type=n1-standard-2 \
--traffic-split=0=100

Le déploiement du point de terminaison prendra environ 5 à 10 minutes. Pendant le déploiement de votre point de terminaison, accédez à la section des modèles de votre console. Cliquez sur votre modèle. Votre point de terminaison devrait se déployer:

Une fois le déploiement terminé, une coche verte s'affiche à la place de l'icône de chargement.

Étape 4: Tester le modèle déployé

Pour vous assurer que votre modèle déployé fonctionne, testez-le à l'aide de gcloud pour effectuer une prédiction. Commencez par enregistrer un fichier JSON avec un exemple issu de notre ensemble de test:

%%writefile predictions.json
{
  "instances": [
    [2016.0, 1.0, 346.0, 27.0, 211.0, 4530.0, 86700.0, 132.13, 1289.0, 1408.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0]
  ]
}

Testez votre modèle en exécutant la commande gcloud suivante:

!gcloud beta ai endpoints predict $ENDPOINT_ID \
--json-request=predictions.json \
--region=us-central1

La prédiction de votre modèle doit s'afficher dans le résultat. Cet exemple particulier a été approuvé, vous devriez donc voir une valeur proche de 1.

9. Nettoyage

Si vous souhaitez continuer à utiliser ce notebook, nous vous recommandons de le désactiver quand vous ne vous en servez pas. À partir de l'interface utilisateur de Notebooks dans Cloud Console, sélectionnez le notebook, puis cliquez sur Arrêter:

Si vous souhaitez supprimer toutes les ressources que vous avez créées dans cet atelier, il vous suffit de supprimer l'instance de notebook au lieu de l'arrêter.

Pour supprimer le point de terminaison que vous avez déployé, accédez à la section "Points de terminaison" de votre console Vertex, puis cliquez sur l'icône de suppression:

Pour supprimer le bucket de stockage, utilisez le menu de navigation de la console Cloud pour accéder à Stockage, sélectionnez votre bucket puis cliquez sur "Supprimer" :