Apprenez à combiner l'apprentissage automatique et l'ingénierie logicielle pour concevoir, développer, déployer et itérer sur des applications ML de production.
Dans ce cours, nous passerons de l'expérimentation (conception + développement) à la production (déploiement + itération). Nous le ferons de manière itérative en motivant les composants qui nous permettront de construire un système de production fiable .
Assurez-vous de regarder la vidéo ci-dessous pour un aperçu rapide de ce que nous allons construire.
L'apprentissage automatique n'est pas une industrie distincte, mais plutôt une manière puissante de réfléchir aux données qui n'est pas réservée à un type particulier de personne.
Assurez-vous de suivre le cours pour une présentation beaucoup plus détaillée du contenu de ce référentiel. Nous aurons des instructions pour les ordinateurs portables locaux et les clusters Anyscale pour les sections ci-dessous, alors assurez-vous d'activer la liste déroulante ► en fonction de ce que vous utilisez (les instructions Anyscale seront activées par défaut). Si vous souhaitez suivre ce cours avec Anyscale, où nous fournirons la structure , le calcul (GPU) et la communauté pour tout apprendre en une journée, rejoignez notre prochaine cohorte en direct → inscrivez-vous ici !
Nous allons commencer par configurer notre cluster avec les configurations d'environnement et de calcul.
Nous pouvons créer un espace de travail Anyscale à l'aide de l'interface utilisateur de la page Web.
- Workspace name: ` madewithml `
- Project: ` madewithml `
- Cluster environment name: ` madewithml-cluster-env `
# Toggle ` Select from saved configurations `
- Compute config: ` madewithml-cluster-compute-g5.4xlarge `
Alternativement, nous pouvons utiliser la CLI pour créer l'espace de travail via
anyscale workspace create ...
Si vous ne souhaitez pas suivre ce cours localement ou via Anyscale, vous disposez des options suivantes :
Créez un référentiel en suivant ces instructions : Créez un nouveau référentiel → nommez-le Made-With-ML
→ Basculez Add a README file
( très important car cela crée une branche main
) → Cliquez sur Create repository
(faites défiler vers le bas)
Nous sommes maintenant prêts à cloner le référentiel contenant tout notre code :
git clone https://github.com/GokuMohandas/Made-With-ML.git .
touch .env
# Inside .env
GITHUB_USERNAME= " CHANGE_THIS_TO_YOUR_USERNAME " # ← CHANGE THIS
source .env
export PYTHONPATH= $PYTHONPATH : $PWD
python3 -m venv venv # recommend using Python 3.10
source venv/bin/activate # on Windows: venvScriptsactivate
python3 -m pip install --upgrade pip setuptools wheel
python3 -m pip install -r requirements.txt
pre-commit install
pre-commit autoupdate
Je recommande fortement d'utiliser Python
3.10
et d'utiliser pyenv (mac) ou pyenv-win (windows).
Notre environnement avec la version Python et les bibliothèques appropriées est déjà configuré pour nous via l'environnement de cluster que nous avons utilisé lors de la configuration de notre espace de travail Anyscale. Il nous suffit donc d'exécuter ces commandes :
export PYTHONPATH= $PYTHONPATH : $PWD
pre-commit install
pre-commit autoupdate
Commencez par explorer le notebook Jupyter pour parcourir de manière interactive les principales charges de travail d'apprentissage automatique.
# Start notebook
jupyter lab notebooks/madewithml.ipynb
Cliquez sur l'icône Jupyter dans le coin supérieur droit de notre page Anyscale Workspace et cela ouvrira notre instance JupyterLab dans un nouvel onglet. Accédez ensuite au répertoire notebooks
et ouvrez le notebook madewithml.ipynb
.
Nous allons maintenant exécuter les mêmes charges de travail en utilisant les scripts Python propres en suivant les meilleures pratiques d'ingénierie logicielle (tests, documentation, journalisation, service, gestion des versions, etc.). Le code que nous avons implémenté dans notre notebook sera refactorisé dans les scripts suivants :
madewithml
├── config.py
├── data.py
├── evaluate.py
├── models.py
├── predict.py
├── serve.py
├── train.py
├── tune.py
└── utils.py
Remarque : modifiez les valeurs des arguments d'entrée --num-workers
, --cpu-per-worker
et --gpu-per-worker
ci-dessous en fonction des ressources de votre système. Par exemple, si vous utilisez un ordinateur portable local, une configuration raisonnable serait --num-workers 6 --cpu-per-worker 1 --gpu-per-worker 0
.
export EXPERIMENT_NAME= " llm "
export DATASET_LOC= " https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/dataset.csv "
export TRAIN_LOOP_CONFIG= ' {"dropout_p": 0.5, "lr": 1e-4, "lr_factor": 0.8, "lr_patience": 3} '
python madewithml/train.py
--experiment-name " $EXPERIMENT_NAME "
--dataset-loc " $DATASET_LOC "
--train-loop-config " $TRAIN_LOOP_CONFIG "
--num-workers 1
--cpu-per-worker 3
--gpu-per-worker 1
--num-epochs 10
--batch-size 256
--results-fp results/training_results.json
export EXPERIMENT_NAME= " llm "
export DATASET_LOC= " https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/dataset.csv "
export TRAIN_LOOP_CONFIG= ' {"dropout_p": 0.5, "lr": 1e-4, "lr_factor": 0.8, "lr_patience": 3} '
export INITIAL_PARAMS= " [{ " train_loop_config " : $TRAIN_LOOP_CONFIG }] "
python madewithml/tune.py
--experiment-name " $EXPERIMENT_NAME "
--dataset-loc " $DATASET_LOC "
--initial-params " $INITIAL_PARAMS "
--num-runs 2
--num-workers 1
--cpu-per-worker 3
--gpu-per-worker 1
--num-epochs 10
--batch-size 256
--results-fp results/tuning_results.json
Nous utiliserons MLflow pour suivre nos expériences et stocker nos modèles ainsi que l'interface utilisateur de suivi MLflow pour afficher nos expériences. Nous avons sauvegardé nos expériences dans un répertoire local, mais notons que dans un environnement de production réel, nous aurions un emplacement central pour stocker toutes nos expériences. Il est facile/peu coûteux de créer votre propre serveur MLflow pour que tous les membres de votre équipe puissent suivre leurs expériences ou utiliser une solution gérée comme Weights & Biases, Comet, etc.
export MODEL_REGISTRY= $( python -c " from madewithml import config; print(config.MODEL_REGISTRY) " )
mlflow server -h 0.0.0.0 -p 8080 --backend-store-uri $MODEL_REGISTRY
Si vous exécutez ce bloc-notes sur votre ordinateur portable local, rendez-vous sur http://localhost:8080/ pour afficher votre tableau de bord MLflow.
Si vous utilisez Anyscale Workspaces, nous devons d'abord exposer le port du serveur MLflow. Exécutez la commande suivante sur votre terminal Anyscale Workspace pour générer l'URL publique vers votre serveur MLflow.
APP_PORT=8080
echo https:// $APP_PORT -port- $ANYSCALE_SESSION_DOMAIN
export EXPERIMENT_NAME= " llm "
export RUN_ID= $( python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC )
export HOLDOUT_LOC= " https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/holdout.csv "
python madewithml/evaluate.py
--run-id $RUN_ID
--dataset-loc $HOLDOUT_LOC
--results-fp results/evaluation_results.json
{
"timestamp" : " June 09, 2023 09:26:18 AM " ,
"run_id" : " 6149e3fec8d24f1492d4a4cabd5c06f6 " ,
"overall" : {
"precision" : 0.9076136428670714 ,
"recall" : 0.9057591623036649 ,
"f1" : 0.9046792827719773 ,
"num_samples" : 191.0
},
...
export EXPERIMENT_NAME= " llm "
export RUN_ID= $( python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC )
python madewithml/predict.py predict
--run-id $RUN_ID
--title " Transfer learning with transformers "
--description " Using transformers for transfer learning on text classification tasks. "
[{
"prediction" : [
" natural-language-processing "
],
"probabilities" : {
"computer-vision" : 0.0009767753 ,
"mlops" : 0.0008223939 ,
"natural-language-processing" : 0.99762577 ,
"other" : 0.000575123
}
}]
# Start
ray start --head
# Set up
export EXPERIMENT_NAME= " llm "
export RUN_ID= $( python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC )
python madewithml/serve.py --run_id $RUN_ID
Une fois l'application lancée, nous pouvons l'utiliser via cURL, Python, etc. :
# via Python
import json
import requests
title = "Transfer learning with transformers"
description = "Using transformers for transfer learning on text classification tasks."
json_data = json . dumps ({ "title" : title , "description" : description })
requests . post ( "http://127.0.0.1:8000/predict" , data = json_data ). json ()
ray stop # shutdown
Dans Anyscale Workspaces, Ray est déjà en cours d'exécution, nous n'avons donc pas besoin de démarrer/arrêter manuellement comme nous devons le faire localement.
# Set up
export EXPERIMENT_NAME= " llm "
export RUN_ID= $( python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC )
python madewithml/serve.py --run_id $RUN_ID
Une fois l'application lancée, nous pouvons l'utiliser via cURL, Python, etc. :
# via Python
import json
import requests
title = "Transfer learning with transformers"
description = "Using transformers for transfer learning on text classification tasks."
json_data = json . dumps ({ "title" : title , "description" : description })
requests . post ( "http://127.0.0.1:8000/predict" , data = json_data ). json ()
# Code
python3 -m pytest tests/code --verbose --disable-warnings
# Data
export DATASET_LOC= " https://raw.githubusercontent.com/GokuMohandas/Made-With-ML/main/datasets/dataset.csv "
pytest --dataset-loc= $DATASET_LOC tests/data --verbose --disable-warnings
# Model
export EXPERIMENT_NAME= " llm "
export RUN_ID= $( python madewithml/predict.py get-best-run-id --experiment-name $EXPERIMENT_NAME --metric val_loss --mode ASC )
pytest --run-id= $RUN_ID tests/model --verbose --disable-warnings
# Coverage
python3 -m pytest tests/code --cov madewithml --cov-report html --disable-warnings # html report
python3 -m pytest tests/code --cov madewithml --cov-report term --disable-warnings # terminal report
À partir de ce moment, afin de déployer notre application en production, nous devrons être soit sur Anyscale, soit sur une VM cloud/cluster sur site que vous gérez vous-même (avec Ray). Si ce n'est pas sur Anyscale, les commandes seront légèrement différentes mais les concepts seront les mêmes.
Si vous ne souhaitez pas configurer tout cela vous-même, nous vous recommandons vivement de rejoindre notre prochaine cohorte en direct{:target="_blank"} dans laquelle nous vous fournirons un environnement avec toute cette infrastructure déjà configurée pour vous afin que vous je me suis juste concentré sur l’apprentissage automatique.
Ces informations d'identification ci-dessous sont automatiquement définies pour nous si nous utilisons Anyscale Workspaces. Nous n'avons pas besoin de définir explicitement ces informations d'identification sur les espaces de travail, mais nous le faisons si nous l'exécutons localement ou sur un cluster en dehors de l'endroit où nos tâches et services Anyscale sont configurés pour s'exécuter.
export ANYSCALE_HOST=https://console.anyscale.com
export ANYSCALE_CLI_TOKEN= $YOUR_CLI_TOKEN # retrieved from Anyscale credentials page
L'environnement de cluster détermine où nos charges de travail seront exécutées (OS, dépendances, etc.). Nous avons déjà créé cet environnement de cluster pour nous mais c'est ainsi que nous pouvons en créer/mettre à jour un nous-mêmes.
export CLUSTER_ENV_NAME= " madewithml-cluster-env "
anyscale cluster-env build deploy/cluster_env.yaml --name $CLUSTER_ENV_NAME
La configuration de calcul détermine sur quelles ressources nos charges de travail seront exécutées. Nous avons déjà créé cette configuration de calcul pour nous, mais c'est ainsi que nous pouvons la créer nous-mêmes.
export CLUSTER_COMPUTE_NAME= " madewithml-cluster-compute-g5.4xlarge "
anyscale cluster-compute create deploy/cluster_compute.yaml --name $CLUSTER_COMPUTE_NAME
Nous sommes maintenant prêts à exécuter nos charges de travail ML. Nous avons décidé de les combiner tous en un seul travail, mais nous aurions également pu créer des tâches distinctes pour chaque charge de travail (entraîner, évaluer, etc.). Nous allons commencer par éditer les slots $GITHUB_USERNAME
dans notre fichier workloads.yaml
:
runtime_env :
working_dir : .
upload_path : s3://madewithml/$GITHUB_USERNAME/jobs # <--- CHANGE USERNAME (case-sensitive)
env_vars :
GITHUB_USERNAME : $GITHUB_USERNAME # <--- CHANGE USERNAME (case-sensitive)
Le runtime_env
spécifie ici que nous devons télécharger notre working_dir
actuel dans un compartiment S3 afin que tous nos travailleurs lorsque nous exécutons un travail Anyscale aient accès au code à utiliser. Le GITHUB_USERNAME
est utilisé ultérieurement pour enregistrer les résultats de nos charges de travail sur S3 afin que nous puissions les récupérer plus tard (par exemple pour le service).
Nous sommes maintenant prêts à soumettre notre travail pour exécuter nos charges de travail ML :
anyscale job submit deploy/jobs/workloads.yaml
Et une fois nos charges de travail ML exécutées, nous sommes prêts à lancer notre modèle en production. Semblable à nos configurations Anyscale Jobs, assurez-vous de modifier le $GITHUB_USERNAME
dans serve_model.yaml
.
ray_serve_config :
import_path : deploy.services.serve_model:entrypoint
runtime_env :
working_dir : .
upload_path : s3://madewithml/$GITHUB_USERNAME/services # <--- CHANGE USERNAME (case-sensitive)
env_vars :
GITHUB_USERNAME : $GITHUB_USERNAME # <--- CHANGE USERNAME (case-sensitive)
Nous sommes maintenant prêts à lancer notre service :
# Rollout service
anyscale service rollout -f deploy/services/serve_model.yaml
# Query
curl -X POST -H " Content-Type: application/json " -H " Authorization: Bearer $SECRET_TOKEN " -d ' {
"title": "Transfer learning with transformers",
"description": "Using transformers for transfer learning on text classification tasks."
} ' $SERVICE_ENDPOINT /predict/
# Rollback (to previous version of the Service)
anyscale service rollback -f $SERVICE_CONFIG --name $SERVICE_NAME
# Terminate
anyscale service terminate --name $SERVICE_NAME
Nous n'allons pas déployer manuellement notre application à chaque fois que nous apportons une modification. Au lieu de cela, nous allons automatiser ce processus à l'aide de GitHub Actions !
git remote set-url origin https://github.com/ $GITHUB_USERNAME /Made-With-ML.git # <-- CHANGE THIS to your username
git checkout -b dev
/settings/secrets/actions
de notre référentiel GitHub. export ANYSCALE_HOST=https://console.anyscale.com
export ANYSCALE_CLI_TOKEN= $YOUR_CLI_TOKEN # retrieved from https://console.anyscale.com/o/madewithml/credentials
main
) et les transférer vers GitHub. Mais afin de transférer notre code vers GitHub, nous devrons d'abord nous authentifier avec nos informations d'identification avant de le transférer vers notre référentiel : git config --global user.name $GITHUB_USERNAME # <-- CHANGE THIS to your username
git config --global user.email [email protected] # <-- CHANGE THIS to your email
git add .
git commit -m " " # <-- CHANGE THIS to your message
git push origin dev
Vous serez maintenant invité à saisir votre nom d'utilisateur et votre mot de passe (jeton d'accès personnel). Suivez ces étapes pour obtenir un jeton d'accès personnel : Nouveau jeton d'accès personnel GitHub → Ajouter un nom → Basculer repo
et workflow
→ Cliquez sur Generate token
(faites défiler vers le bas) → Copiez le jeton et collez-le lorsque vous êtes invité à saisir votre mot de passe.
main
, ce qui déclenchera le workflow des charges de travail. Si le workflow (Anyscale Jobs) réussit, cela produira des commentaires avec les résultats de la formation et de l'évaluation directement sur le PR.main
. Cela déclenchera le workflow de service qui déploiera notre nouveau service en production !Avec notre workflow CI/CD en place pour déployer notre application, nous pouvons désormais nous concentrer sur l'amélioration continue de notre modèle. Il devient très facile d'étendre sur cette base pour se connecter aux exécutions planifiées (cron), aux pipelines de données, aux dérives détectées via la surveillance, l'évaluation en ligne, etc. Et nous pouvons facilement ajouter un contexte supplémentaire tel que comparer n'importe quelle expérience avec ce qui est actuellement en production (directement dans le PR même), etc.
Des problèmes avec la configuration des notebooks avec jupyter ? Par défaut, jupyter utilisera le noyau avec notre environnement virtuel mais nous pouvons également l'ajouter manuellement à jupyter :
python3 -m ipykernel install --user --name=venv
Nous pouvons maintenant ouvrir un bloc-notes → Kernel (barre de menu supérieure) → Change Kernel → venv
. Pour supprimer ce noyau, nous pouvons procéder comme suit :
jupyter kernelspec list
jupyter kernelspec uninstall venv