Mettre à disposition un modèle par le biais d’une API

Les API sont un moyen très pratique pour simplifier la mise à disposition des prédictions d’un modèle de machine learning. Ce chapitre présente la manière dont FastAPI simplifie l’intégration d’un modèle de machine learning dans une application.

Modélisation
Tutoriel
Auteur·rice

Lino Galiana

Date de publication

2025-01-15

Pour essayer les exemples présents dans ce tutoriel :
View on GitHub Onyxia Onyxia Open In Colab

Ce chapitre présente la deuxième application d’une journée de cours que j’ai donné à l’Université Dauphine dans le cadre des PSL Data Week.

L’objectif de ce chapitre est d’amener à développer une API du type de celle-ci.

Dérouler les slides associées ci-dessous ou cliquer ici pour les afficher en plein écran.

Le chapitre précédent constituait une introduction à la création de pipelines de machine learning. Ce chapitre va aller plus loin en montrant la démarche pour le rendre disponible à plus grande échelle par le biais d’une API pouvant être consommée avec de nouvelles données. L’objectif de celle-ci est de ne pas contraindre les réutilisateurs d’un modèle à disposer d’un environnement technique complexe pour pouvoir utiliser le même modèle que celui entraîné précédemment.

1 Exemple de réutilisation d’un modèle sous forme d’API

Un exemple d’API obtenue à l’issue de ce chapitre est mis à disposition sur https://dvf-simple-api.lab.sspcloud.fr/. La documentation de l’API est disponible ici.

Cette API est utilisable dans plusieurs langages.

En Python, par exemple, cela donnera:

import requests

pieces_principales = 6
surface = 50
url = f"https://dvf-simple-api.lab.sspcloud.fr/predict?month=4&nombre_lots=1&code_type_local=2&nombre_pieces_principales={pieces_principales}&surface={surface}"
requests.get(url).json()
728358.5461884077

Néanmoins, l’un des intérêts de proposer une API est que les utilisateurs du modèle ne sont pas obligés d’être des pythonistes. Cela accroît grandement la cible des ré-utilisateurs potentiels.

Cette approche ouvre notamment la possibilité de faire des applications interactives qui utilisent, en arrière plan, notre modèle entraîné avec Python.

Voici un exemple, minimaliste, d’une réutilisation de notre modèle avec deux sélecteurs Javascript qui mettent à jour le prix estimé du bien.

2 Etape 1: créer une application en local

Mettre en place une API consiste à gravir une marche dans l’échelle de la reproductibilité par rapport à fournir un notebook. Ces derniers ne sont pas les outils les plus adaptés pour partager autre chose que du code, à faire tourner de son côté.

Il est donc naturel de sortir des notebooks lorsqu’on commence à aller vers ce niveau de mise à disposition. Par le biais de scripts Python lancés en ligne de commande, construits en exportant le code du chapitre précédent de nos notebooks, on pourra créer une base de départ propre.

Il est plus naturel de privilégier une interface de développement généraliste comme VSCode à Jupyter lorsqu’on franchit ce rubicon. L’exercice suivant permettra donc de créer cette première application minimale, à exécuter en ligne de commande.

Exercice 1: créer des scripts pour entraîner le modèle

Le dépôt Github qui permet de construire l’API from scratch est disponible ici. Nous allons emprunter quelques éléments, par-ci par-là, pour faire notre application en local.

  • Créer un nouveau service VSCode sur le SSPCloud en paramétrant dans l’onglet Networking le port 5000 ;
  • Utiliser la commande suivante depuis le terminal:
mkdir app
cd app

Depuis le menu des fichiers, créer quatre fichiers dont le contenu suit:

  • requirements.txt: récupérer le contenu sur cette page ;

  • getdvf.py: récupérer le contenu sur cette page ;

  • train.py: récupérer le contenu sur cette page ;

  • api.py: récupérer le contenu sur cette page.

  • Exécuter getdvf.py puis train.py pour stocker en local le modèle entraîné

  • Ajouter model.joblib au .gitignore (si vous utilisez Git)

  • Créer un script test.py qui contient la fonction suivante et la teste après avoir importé votre modèle (load('pipe.joblib') en n’oubliant pas from joblib import load):

import pandas as pd


def predict(
    month: int = 3,
    nombre_lots: int = 1,
    code_type_local: int = 2,
    nombre_pieces_principales: int = 3,
    surface: float = 75,
) -> float:
    """ """

    df = pd.DataFrame(
        {
            "month": [month],
            "Nombre_de_lots": [nombre_lots],
            "Code_type_local": [code_type_local],
            "Nombre_pieces_principales": [nombre_pieces_principales],
            "surface": [surface],
        }
    )

    prediction = model.predict(df)

    return prediction

3 Etape 2: créer une API en local

Le script précédent constitue déjà un progrès dans la reproductibilité. Il rend plus facile le réentraînement d’un modèle sur le même jeu de données. Néanmoins, il reste tributaire du fait que la personne désirant utiliser du modèle utilise Python et sache réentrainer le modèle dans les mêmes conditions que vous.

Avec FastAPI, nous allons très facilement pouvoir transformer cette application Python en une API.

Exercice 2: créer des scripts pour entraîner le modèle
  • La ligne ci-dessous du script api.py récupère un modèle pré-entraîné enregistré sur un espace de stockage
download_file(
    "https://minio.lab.sspcloud.fr/projet-formation/diffusion/python-datascientist/pipe.joblib",
    "pipe.joblib",
)

Retirer cette ligne de votre script, pour utiliser le modèle que vous venez d’entraîner.

  • Déployer en local l’API avec la commande
uvicorn api:app --reload --host "0.0.0.0" --port 5000
  • A partir du README du service VSCode, se rendre sur l’URL de déploiement, ajouter /docs/ à celui-ci et observer la documentation de l’API
  • Se servir de la documentation pour tester les requêtes /predict
  • Récupérer l’URL d’une des requêtes proposées. La tester dans le navigateur et depuis Python avec Requests (requests.get(url).json())
  • Optionnel: faire tourner le même code dans un autre environnement que le SSPCloud (par exemple une installation de Python en local) pour voir que ça fonctionne de manière identique.

4 Aller plus loin: mettre à disposition cette API de manière pérenne

L’étape précédente permettait de créer un point d’accès à votre modèle depuis n’importe quel type de client. A chaque requête de l’API, le script api.py était exécuté et renvoyait son output.

Ceci est déjà un saut de géant dans l’échelle de la reproductibilité. Néanmoins, cela reste artisanal: si votre serveur local connait un problème (par exemple, vous killez l’application), les clients ne recevront plus de réponse, sans comprendre pourquoi.

Il est donc plus fiable de mettre en production sur des serveurs dédiés, qui tournent 24h/24 et qui peuvent également se répartir la charge de travail s’il y a beaucoup de demandes instantanées.

Ceci dépasse néanmoins le cadre de ce cours et sera l’objet d’un cours dédié en 3e année de l’ENSAE: “Mise en production de projets data science donné par Romain Avouac et moi.

Informations additionnelles

environment files have been tested on.

Latest built version: 2025-01-15

Python version used:

'3.12.6 | packaged by conda-forge | (main, Sep 30 2024, 18:08:52) [GCC 13.3.0]'
Package Version
affine 2.4.0
aiobotocore 2.15.1
aiohappyeyeballs 2.4.3
aiohttp 3.10.8
aioitertools 0.12.0
aiosignal 1.3.1
alembic 1.13.3
altair 5.4.1
aniso8601 9.0.1
annotated-types 0.7.0
anyio 4.8.0
appdirs 1.4.4
archspec 0.2.3
asttokens 2.4.1
attrs 24.2.0
babel 2.16.0
bcrypt 4.2.0
beautifulsoup4 4.12.3
black 24.8.0
blinker 1.8.2
blis 0.7.11
bokeh 3.5.2
boltons 24.0.0
boto3 1.35.23
botocore 1.35.23
branca 0.7.2
Brotli 1.1.0
cachetools 5.5.0
cartiflette 0.0.2
Cartopy 0.24.1
catalogue 2.0.10
cattrs 24.1.2
certifi 2024.8.30
cffi 1.17.1
charset-normalizer 3.3.2
click 8.1.7
click-plugins 1.1.1
cligj 0.7.2
cloudpathlib 0.20.0
cloudpickle 3.0.0
colorama 0.4.6
comm 0.2.2
commonmark 0.9.1
conda 24.9.1
conda-libmamba-solver 24.7.0
conda-package-handling 2.3.0
conda_package_streaming 0.10.0
confection 0.1.5
contextily 1.6.2
contourpy 1.3.0
cryptography 43.0.1
cycler 0.12.1
cymem 2.0.10
cytoolz 1.0.0
dask 2024.9.1
dask-expr 1.1.15
databricks-sdk 0.33.0
dataclasses-json 0.6.7
debugpy 1.8.6
decorator 5.1.1
Deprecated 1.2.14
diskcache 5.6.3
distributed 2024.9.1
distro 1.9.0
docker 7.1.0
duckdb 0.10.1
en-core-web-sm 3.7.1
entrypoints 0.4
et_xmlfile 2.0.0
exceptiongroup 1.2.2
executing 2.1.0
fastexcel 0.11.6
fastjsonschema 2.21.1
fiona 1.10.1
Flask 3.0.3
folium 0.17.0
fontawesomefree 6.6.0
fonttools 4.54.1
frozendict 2.4.4
frozenlist 1.4.1
fsspec 2023.12.2
geographiclib 2.0
geopandas 1.0.1
geoplot 0.5.1
geopy 2.4.1
gitdb 4.0.11
GitPython 3.1.43
google-auth 2.35.0
graphene 3.3
graphql-core 3.2.4
graphql-relay 3.2.0
graphviz 0.20.3
great-tables 0.12.0
greenlet 3.1.1
gunicorn 22.0.0
h11 0.14.0
h2 4.1.0
hpack 4.0.0
htmltools 0.6.0
httpcore 1.0.7
httpx 0.28.1
httpx-sse 0.4.0
hyperframe 6.0.1
idna 3.10
imageio 2.36.1
importlib_metadata 8.5.0
importlib_resources 6.4.5
inflate64 1.0.1
ipykernel 6.29.5
ipython 8.28.0
itsdangerous 2.2.0
jedi 0.19.1
Jinja2 3.1.4
jmespath 1.0.1
joblib 1.4.2
jsonpatch 1.33
jsonpointer 3.0.0
jsonschema 4.23.0
jsonschema-specifications 2024.10.1
jupyter-cache 1.0.0
jupyter_client 8.6.3
jupyter_core 5.7.2
kaleido 0.2.1
kiwisolver 1.4.7
langchain 0.3.14
langchain-community 0.3.9
langchain-core 0.3.29
langchain-text-splitters 0.3.5
langcodes 3.5.0
langsmith 0.1.147
language_data 1.3.0
lazy_loader 0.4
libmambapy 1.5.9
locket 1.0.0
loguru 0.7.3
lxml 5.3.0
lz4 4.3.3
Mako 1.3.5
mamba 1.5.9
mapclassify 2.8.1
marisa-trie 1.2.1
Markdown 3.6
markdown-it-py 3.0.0
MarkupSafe 2.1.5
marshmallow 3.25.1
matplotlib 3.9.2
matplotlib-inline 0.1.7
mdurl 0.1.2
menuinst 2.1.2
mercantile 1.2.1
mizani 0.11.4
mlflow 2.16.2
mlflow-skinny 2.16.2
msgpack 1.1.0
multidict 6.1.0
multivolumefile 0.2.3
munkres 1.1.4
murmurhash 1.0.11
mypy-extensions 1.0.0
narwhals 1.22.0
nbclient 0.10.0
nbformat 5.10.4
nest_asyncio 1.6.0
networkx 3.3
nltk 3.9.1
numpy 1.26.4
opencv-python-headless 4.10.0.84
openpyxl 3.1.5
opentelemetry-api 1.16.0
opentelemetry-sdk 1.16.0
opentelemetry-semantic-conventions 0.37b0
orjson 3.10.14
OWSLib 0.28.1
packaging 24.1
pandas 2.2.3
paramiko 3.5.0
parso 0.8.4
partd 1.4.2
pathspec 0.12.1
patsy 0.5.6
Pebble 5.1.0
pexpect 4.9.0
pickleshare 0.7.5
pillow 10.4.0
pip 24.2
platformdirs 4.3.6
plotly 5.24.1
plotnine 0.13.6
pluggy 1.5.0
polars 1.8.2
preshed 3.0.9
prometheus_client 0.21.0
prometheus_flask_exporter 0.23.1
prompt_toolkit 3.0.48
protobuf 4.25.3
psutil 6.0.0
ptyprocess 0.7.0
pure_eval 0.2.3
py7zr 0.20.8
pyarrow 17.0.0
pyarrow-hotfix 0.6
pyasn1 0.6.1
pyasn1_modules 0.4.1
pybcj 1.0.3
pycosat 0.6.6
pycparser 2.22
pycryptodomex 3.21.0
pydantic 2.10.5
pydantic_core 2.27.2
pydantic-settings 2.7.1
Pygments 2.18.0
PyNaCl 1.5.0
pynsee 0.1.8
pyogrio 0.10.0
pyOpenSSL 24.2.1
pyparsing 3.1.4
pyppmd 1.1.1
pyproj 3.7.0
pyshp 2.3.1
PySocks 1.7.1
python-dateutil 2.9.0
python-dotenv 1.0.1
python-magic 0.4.27
pytz 2024.1
pyu2f 0.1.5
pywaffle 1.1.1
PyYAML 6.0.2
pyzmq 26.2.0
pyzstd 0.16.2
querystring_parser 1.2.4
rasterio 1.4.3
referencing 0.35.1
regex 2024.9.11
requests 2.32.3
requests-cache 1.2.1
requests-toolbelt 1.0.0
retrying 1.3.4
rich 13.9.4
rpds-py 0.22.3
rsa 4.9
ruamel.yaml 0.18.6
ruamel.yaml.clib 0.2.8
s3fs 2023.12.2
s3transfer 0.10.2
scikit-image 0.24.0
scikit-learn 1.5.2
scipy 1.13.0
seaborn 0.13.2
setuptools 74.1.2
shapely 2.0.6
shellingham 1.5.4
six 1.16.0
smart-open 7.1.0
smmap 5.0.0
sniffio 1.3.1
sortedcontainers 2.4.0
soupsieve 2.5
spacy 3.7.5
spacy-legacy 3.0.12
spacy-loggers 1.0.5
SQLAlchemy 2.0.35
sqlparse 0.5.1
srsly 2.5.0
stack-data 0.6.2
statsmodels 0.14.4
tabulate 0.9.0
tblib 3.0.0
tenacity 9.0.0
texttable 1.7.0
thinc 8.2.5
threadpoolctl 3.5.0
tifffile 2025.1.10
toolz 1.0.0
topojson 1.9
tornado 6.4.1
tqdm 4.66.5
traitlets 5.14.3
truststore 0.9.2
typer 0.15.1
typing_extensions 4.12.2
typing-inspect 0.9.0
tzdata 2024.2
Unidecode 1.3.8
url-normalize 1.4.3
urllib3 1.26.20
wasabi 1.1.3
wcwidth 0.2.13
weasel 0.4.1
webdriver-manager 4.0.2
websocket-client 1.8.0
Werkzeug 3.0.4
wheel 0.44.0
wordcloud 1.9.3
wrapt 1.16.0
xgboost 2.1.1
xlrd 2.0.1
xyzservices 2024.9.0
yarl 1.13.1
yellowbrick 1.5
zict 3.0.0
zipp 3.20.2
zstandard 0.23.0

View file history

SHA Date Author Description
5ff770b 2024-12-04 10:07:34 lgaliana Partie ML plus esthétique
a3dc832 2024-06-24 16:15:19 Lino Galiana Improve homepage images (#508)
06d003a 2024-04-23 10:09:22 Lino Galiana Continue la restructuration des sous-parties (#492)
005d89b 2023-12-20 17:23:04 Lino Galiana Finalise l’affichage des statistiques Git (#478)
3fba612 2023-12-17 18:16:42 Lino Galiana Remove some badges from python (#476)
1f23de2 2023-12-01 17:25:36 Lino Galiana Stockage des images sur S3 (#466)
e4642ee 2023-11-27 17:02:05 Lino Galiana Deploy ML model as API (#460)
Retour au sommet

Citation

BibTeX
@book{galiana2023,
  author = {Galiana, Lino},
  title = {Python pour la data science},
  date = {2023},
  url = {https://pythonds.linogaliana.fr/},
  doi = {10.5281/zenodo.8229676},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
Galiana, Lino. 2023. Python pour la data science. https://doi.org/10.5281/zenodo.8229676.