Debug dello script di assegnazione dei punteggi con il server HTTP di inferenza di Azure Machine Learning

Il server HTTP di inferenza di Azure Machine Learning è un pacchetto Python che espone la funzione di punteggio come endpoint HTTP ed esegue il wrapping del codice e delle dipendenze del server Flask in un pacchetto singolare. È incluso nelle immagini Docker predefinite per l'inferenza usate durante la distribuzione di un modello con Azure Machine Learning. Usando il pacchetto da solo, è possibile distribuire il modello in locale per la produzione ed è anche possibile convalidare facilmente lo script di assegnazione dei punteggi (voce) in un ambiente di sviluppo locale. Se si verifica un problema con lo script di assegnazione dei punteggi, il server restituirà un errore e la posizione in cui si è verificato l'errore.

Il server può essere usato anche per creare controlli di convalida in una pipeline di integrazione continua e distribuzione. Ad esempio, è possibile avviare il server con lo script candidato ed eseguire il gruppo di test sull'endpoint locale.

Questo articolo è destinato principalmente agli utenti che vogliono usare il server di inferenza per eseguire il debug in locale, ma consentono anche di comprendere come usare il server di inferenza con endpoint online.

Debug locale dell'endpoint online

Il debug degli endpoint in locale prima di distribuirli nel cloud consente di rilevare gli errori nel codice e nella configurazione in precedenza. Per eseguire il debug degli endpoint in locale, è possibile usare:

Questo articolo è incentrato sul server HTTP di inferenza di Azure Machine Learning.

La tabella seguente offre una panoramica degli scenari che consentono di scegliere le opzioni più adatte.

Scenario Server HTTP di inferenza Endpoint locale
Aggiornare l'ambiente Python locale senza ricompilare l'immagine Docker No
Aggiornare lo script di assegnazione dei punteggi
Aggiornare le configurazioni di distribuzione (distribuzione, ambiente, codice, modello) No
Integrare il debugger di VS Code

Eseguendo il server HTTP di inferenza in locale, è possibile concentrarsi sul debug dello script di assegnazione dei punteggi senza essere interessati dalle configurazioni del contenitore di distribuzione.

Prerequisiti

  • Richiede: Python >=3.8
  • Anaconda

Suggerimento

Il server HTTP di inferenza di Azure Machine Learning viene eseguito nei sistemi operativi basati su Windows e Linux.

Installazione

Nota

Per evitare conflitti di pacchetti, installare il server in un ambiente virtuale.

Per installare azureml-inference-server-http package, eseguire il comando seguente nel cmd/terminale:

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

Eseguire il debug dello script di assegnazione dei punteggi in locale

Per eseguire il debug dello script di assegnazione dei punteggi in locale, è possibile testare il comportamento del server con uno script di assegnazione dei punteggi fittizi, usare VS Code per eseguire il debug con il pacchetto azureml-inference-server-http oppure testare il server con uno script di punteggio effettivo, un file di modello e un file di ambiente dal repository di esempi.

Testare il comportamento del server con uno script di assegnazione dei punteggi fittizi

  1. Creare una directory per contenere i file:

    mkdir server_quickstart
    cd server_quickstart
    
  2. Per evitare conflitti di pacchetti, creare un ambiente virtuale e attivarlo:

    python -m venv myenv
    source myenv/bin/activate
    

    Suggerimento

    Dopo il test, eseguire deactivate per disattivare l'ambiente virtuale Python.

  3. Installare il pacchetto azureml-inference-server-http dal feed pypi:

    python -m pip install azureml-inference-server-http
    
  4. Creare lo script di immissione (score.py). L'esempio seguente crea uno script di immissione di base:

    echo '
    import time
    
    def init():
        time.sleep(1)
    
    def run(input_data):
        return {"message":"Hello, World!"}
    ' > score.py
    
  5. Avviare il server (azmlinfsrv) e impostare score.py come script di immissione:

    azmlinfsrv --entry_script score.py
    

    Nota

    Il server è ospitato in 0.0.0.0, il che significa che sarà in ascolto di tutti gli indirizzi IP del computer di hosting.

  6. Inviare una richiesta di assegnazione di punteggio al server usando curl:

    curl -p 127.0.0.1:5001/score
    

    Il server deve rispondere in questo modo.

    {"message": "Hello, World!"}
    

Dopo il test, è possibile premere Ctrl + C per terminare il server. È ora possibile modificare lo script di assegnazione dei punteggi (score.py) e testare le modifiche eseguendo di nuovo il server (azmlinfsrv --entry_script score.py).

Come eseguire l'integrazione con Visual Studio Code

Esistono due modi per usare Visual Studio Code (VS Code) e l'estensione Python per eseguire il debug con il pacchetto azureml-inference-server-http (modalità di avvio e collegamento).

  • Modalità di avvio: configurare launch.json in VS Code e avviare il server HTTP di inferenza di Azure Machine Learning all'interno di VS Code.

    1. Avviare VS Code e aprire la cartella contenente lo script (score.py).

    2. Aggiungere la configurazione seguente a launch.json per tale area di lavoro in 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. Avviare la sessione di debug in VS Code. Selezionare "Esegui" -> "Avvia debug" (o F5).

  • Modalità di collegamento: avviare il server HTTP di inferenza di Azure Machine Learning in una riga di comando e usare VS Code + Estensione Python per connettersi al processo.

    Nota

    Se si usa l'ambiente Linux, installare prima di tutto il gdb pacchetto eseguendo sudo apt-get install -y gdb.

    1. Aggiungere la configurazione seguente a launch.json per tale area di lavoro in 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. Avviare il server di inferenza usando l'interfaccia della riga di comando (azmlinfsrv --entry_script score.py).

    3. Avviare la sessione di debug in VS Code.

      1. In VS Code selezionare "Esegui" -> "Avvia debug" (o F5).
      2. Immettere l'ID processo di azmlinfsrv (non gunicorn) usando i log (dal server di inferenza) visualizzati nell'interfaccia della riga di comando. Screenshot dell'interfaccia della riga di comando che mostra l'ID processo del server.

      Nota

      Se la selezione processo non viene visualizzata, immettere manualmente l'ID processo nel processId campo di launch.json.

In entrambi i modi, è possibile impostare il punto di interruzione e il debug passo dopo passo.

Esempio end-to-end

In questa sezione verrà eseguito il server in locale con file di esempio (script di assegnazione dei punteggi, file di modello e ambiente) nel repository di esempio. I file di esempio vengono usati anche nell'articolo distribuire e assegnare un punteggio a un modello di Machine Learning usando un endpoint online

  1. Clonare il repository di esempio.

    git clone --depth 1 https://github.com/Azure/azureml-examples
    cd azureml-examples/cli/endpoints/online/model-1/
    
  2. Creare e attivare un ambiente virtuale con conda. In questo esempio il azureml-inference-server-http pacchetto viene installato automaticamente perché è incluso come libreria dipendente del azureml-defaults pacchetto in conda.yml come indicato di seguito.

    # 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. Esaminare lo script di assegnazione dei punteggi.

    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. Eseguire il server di inferenza con la specifica dello script di assegnazione dei punteggi e del file del modello. La directory del modello specificata (model_dir parametro ) verrà definita come AZUREML_MODEL_DIR variabile e recuperata nello script di assegnazione dei punteggi. In questo caso, si specifica la directory corrente (./) perché la sottodirectory viene specificata nello script di assegnazione dei punteggi come model/sklearn_regression_model.pkl.

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

    Il log di avvio di esempio verrà visualizzato se il server è stato avviato e lo script di assegnazione dei punteggi è stato richiamato correttamente. In caso contrario, nel log verranno visualizzati messaggi di errore.

  5. Testare lo script di assegnazione dei punteggi con dati di esempio. Aprire un altro terminale e passare alla stessa directory di lavoro per eseguire il comando. Usare il curl comando per inviare una richiesta di esempio al server e ricevere un risultato di assegnazione dei punteggi.

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

    Il risultato dell'assegnazione dei punteggi verrà restituito se non è presente alcun problema nello script di assegnazione dei punteggi. Se si verifica un errore, è possibile provare ad aggiornare lo script di assegnazione dei punteggi e avviare di nuovo il server per testare lo script aggiornato.

Route server

Il server è in ascolto sulla porta 5001 (come impostazione predefinita) in queste route.

Nome Itinerario
Probe di attività 127.0.0.1:5001/
Punteggio 127.0.0.1:5001/punteggio
OpenAPI (swagger) 127.0.0.1:5001/swagger.json

Parametri del server

La tabella seguente contiene i parametri accettati dal server:

Parametro Richiesto Default Descrizione
entry_script Vero N/D Percorso relativo o assoluto dello script di assegnazione dei punteggi.
model_dir Falso N/D Percorso relativo o assoluto della directory che contiene il modello utilizzato per l'inferenza.
port Falso 5001 Porta di servizio del server.
worker_count Falso 1 Numero di thread di lavoro che elaborano richieste simultanee.
appinsights_instrumentation_key Falso N/D Chiave di strumentazione per application insights in cui verranno pubblicati i log.
access_control_allow_origins Falso N/D Abilitare CORS per le origini specificate. Separare più origini con ",".
Esempio: "microsoft.com, bing.com"

Flusso di richiesta

La procedura seguente illustra come il server HTTP di inferenza di Azure Machine Learning (azmlinfsrv) gestisce le richieste in ingresso:

  1. Un wrapper dell'interfaccia della riga di comando di Python si trova intorno allo stack di rete del server e viene usato per avviare il server.
  2. Un client invia una richiesta al server.
  3. Quando viene ricevuta una richiesta, passa attraverso il server WSGI e viene quindi inviato a uno dei ruoli di lavoro.
  4. Le richieste vengono quindi gestite da un'app Flask , che carica lo script di immissione e le eventuali dipendenze.
  5. Infine, la richiesta viene inviata allo script di immissione. Lo script di immissione esegue quindi una chiamata di inferenza al modello caricato e restituisce una risposta.

Diagramma del processo del server HTTP.

Informazioni sui log

Di seguito vengono descritti i log del server HTTP di inferenza di Azure Machine Learning. È possibile ottenere il log quando si esegue localmente azureml-inference-server-http o ottenere i log dei contenitori se si usano endpoint online.

Nota

Il formato di registrazione è cambiato dalla versione 0.8.0. Se si trova il log in uno stile diverso, aggiornare il azureml-inference-server-http pacchetto alla versione più recente.

Suggerimento

Se si usano endpoint online, il log dal server di inferenza inizia con Azure Machine Learning Inferencing HTTP server <version>.

Log di avvio

All'avvio del server, le impostazioni del server vengono visualizzate per la prima volta dai log come indicato di seguito:

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>

Ad esempio, quando si avvia il server è stato seguito l'esempio end-to-end:

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.

Formato log

I log del server di inferenza vengono generati nel formato seguente, ad eccezione degli script di avvio perché non fanno parte del pacchetto Python:

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

Di seguito <pid> è riportato l'ID del processo ed <level> è il primo carattere del livello di registrazione: E per ERRORE, I per INFO e così via.

Esistono sei livelli di registrazione in Python, con numeri associati alla gravità:

Livello di registrazione Valore numerico
CRITICO 50
ERROR 40
AVVISO 30
INFO 20
DEBUG 10
NOT edizione Standard T 0

Guida alla risoluzione dei problemi

In questa sezione verranno forniti suggerimenti di base per la risoluzione dei problemi per il server HTTP di inferenza di Azure Machine Learning. Per risolvere i problemi relativi agli endpoint online, vedere anche Risoluzione dei problemi di distribuzione degli endpoint online

Passaggi principali

I passaggi di base per la risoluzione dei problemi sono:

  1. Raccogliere informazioni sulla versione per l'ambiente Python.
  2. Assicurarsi che la versione del pacchetto python azureml-inference-server-http specificata nel file di ambiente corrisponda alla versione del server HTTP di inferenza di AzureML visualizzata nel log di avvio. A volte il sistema di risoluzione delle dipendenze di pip porta a versioni impreviste dei pacchetti installati.
  3. Se si specifica Flask (e le relative dipendenze) nell'ambiente, rimuoverli. Le dipendenze includono Flask, Jinja2, Werkzeugitsdangerous, MarkupSafe, e click. Flask è elencato come dipendenza nel pacchetto del server ed è consigliabile consentire al server di installarlo. In questo modo, quando il server supporta le nuove versioni di Flask, le si otterrà automaticamente.

Versione del server

Il pacchetto azureml-inference-server-http server viene pubblicato in PyPI. È possibile trovare il log delle modifiche e tutte le versioni precedenti nella pagina PyPI. Eseguire l'aggiornamento alla versione più recente se si usa una versione precedente.

  • 0.4.x: versione in bundle nelle immagini di training ≤ 20220601 e in azureml-defaults>=1.34,<=1.43. 0.4.13 è l'ultima versione stabile. Se si usa il server prima della versione 0.4.11, potrebbero verificarsi problemi di dipendenza Flask, ad esempio non è possibile importare il nome Markup da jinja2. È consigliabile eseguire l'aggiornamento a 0.4.13 o 0.8.x (versione più recente), se possibile.
  • 0.6.x: versione preinstallata nelle immagini di inferenza ≤ 20220516. L'ultima versione stabile è 0.6.1.
  • 0.7.x: la prima versione che supporta Flask 2. L'ultima versione stabile è 0.7.7.
  • 0.8.x: il formato del log è stato modificato e il supporto di Python 3.6 è stato eliminato.

Dipendenze dei pacchetti

I pacchetti più rilevanti per il server azureml-inference-server-http sono i pacchetti seguenti:

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

Se è stato specificato azureml-defaults nell'ambiente Python, il azureml-inference-server-http pacchetto dipende e verrà installato automaticamente.

Suggerimento

Se si usa Python SDK v1 e non si specifica azureml-defaults in modo esplicito nell'ambiente Python, l'SDK può aggiungere il pacchetto. Tuttavia, lo bloccherà alla versione in cui è attivo l'SDK. Ad esempio, se la versione dell'SDK è 1.38.0, verrà aggiunta azureml-defaults==1.38.0 ai requisiti pip dell'ambiente.

Domande frequenti

1. Si è verificato l'errore seguente durante l'avvio del server:


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

Flask 2 è installato nell'ambiente Python, ma esegue una versione di azureml-inference-server-http che non supporta Flask 2. Il supporto per Flask 2 viene aggiunto in azureml-inference-server-http>=0.7.0, che è anche in azureml-defaults>=1.44.

  • Se non si usa questo pacchetto in un'immagine Docker di AzureML, usare la versione più recente di azureml-inference-server-http o azureml-defaults.

  • Se si usa questo pacchetto con un'immagine Docker di AzureML, assicurarsi di usare un'immagine incorporata o successiva a luglio 2022. La versione dell'immagine è disponibile nei log del contenitore. Dovrebbe essere possibile trovare un log simile al seguente:

    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, Materializaton Build:20220708.v2
    2022-08-22T17:05:02,188930082+00:00 | gunicorn/run | 
    2022-08-22T17:05:02,190557998+00:00 | gunicorn/run | 
    

    La data di compilazione dell'immagine viene visualizzata dopo "Materialization Build", che nell'esempio precedente è 20220708, o l'8 luglio 2022. Questa immagine è compatibile con Flask 2. Se nel log del contenitore non viene visualizzato un banner simile al seguente, l'immagine non è aggiornata e deve essere aggiornata. Se si usa un'immagine CUDA e non è possibile trovare un'immagine più recente, verificare se l'immagine è deprecata in AzureML-Containers. In caso affermativo, dovrebbe essere possibile trovare sostituzioni.

  • Se si usa il server con un endpoint online, è anche possibile trovare i log in "Log di distribuzione" nella pagina endpoint online in studio di Azure Machine Learning. Se si distribuisce con SDK v1 e non si specifica in modo esplicito un'immagine nella configurazione di distribuzione, per impostazione predefinita si usa una versione di corrispondente al set di openmpi4.1.0-ubuntu20.04 strumenti dell'SDK locale, che potrebbe non essere la versione più recente dell'immagine. Ad esempio, SDK 1.43 usa per openmpi4.1.0-ubuntu20.04:20220616impostazione predefinita , che non è compatibile. Assicurarsi di usare l'SDK più recente per la distribuzione.

  • Se per qualche motivo non è possibile aggiornare l'immagine, è possibile evitare temporaneamente il problema aggiungendo azureml-defaults==1.43 o azureml-inference-server-http~=0.4.13, che installerà il server versione precedente con Flask 1.0.x.

2. Si è verificato un oggetto ImportError o ModuleNotFoundError nei moduli opencensus, jinja2, MarkupSafeo click durante l'avvio, come nel messaggio seguente:

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

Le versioni precedenti (<= 0.4.10) del server non hanno aggiunto la dipendenza di Flask alle versioni compatibili. Questo problema è stato risolto nella versione più recente del server.

Passaggi successivi