Partager via


Débogage des scripts de scoring avec le serveur HTTP d’inférence Azure Machine Learning

Le serveur HTTP d’inférence Azure Machine Learning est un package Python qui expose votre fonction de scoring en tant que point de terminaison HTTP et encapsule le code et les dépendances du serveur Flask dans un même package. Le serveur est inclus dans les images conteneur Docker prédéfinies pour l’inférence qui sont utilisées lors du déploiement d’un modèle avec Azure Machine Learning. En utilisant le package seul, vous pouvez déployer le modèle localement pour la production, et aussi valider facilement votre script de scoring (entrée) dans un environnement de développement local. En cas de problème avec le script de notation, le serveur renvoie une erreur et l’emplacement de l’erreur.

Le serveur peut également être utilisé pour créer des portes de validation dans un pipeline d’intégration et de déploiement continus. Par exemple, vous pouvez démarrer le serveur avec le script candidat et exécutez la suite de tests sur le point de terminaison local.

Cet article s’adresse aux développeurs qui souhaitent utiliser le serveur d’inférence pour déboguer localement et décrit comment utiliser le serveur d’inférence avec des points de terminaison en ligne sous Windows.

Prérequis

Pour utiliser le serveur HTTP d’inférence Azure Machine Learning pour le débogage local, votre configuration doit inclure les composants suivants :

  • Python 3.8 ou version ultérieure
  • Anaconda

Le serveur HTTP d’inférence Azure Machine Learning s’exécute sur les systèmes d’exploitation Windows et Linux.

Explorer les options de débogage local pour les points de terminaison en ligne

En déboguant les points d’extrémité localement avant de les déployer dans le nuage, vous pouvez détecter plus tôt les erreurs dans votre code et votre configuration. Pour déboguer des points de terminaison localement, vous avez plusieurs options, notamment :

Cet article explique comment utiliser le serveur HTTP d’inférence Azure Machine Learning sur Windows.

Le tableau suivant présente une vue d’ensemble des scénarios pour vous aider à choisir la meilleure option :

Scénario Serveur HTTP d’inférence Point de terminaison local
Mettre à jour l’environnement Python local, sans regénération de l’image Docker Oui Non
Mettre à jour le script de scoring Oui Oui
Mettre à jour les configurations de déploiement (déploiement, environnement, code, modèle) Non Oui
Intégrer le débogueur Microsoft Visual Studio Code (VS Code) Oui Oui

Lorsque vous exécutez le serveur HTTP d’inférence localement, vous pouvez vous concentrer sur le débogage de votre script de notation sans vous préoccuper des configurations du conteneur de déploiement.

Installer le package azureml-inference-server-http

Pour installer le package azureml-inference-server-http, exécutez la commande suivante :

python -m pip install azureml-inference-server-http

Remarque

Pour éviter les conflits de paquets, installez le serveur HTTP d’inférence dans un environnement virtuel. Vous pouvez utiliser la commande pip install virtualenv pour activer les environnements virtuels pour votre configuration.

Déboguer votre script de scoring localement

Pour déboguer votre script de scoring localement, vous avez plusieurs options pour tester le comportement du serveur :

Tester le comportement du serveur avec un script de scoring factice

  1. Créez un répertoire nommé server_quickstart pour contenir vos fichiers :

    mkdir server_quickstart
    cd server_quickstart
    
  2. Pour éviter les conflits de paquets, créez un environnement virtuel, tel que myenv , et activez-le :

    python -m virtualenv myenv
    

    Remarque

    Sous Linux, exécutez la commande source myenv/bin/activate pour activer l’environnement virtuel.

    Après avoir testé le serveur, vous pouvez exécuter la commande deactivate pour désactiver l’environnement virtuel Python.

  3. Installez le package azureml-inference-server-http à partir du flux pypi :

    python -m pip install azureml-inference-server-http
    
  4. Créez votre script d’entrée. L’exemple suivant crée un script d’entrée de base et l’enregistre dans un fichier nommé score.py :

    echo -e "import time def init(): \n\t time.sleep(1) \n\n def run(input_data): \n\t return {"message":"Hello, World!"}" > score.py
    
  5. Démarrez le serveur avec la commande azmlinfsrv et définissez le fichier score.py comme script d’entrée :

    azmlinfsrv --entry_script score.py
    

    Remarque

    Le serveur est hébergé à 0.0.0.0, ce qui signifie qu’il doit écouter toutes les adresses IP de l’ordinateur hôte.

  6. Envoyer une requête de notation au serveur à l’aide de l’utilitaire curl :

    curl -p 127.0.0.1:5001/score
    

    Le serveur publie la réponse suivante :

    {"message": "Hello, World!"}
    
  7. Après le test, appuyez sur Ctrl + C pour mettre fin au serveur.

Vous pouvez maintenant modifier le fichier script de notation (score.py) et tester vos modifications en relançant le serveur avec la commande azmlinfsrv --entry_script score.py.

Procéder à l’intégration à Visual Studio Code

Pour utiliser VS Code et l’extension Python pour le débogage avec le package azureml-inference-server-http , vous pouvez utiliser les modes de lancement et attachement.

  • Pour le mode de lancement, configurez le fichier launch.json dans VS Code et démarrez le serveur HTTP d’inférence Azure Machine Learning dans VS Code :

    1. Démarrez VS Code et ouvrez le dossier contenant le script (score.py).

    2. Ajoutez la configuration suivante au fichier launch.json pour cet espace de travail dans VS Code :

      launch.json

      {
          "version": "0.2.0",
          "configurations": [
              {
                  "name": "Debug score.py",
                  "type": "python",
                  "request": "launch",
                  "module": "azureml_inference_server_http.amlserver",
                  "args": [
                      "--entry_script",
                      "score.py"
                  ]
              }
          ]
        }
      
    3. Démarrez la session de débogage dans VS Code en sélectionnant Exécuter>Démarrer le débogage ou utilisez le raccourci clavier F5.

  • Pour le mode Attacher, démarrez le serveur HTTP d’inférence Azure Machine Learning dans une Fenêtre commande, et utilisez VS Code avec l’extension Python pour vous attacher au processus :

    Remarque

    Pour Linux, installez d’abord le gdbpackage en exécutantsudo apt-get install -y gdb la commande.

    1. Ajoutez la configuration suivante au fichier launch.json pour cet espace de travail dans VS Code :

      launch.json

      {
          "version": "0.2.0",
          "configurations": [
              {
                  "name": "Python: Attach using Process Id",
                  "type": "python",
                  "request": "attach",
                  "processId": "${command:pickProcess}",
                  "justMyCode": true
              }
          ]
        }
      
    2. Dans une fenêtre de commande, démarrez le serveur HTTP d’inférence à l’aide de la commande azmlinfsrv --entry_script score.py.

    3. Démarrez la session de débogage dans VS Code.

      1. Sélectionnez Exécuter>démarrer le débogage ou utilisez le raccourci clavier F5.

      2. Dans la fenêtre Commande, affichez les journaux à partir du serveur d’inférence et recherchez l’ID de processus de la commande azmlinfsrv (et non le gunicorn) :

        Capture d’écran montrant une fenêtre Commande affichant les journaux à partir du serveur HTTP d’inférence et l’ID de processus de la commande azmlinfsrv mise en surbrillance.

      3. Dans le débogueur VS Code, entrez l’ID de processus de la commande azmlinfsrv.

        Si vous ne voyez pas le sélecteur de processus VS Code, vous pouvez entrer manuellement l’ID de processus dans le champ processId du fichier launch.json pour cet espace de travail.

Pour les deux modes, vous pouvez définir points d’arrêt et déboguer le script étape par étape.

Utiliser un exemple de bout en bout

La procédure suivante exécute le serveur localement avec échantillon de fichiers (script de scoring, fichier de modèle et environnement) à partir du référentiel d’exemples Azure Machine Learning. Pour plus d’exemples sur l’utilisation de ces fichiers d’exemple, voir Déployer et évaluer un modèle d’apprentissage automatique à l’aide d’un point de terminaison en ligne.

  1. Clonez l’exemple de dépôt :

    git clone --depth 1 https://github.com/Azure/azureml-examples
    cd azureml-examples/cli/endpoints/online/model-1/
    
  2. Créez et activez un environnement virtuel avec conda :

    Dans cet exemple, le package azureml-inference-server-http est automatiquement installé. Le package est inclus en tant que bibliothèque dépendante du package azureml-defaults dans le fichier conda.yml :

    # Create the environment from the YAML file
    conda env create --name model-env -f ./environment/conda.yml
    # Activate the new environment
    conda activate model-env
    
  3. Évaluez votre script de scoring :

    onlinescoring/score.py

    import os
    import logging
    import json
    import numpy
    import joblib
    
    
    def init():
        """
        This function is called when the container is initialized/started, typically after create/update of the deployment.
        You can write the logic here to perform init operations like caching the model in memory
        """
        global model
        # AZUREML_MODEL_DIR is an environment variable created during deployment.
        # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)
        # Please provide your model's folder name if there is one
        model_path = os.path.join(
            os.getenv("AZUREML_MODEL_DIR"), "model/sklearn_regression_model.pkl"
        )
        # deserialize the model file back into a sklearn model
        model = joblib.load(model_path)
        logging.info("Init complete")
    
    
    def run(raw_data):
        """
        This function is called for every invocation of the endpoint to perform the actual scoring/prediction.
        In the example we extract the data from the json input and call the scikit-learn model's predict()
        method and return the result back
        """
        logging.info("model 1: request received")
        data = json.loads(raw_data)["data"]
        data = numpy.array(data)
        result = model.predict(data)
        logging.info("Request processed")
        return result.tolist()
    
  4. Exécutez le serveur HTTP d’inférence en spécifiant le script d’évaluation et le fichier de modèle :

    Le répertoire du modèle spécifié dans le paramètre model_dir est défini à l’aide de la variable AZUREML_MODEL_DIR et récupéré dans le script de notation.

    Dans ce cas, vous spécifiez le répertoire courant ./ parce que le sous-répertoire est spécifié dans le script de notation comme model/sklearn_regression_model.pkl.

    azmlinfsrv --entry_script ./onlinescoring/score.py --model_dir ./
    

    Lorsque le serveur démarre et appelle correctement le script de scoring, l’exemple journal de démarrage s’ouvre. Sinon, le journal affiche les messages d’erreur.

  5. Testez le script de scoring avec un exemple de données :

    Ouvrez une autre fenêtre Commande et accédez au même répertoire de travail que celui où vous exécutez la commande.

    Utilisez l’utilitaire curl pour envoyer un exemple de requête au serveur et recevoir un résultat de scoring :

    curl --request POST "127.0.0.1:5001/score" --header "Content-Type:application/json" --data @sample-request.json
    

    Lorsqu’il n’y a aucun problème dans votre script de scoring, le script retourne le résultat du scoring. Si des problèmes surviennent, vous pouvez essayer de mettre à jour le script de notation et relancer le serveur pour tester le script mis à jour.

Examiner les itinéraires des serveurs

Le serveur HTTP d’inférence écoute sur le port 5001 par défaut aux itinéraires suivants :

Nom Route
Probe liveness 127.0.0.1:5001/
Score 127.0.0.1:5001/score
OpenAPI (swagger) 127.0.0.1:5001/swagger.json

Évaluer les paramètres de serveur

Le serveur HTTP d’inférence accepte les paramètres suivants :

Paramètre Obligatoire Default Description
entry_script True S/O Identifie le chemin relatif ou absolu du script de scoring.
model_dir False S/O Identifie le chemin relatif ou absolu du répertoire qui contient le modèle utilisé pour l’inférence.
port False 5001 Spécifie le port de service du serveur.
worker_count False 1 Fournit le nombre de threads de travail pour traiter les requêtes simultanées.
appinsights_instrumentation_key False S/O Fournit la clé d’instrumentation vers Application Insights où les journaux sont publiés.
access_control_allow_origins False S/O Active CORS pour les origines spécifiées, où plusieurs origines sont séparées par une virgule (,), telle que microsoft.com, bing.com.

Explorer le traitement des requêtes de serveur

Les étapes suivantes montrent comment le serveur HTTP d’inférence d’Azure Machine Learning (azmlinfsrv) traite les demandes entrantes :

  1. Un wrapper de l’interface CLI Python réside autour de la pile réseau du serveur, et est utilisé pour démarrer le serveur.

  2. Un client envoie une requête au serveur.

  3. Le serveur envoie la requête via l’interface WSGI (Web Server Gateway Interface), qui distribue la requête à une application de travail Flask :

  4. L’application worker Flask gère la requête, ce qui inclut le chargement du script d’entrée et toutes les dépendances.

  5. Votre script d’entrée reçoit la requête. Le script d’entrée effectue un appel d’inférence au modèle chargé, et retourne une réponse :

Diagramme montrant comment le serveur HTTP d’inférence traite les requêtes entrantes.

Explorer les journaux du serveur

Il existe deux façons d’obtenir des données de journal pour le test du serveur HTTP d’inférence :

  • Exécutez le package azureml-inference-server-http localement et affichez la sortie des journaux.
  • Utilisez des points de terminaison en ligne et affichez les journaux de conteneur. Le journal du serveur d’inférence est nommé serveur HTTP d’inférence Azure Machine Learning <version>.

Remarque

Le format de journalisation a changé depuis la version 0.8.0. Si votre journal utilise un style différent de celui prévu, mettez à jour le package azureml-inference-server-http avec la dernière version.

Afficher les journaux de démarrage

Lorsque le serveur démarre, les journaux affichent les paramètres du serveur initial comme suit :

Azure Machine Learning Inferencing HTTP server <version>

Server Settings
---------------
Entry Script Name: <entry_script>
Model Directory: <model_dir>
Worker Count: <worker_count>
Worker Timeout (seconds): None
Server Port: <port>
Application Insights Enabled: false
Application Insights Key: <appinsights_instrumentation_key>
Inferencing HTTP server version: azmlinfsrv/<version>
CORS for the specified origins: <access_control_allow_origins>

Server Routes
---------------
Liveness Probe: GET   127.0.0.1:<port>/
Score:          POST  127.0.0.1:<port>/score

<logs>

Par exemple, lorsque vous lancez le serveur en suivant l’exemple de bout en bout, le journal s’affiche comme suit :

Azure Machine Learning Inferencing HTTP server v0.8.0

Server Settings
---------------
Entry Script Name: /home/user-name/azureml-examples/cli/endpoints/online/model-1/onlinescoring/score.py
Model Directory: ./
Worker Count: 1
Worker Timeout (seconds): None
Server Port: 5001
Application Insights Enabled: false
Application Insights Key: None
Inferencing HTTP server version: azmlinfsrv/0.8.0
CORS for the specified origins: None

Server Routes
---------------
Liveness Probe: GET   127.0.0.1:5001/
Score:          POST  127.0.0.1:5001/score

2022-12-24 07:37:53,318 I [32726] gunicorn.error - Starting gunicorn 20.1.0
2022-12-24 07:37:53,319 I [32726] gunicorn.error - Listening at: http://0.0.0.0:5001 (32726)
2022-12-24 07:37:53,319 I [32726] gunicorn.error - Using worker: sync
2022-12-24 07:37:53,322 I [32756] gunicorn.error - Booting worker with pid: 32756
Initializing logger
2022-12-24 07:37:53,779 I [32756] azmlinfsrv - Starting up app insights client
2022-12-24 07:37:54,518 I [32756] azmlinfsrv.user_script - Found user script at /home/user-name/azureml-examples/cli/endpoints/online/model-1/onlinescoring/score.py
2022-12-24 07:37:54,518 I [32756] azmlinfsrv.user_script - run() is not decorated. Server will invoke it with the input in JSON string.
2022-12-24 07:37:54,518 I [32756] azmlinfsrv.user_script - Invoking user's init function
2022-12-24 07:37:55,974 I [32756] azmlinfsrv.user_script - Users's init has completed successfully
2022-12-24 07:37:55,976 I [32756] azmlinfsrv.swagger - Swaggers are prepared for the following versions: [2, 3, 3.1].
2022-12-24 07:37:55,977 I [32756] azmlinfsrv - AML_FLASK_ONE_COMPATIBILITY is set, but patching is not necessary.

Comprendre le format des données du journal

Tous les journaux d’activité du serveur HTTP d’inférence, à l’exception du script du lanceur, présentent des données au format suivant :

<UTC Time> | <level> [<pid>] <logger name> - <message>

L’entrée se compose des éléments suivants :

  • <UTC Time> : heure à laquelle l’entrée a été entrée dans le journal.
  • <pid> : ID du processus associé à l’entrée.
  • <level> : premier caractère du niveau de journalisation pour l’entrée, tel que E pour ERROR, I pour INFO, etc.
  • <logger name> : Nom de la ressource associée à l’entrée du journal.
  • <message> : Contenu du message du journal.

Il existe six niveaux de journalisation dans Python avec des valeurs numériques attribuées en fonction de la gravité :

Niveau de journalisation Valeur numérique
CRITIQUE 50
ERROR 40
AVERTISSEMENT 30
INFO 20
DEBUG 10
NOTSET 0

Résoudre les problèmes liés aux problèmes du serveur

Les sections suivantes fournissent des conseils de dépannage de base pour le serveur HTTP d’inférence d’Azure Machine Learning. Pour dépanner les points de terminaison en ligne, voir Dépannage du déploiement des points de terminaison en ligne.

Vérifier les packages installés

Pour résoudre les problèmes liés aux packages installés, effectuez les étapes suivantes.

  1. Collectez des informations sur les packages et les versions installés pour votre environnement Python.

  2. Confirmez que la version du package Python azureml-inference-server-http spécifiée dans le fichier d’environnement correspond à la version du serveur HTTP d’inférence Azure Machine Learning affichée dans le journal de démarrage.

    Dans certains cas, le programme de résolution de dépendance pip installe des versions de package inattendues. Vous devrez peut-être exécuter pip pour corriger les packages et les versions installés.

  3. Si vous spécifiez Flask ou ses dépendances dans votre environnement, supprimez ces éléments.

    • Les packages dépendants incluent flask, jinja2, itsdangerous, werkzeug, markupsafe et click.
    • flask est listé comme une dépendance dans le package de serveur. La meilleure approche consiste à autoriser le serveur d’inférence à installer le package flask.
    • Lorsque le serveur d’inférence est configuré pour prendre en charge les nouvelles versions de Flask, le serveur reçoit automatiquement les mises à jour du package dès leur mise à disposition.

Vérifier la version du serveur

Le package de serveur azureml-inference-server-http est publié sur PyPI. La page PyPI répertorie les journal des modifications et toutes les versions précédentes.

Si vous utilisez une version antérieure du package, mettez à jour votre configuration vers la dernière version. Le tableau suivant récapitule les versions stables, les problèmes courants et les ajustements recommandés :

Version du package Description Problème Résolution
0.4.x Incluse dans les images de formation datant de 20220601 et antérieures et le package azureml-defaults versions .1.34 à 1.43. La dernière version stable est la version 0.4.13. Pour les versions de serveur antérieures à 0.4.11, il est possible que vous rencontriez des problèmes de dépendance à Flask comme "can't import name Markup from jinja2". Effectuez si possible une mise à niveau vers la version 0.4.13 ou 0.8.x (la dernière version).
0.6.x Préinstallée dans les images d’inférence datant de 20220516 et antérieures. La dernière version stable est la version 0.6.1. N/A N/A
0.7.x Prend en charge Flask 2. La dernière version stable est la version 0.7.7. N/A N/A
0.8.x Le format du journal a changé. La prise en charge de Python 3.6 a pris fin. N/A N/A

Vérifier les dépendances de package

Les packages dépendants les plus pertinents pour le package de serveur azureml-inference-server-http sont les suivants :

  • flask
  • opencensus-ext-azure
  • inference-schema

Si vous avez spécifié le package azureml-defaults dans votre environnement Python, le package azureml-inference-server-http est un package dépendant. La dépendance est installée automatiquement.

Conseil

Si vous utilisez le Kit de développement logiciel (SDK) Python v1 et que vous ne spécifiez pas explicitement le package azureml-defaults dans votre environnement Python, le SDK peut ajouter automatiquement le package. Toutefois, la version du packager est verrouillée par rapport à la version du SDK. Par exemple, si la version du SDK est 1.38.0, l’entrée azureml-defaults==1.38.0 est ajoutée aux exigences pip de l’environnement.

TypeError pendant le démarrage du serveur

Il est possible que vous rencontriez l’erreur TypeError suivante lors du démarrage du serveur :

TypeError: register() takes 3 positional arguments but 4 were given

  File "/var/azureml-server/aml_blueprint.py", line 251, in register

    super(AMLBlueprint, self).register(app, options, first_registration)

TypeError: register() takes 3 positional arguments but 4 were given

Cette erreur se produit lorsque Flask 2 est installé dans votre environnement Python, mais que votre version de package azureml-inference-server-http ne prend pas en charge Flask 2. La prise en charge de Flask 2 est disponible dans le package azureml-inference-server-http versions 0.7.0 et ultérieures, ainsi que le package azureml-defaults versions 1.44 et ultérieures.

  • Si vous n’utilisez pas le package Flask 2 dans une image Docker Azure Machine Learning, utilisez la dernière version du package azureml-inference-server-http ou azureml-defaults.

  • Si vous utilisez le package Flask 2 dans une image Docker Azure Machine Learning, vérifiez que la version de build de l’image indique juillet 2022 ou une date ultérieure.

    Vous trouverez la version de l’image dans les journaux du conteneur. Par exemple :

    2022-08-22T17:05:02,147738763+00:00 | gunicorn/run | AzureML Container Runtime Information
    2022-08-22T17:05:02,161963207+00:00 | gunicorn/run | ###############################################
    2022-08-22T17:05:02,168970479+00:00 | gunicorn/run | 
    2022-08-22T17:05:02,174364834+00:00 | gunicorn/run | 
    2022-08-22T17:05:02,187280665+00:00 | gunicorn/run | AzureML image information: openmpi4.1.0-ubuntu20.04, Materialization Build:20220708.v2
    2022-08-22T17:05:02,188930082+00:00 | gunicorn/run | 
    2022-08-22T17:05:02,190557998+00:00 | gunicorn/run | 
    

    La date de génération de l’image apparaît après la notation Materialization Build. Dans l’exemple précédent, la version de l’image est 20220708 ou le 8 juillet 2022. Dans cet exemple, l’image est compatible avec Flask 2.

    Si vous ne voyez pas de message similaire dans le journal de votre conteneur, votre image est obsolète et doit être mise à jour. Si vous utilisez une image CUDA (Compute Unified Device Architecture) et que vous ne trouvez pas d’image plus récente, vérifiez si votre image est déconseillée dans AzureML-Containers. Vous trouverez des remplacements désignés pour les images déconseillées.

    Si vous utilisez le serveur avec un point de terminaison en ligne, vous trouverez également les journaux dans les Journaux d’activité de page Points de terminaison dans Azure Machine Learning studio.

Si vous effectuez le déploiement avec le SDK v1 et que vous ne spécifiez pas explicitement d’image dans la configuration de votre déploiement, le serveur applique le package openmpi4.1.0-ubuntu20.04 avec une version qui correspond à l’ensemble d’outils de votre SDK local. Toutefois, la version installée peut ne pas être la dernière version disponible de l’image.

Pour le SDK version 1.43, le serveur installe la version par défaut du package openmpi4.1.0-ubuntu20.04:20220616, mais cette version n’est pas compatible avec le SDK 1.43. Veillez à utiliser la dernière version du kit SDK pour votre déploiement.

Si vous ne pouvez pas mettre à jour l’image, vous pouvez éviter temporairement le problème en épinglant l’entrée azureml-defaults==1.43 ou azureml-inference-server-http~=0.4.13 dans votre fichier d’environnement. Ces entrées indiquent au serveur d’installer l’ancienne version avec flask 1.0.x.

ImportError ou ModuleNotFoundError lors du démarrage du serveur

Il est possible que vous rencontriez une erreur ImportError ou ModuleNotFoundError sur des modules spécifiques lors du démarrage du serveur, notamment opencensus, jinja2, markupsafe ou click. L'exemple suivant montre le message d’erreur :

ImportError: cannot import name 'Markup' from 'jinja2'

Les erreurs liées à l’importation et au module se produisent lorsque vous utilisez la version 0.4.10 et versions antérieures du serveur qui n’épinglent pas la dépendance Flask à une version compatible. Pour éviter le problème, installez une version ultérieure du serveur.