Depuración del script de puntuación con el servidor HTTP de inferencia de Azure Machine Learning

El servidor HTTP de inferencia de Azure Machine Learning es un paquete de Python que expone su función de puntuación como un punto de conexión HTTP y envuelve el código y las dependencias del servidor Flask en un paquete singular. Se incluye en las imágenes de Docker precompiladas para inferencia que se usan al implementar un modelo con Azure Machine Learning. El uso del paquete por sí solo le permite implementar el modelo localmente para la producción, y también puede validar fácilmente su script de puntuación (entrada) en un entorno de desarrollo local. Si hay un problema con el script de puntuación, el servidor devolverá un error y la ubicación donde se produjo el error.

El servidor también puede usarse para crear puertas de validación en una canalización continua de integración e implementación. Puede, por ejemplo, iniciar el servidor con el script candidato y ejecutar el conjunto de pruebas en el punto de conexión local.

Este artículo está dirigido principalmente a los usuarios que quieren usar el servidor de inferencia para depurar localmente, pero también le ayudará a entender cómo usar el servidor de inferencia con puntos de conexión en línea.

Depuración local de puntos de conexión en línea

Depurar puntos de conexión localmente antes de implementarlos en la nube puede ayudarle a detectar antes errores en el código y en la configuración. Para depurar puntos de conexión localmente, puede usar:

Este artículo se centra en el servidor HTTP de inferencia de Azure Machine Learning.

En la tabla siguiente encontrará información general sobre los escenarios que le ayudarán a elegir lo que le funcione mejor en su caso.

Escenario Servidor HTTP de inferencia Punto de conexión local
Actualización del entorno de Python local, sin recompilación de imágenes de Docker No
Actualización del script de puntuación
Actualización de las configuraciones de implementación (implementación, entorno, código, modelo) No
Integración del depurador de VS Code

Al ejecutar el servidor HTTP de inferencia localmente, puede centrarse en depurar el script de puntuación sin verse afectado por las configuraciones del contenedor de implementación.

Requisitos previos

  • Requiere: Python >=3.8
  • Anaconda

Sugerencia

El servidor HTTP de inferencia de Azure Machine Learning se ejecuta en Windows y en los sistemas operativos basados en Linux.

Instalación

Nota

Para evitar conflictos con los paquetes, instale el servidor en un entorno virtual.

Para instalar azureml-inference-server-http package, ejecute el siguiente comando en cmd/terminal:

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

Depuración local del script de puntuación

Para depurar el script de puntuación localmente, puede probar cómo se comporta el servidor con un script de puntuación ficticio, usar VS Code para depurar con el paquete azureml-inference-server-http o probar el servidor con un script de puntuación real, un archivo de modelo y un archivo de entorno de nuestro repositorio de ejemplos.

Prueba del comportamiento del servidor con un script de puntuación ficticio

  1. Cree un directorio para almacenar los archivos:

    mkdir server_quickstart
    cd server_quickstart
    
  2. Para evitar conflictos con los paquetes, cree un entorno virtual y actívelo:

    python -m venv myenv
    source myenv/bin/activate
    

    Sugerencia

    Después de las pruebas, ejecute deactivate para desactivar el entorno virtual de Python.

  3. Instale el paquete azureml-inference-server-http desde la fuente pypi:

    python -m pip install azureml-inference-server-http
    
  4. Creación del script de entrada (score.py). En el ejemplo siguiente se crea un script de entrada básico:

    echo '
    import time
    
    def init():
        time.sleep(1)
    
    def run(input_data):
        return {"message":"Hello, World!"}
    ' > score.py
    
  5. Inicie el servidor (azmlinfsrv) y establezca score.py como script de entrada:

    azmlinfsrv --entry_script score.py
    

    Nota

    El servidor se hospeda en 0.0.0.0, lo que significa que escuchará todas las direcciones IP del equipo host.

  6. Envíe una solicitud de puntuación al servidor mediante curl:

    curl -p 127.0.0.1:5001/score
    

    El servidor debe responder de esta manera.

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

Después de las pruebas, puede presionar Ctrl + C para finalizar el servidor. Ahora puede modificar el script de puntuación (score.py) y probar sus cambios ejecutando de nuevo el servidor (azmlinfsrv --entry_script score.py).

Procedimiento para la integración con Visual Studio Code

Hay dos formas de usar Visual Studio Code (VS Code) y la Extensión de Python para depurar con el paquete azureml-inference-server-http (modos Iniciar y Adjuntar).

  • Modo Iniciar: configure el archivo launch.json en VS Code e inicie el servidor HTTP de inferencia de Azure Machine Learning dentro de VS Code.

    1. Inicie VS Code y abra la carpeta que contiene el script (score.py).

    2. Agregue la siguiente configuración a launch.json para esa área de trabajo en 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. Inicie una sesión de depuración en VS Code. Seleccione "Ejecutar" -> "Iniciar depuración" (o F5).

  • Modo Adjuntar: inicie el servidor HTTP de inferencia de Azure Machine Learning en una línea de comandos y use VS Code y la extensión de Python para adjuntarlo al proceso.

    Nota

    Si está usando un entorno Linux, instale primero el paquete gdb ejecutando sudo apt-get install -y gdb.

    1. Agregue la siguiente configuración a launch.json para esa área de trabajo en 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. Inicie el servidor de inferencia mediante la CLI (azmlinfsrv --entry_script score.py).

    3. Inicie una sesión de depuración en VS Code.

      1. En VS Code, seleccione "Ejecutar" -> "Iniciar depuración" (o F5).
      2. Escriba el id de proceso del azmlinfsrv (no del gunicorn) usando los registros (del servidor de inferencia) mostrados en la CLI. Captura de pantalla de la CLI que muestra el identificador de proceso del servidor.

      Nota

      Si no aparece el selector de procesos, introduzca manualmente el id. del proceso en el campo processId del launch.json.

De ambas formas, puede establecer el punto de interrupción y depurar paso a paso.

Ejemplo de un extremo a otro

En esta sección, ejecutaremos el servidor localmente con archivos de ejemplo (script de puntuación, archivo de modelo y entorno) en nuestro repositorio de ejemplo. Los archivos de ejemplo también se usan en nuestro artículo para Implementar y puntuar un modelo de Machine Learning mediante un punto de conexión en línea.

  1. Clone el repositorio de ejemplo.

    git clone --depth 1 https://github.com/Azure/azureml-examples
    cd azureml-examples/cli/endpoints/online/model-1/
    
  2. Cree y active un entorno virtual con conda. En este ejemplo, el paquete azureml-inference-server-http se instala automáticamente porque está incluido como biblioteca dependiente del paquete azureml-defaults en conda.yml de la siguiente manera.

    # 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. Revise el script de puntuación.

    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. Ejecute el servidor de inferencia con la especificación del script de puntuación y el archivo de modelo. El directorio del modelo especificado (parámetro model_dir) se definirá como variable AZUREML_MODEL_DIR y se recuperará en el script de puntuación. En este caso, se especifica el directorio actual (./), ya que el subdirectorio se especifica en el script de puntuación como model/sklearn_regression_model.pkl.

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

    El registro de inicio de ejemplo se mostrará si el servidor se inició y el script de puntuación se invocó correctamente. De lo contrario, habrá mensajes de error en el registro.

  5. Pruebe el script de puntuación con datos de ejemplo. Abra otro terminal y vaya al mismo directorio de trabajo para ejecutar el comando. Use el comando curl para enviar una solicitud de ejemplo al servidor y recibir un resultado de puntuación.

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

    El resultado de puntuación se devolverá si no hay ningún problema en el script de puntuación. Si encuentra algún problema, puede intentar actualizar el script de puntuación e iniciar el servidor de nuevo para probar el script actualizado.

Rutas de servidor

El servidor escucha en el puerto 5001 (como predeterminado) en estas rutas.

Nombre Ruta
Sondeo de ejecución 127.0.0.1:5001/
Puntuación 127.0.0.1:5001/score
OpenAPI (swagger) 127.0.0.1:5001/swagger.json

Parámetros del servidor

La tabla siguiente contiene los parámetros que acepta el servidor:

Parámetro Obligatorio Valor predeterminado Descripción
entry_script True N/D Ruta de acceso relativa o absoluta al script de puntuación.
model_dir Falso N/D Ruta de acceso relativa o absoluta al directorio que contiene el modelo utilizado para la inferencia.
port False 5001 Puerto de servicio del servidor.
worker_count False 1 Número de subprocesos de trabajo que procesarán solicitudes simultáneas.
appinsights_instrumentation_key Falso N/D Clave de instrumentación de Application Insights donde se publicarán los registros.
access_control_allow_origins Falso N/D Habilite CORS para los orígenes especificados. Separe varios orígenes con ",".
Ejemplo: "microsoft.com, bing.com"

Flujo de las solicitudes

Los siguientes pasos explican cómo el servidor HTTP de inferencia de Azure Machine Learning (azmlinfsrv) gestiona las solicitudes entrantes:

  1. Alrededor de la pila de red del servidor, un contenedor de la CLI de Python inicia el servidor.
  2. Un cliente envía una solicitud al servidor.
  3. Cuando se recibe una solicitud, pasa por el servidor WSGI y se envía a uno de los trabajadores.
  4. Las solicitudes se controlan a continuación mediante una aplicación de Flask, que carga el script de entrada y las dependencias.
  5. Por último, la solicitud se envía al script de entrada. A continuación, el script de entrada realiza una llamada de inferencia al modelo cargado y devuelve una respuesta.

Diagrama del proceso del servidor HTTP.

Comprender los registros

Aquí, se describen los registros del servidor HTTP de inferencia de Azure Machine Learning. Puede obtener el registro cuando ejecute el azureml-inference-server-http localmente u obtener los registros del contenedor si está usando puntos de conexión en línea.

Nota

El formato de registro ha cambiado desde la versión 0.8.0. Si encuentra su registro con un estilo diferente, actualice el paquete azureml-inference-server-http a la última versión.

Sugerencia

Si usa puntos de conexión en línea, el registro del servidor de inferencia comienza por Azure Machine Learning Inferencing HTTP server <version>.

Registros de inicio

Cuando se inicia el servidor, los registros muestran primero la configuración del servidor de la siguiente manera:

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>

Por ejemplo, al iniciar el servidor seguido del ejemplo de de un extremo a otro:

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 de registro

Los registros del servidor de inferencia se generan en el siguiente formato, excepto en los scripts del iniciador, ya que no forman parte del paquete de Python:

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

Aquí <pid> es el id. del proceso y <level> es el primer carácter del nivel de registro: E para ERROR, I para INFO, etc.

Hay seis niveles de registro en Python, con números asociados a la gravedad:

Nivel de registro Valor numérico
CRÍTICO 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
NOTSET 0

Guía de solución de problemas

En esta sección, proporcionaremos sugerencias básicas de solución de problemas para el servidor HTTP de inferencia de Azure Machine Learning. Si quiere solucionar problemas de puntos de conexión en línea, vea también Solución de problemas de implementación de puntos de conexión en línea

Pasos básicos

Los pasos básicos para solucionar problemas son:

  1. Recopile información de versión para el entorno de Python.
  2. Asegúrese de que la versión del paquete de Python azureml-inference-server-http especificada en el archivo de entorno coincide con la versión del servidor HTTP de inferencia de AzureML que se muestra en el registro de inicio. A veces, el solucionador de dependencias de PIP conduce a versiones inesperadas de paquetes instalados.
  3. Si especifica Flask (o sus dependencias) en el entorno, quítelos. Las dependencias incluyen Flask, Jinja2, Werkzeugitsdangerous, MarkupSafe y click. Flask aparece como una dependencia en el paquete de servidor y es mejor permitir que nuestro servidor lo instale. De este modo, cuando el servidor admita nuevas versiones de Flask, las obtendrá automáticamente.

Versión del servidor

El paquete azureml-inference-server-http de servidor se publica en PyPI. Puede encontrar nuestro registro de cambios y todas las versiones anteriores en nuestra página de PyPI. Actualice a la versión más reciente si usa una versión anterior.

  • 0.4.x: la versión que se incluye en imágenes de entrenamiento ≤ 20220601 y en azureml-defaults>=1.34,<=1.43. 0.4.13 es la última versión estable. Si usa el servidor antes de la versión 0.4.11, puede ver problemas de dependencia de Flask, como que no se puede importar el nombre Markup desde jinja2. Se recomienda actualizar a 0.4.13 o 0.8.x (la versión más reciente), si es posible.
  • 0.6.x: versión preinstalada en imágenes de inferencia ≤ 20220516. La versión estable más reciente es 0.6.1.
  • 0.7.x: la primera versión que admite Flask 2. La versión estable más reciente es 0.7.7.
  • 0.8.x: el formato de registro ha cambiado y se ha eliminado la compatibilidad con Python 3.6.

Dependencias de paquetes

Los paquetes más relevantes para el servidor azureml-inference-server-http son los siguientes:

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

Si especificó azureml-defaults en su entorno Python, el paquete azureml-inference-server-http es dependiente y se instalará automáticamente.

Sugerencia

Si está usando Python SDK v1 y no especifica explícitamente azureml-defaults en su entorno Python, el SDK puede añadir el paquete por usted. Sin embargo, se bloqueará en la versión en la que se encuentra el SDK. Por ejemplo, si la versión del SDK es 1.38.0, se agregará azureml-defaults==1.38.0 a los requisitos de pip del entorno.

Preguntas más frecuentes

1. He encontrado el siguiente error durante el inicio del servidor:


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

Tiene Flask 2 instalado en el entorno de Python, pero ejecuta una versión de azureml-inference-server-http que no admite Flask 2. La compatibilidad con Flask 2 se agrega en azureml-inference-server-http>=0.7.0, que también está en azureml-defaults>=1.44.

  • Si no usa este paquete en una imagen de Docker de AzureML, use la versión más reciente de azureml-inference-server-http o azureml-defaults.

  • Si usa este paquete con una imagen de Docker de AzureML, asegúrese de que usa una imagen integrada o posterior a julio de 2022. La versión de la imagen está disponible en los registros de contenedor. Debería poder encontrar un registro similar al siguiente:

    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 fecha de compilación de la imagen aparece después de "Compilación de materialización", que en el ejemplo anterior es 20220708, o el 8 de julio de 2022. Esta imagen es compatible con Flask 2. Si no ve un banner como este en el registro de contenedor, la imagen no está actualizada y debe actualizarse. Si usa una imagen CUDA y no encuentra una imagen más reciente, compruebe si la imagen está en desuso en AzureML-Containers. Si es así, debería poder encontrar reemplazos.

  • Si está usando el servidor con un punto de conexión en línea, también puede encontrar los registros en "Registros de implementación" en la página del punto de conexión en línea en Estudio de Azure Machine Learning. Si implementa con SDK v1 y no especifica explícitamente una imagen en la configuración de implementación, el valor predeterminado es usar una versión de openmpi4.1.0-ubuntu20.04 que coincida con el conjunto de herramientas del SDK local, que puede que no sea la versión más reciente de la imagen. Por ejemplo, SDK 1.43 usará openmpi4.1.0-ubuntu20.04:20220616 de forma predeterminada, que es incompatible. Asegúrese de usar el SDK más reciente para la implementación.

  • Si por algún motivo no puede actualizar la imagen, puede evitar temporalmente el problema anclando azureml-defaults==1.43 o azureml-inference-server-http~=0.4.13, que instalará el servidor de versiones anterior con Flask 1.0.x.

2. He encontrado un ImportError o ModuleNotFoundError en los módulos opencensus, jinja2, MarkupSafe o click durante el inicio, como el mensaje siguiente:

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

Las versiones anteriores (<= 0.4.10) del servidor no anclaban la dependencia de Flask a versiones compatibles. Este problema se ha corregido en la versión más reciente del servidor.

Pasos siguientes