Compartir vía


Depurar scripts 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. El servidor 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 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 devuelve un error y la ubicación del 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.

En este artículo se admiten desarrolladores que desean usar el servidor de inferencia para depurar localmente y se describe cómo usar el servidor de inferencia con puntos de conexión en línea en Windows.

Requisitos previos

Para usar el servidor HTTP de inferencia de Azure Machine Learning para la depuración local, la configuración debe incluir los siguientes componentes:

  • Python 3.8 o versiones posteriores
  • Anaconda

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

Explorar las opciones de depuración local para puntos de conexión en línea

Si depura los puntos de conexión localmente antes de implementarlos en la nube, podrá detectar antes los errores en el código y la configuración. Para depurar puntos de conexión localmente, tiene varias opciones, entre las que se incluyen:

En este artículo se describe cómo trabajar con el servidor HTTP de inferencia de Azure Machine Learning en Windows.

En la tabla siguiente se proporciona información general sobre escenarios que le ayudarán a elegir la mejor opción:

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
Integrar depurador de Microsoft Visual Studio Code (VS Code)

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

Instalar paquete azureml-inference-server-http

Para instalar el paquete azureml-inference-server-http, ejecute el siguiente comando:

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

Nota:

Para evitar conflictos de paquetes, instale el servidor HTTP de inferencia en un entorno virtual. Puede usar el comando pip install virtualenv para habilitar entornos virtuales para la configuración.

Depuración local del script de puntuación

Para depurar el script de puntuación localmente, tiene varias opciones para probar el comportamiento del servidor:

Probar el comportamiento del servidor con script de puntuación ficticio

  1. Cree un directorio denominado server_quickstart para almacenar los archivos:

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

    python -m virtualenv myenv
    

    Nota:

    En Linux, ejecute el comando source myenv/bin/activate para activar el entorno virtual.

    Después de probar el servidor, puede ejecutar el comando 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. En el ejemplo siguiente se crea un script de entrada básico y se guarda en un archivo denominado 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. Inicie el servidor con el comando azmlinfsrv y establezca el archivo 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 escucha todas las direcciones IP del equipo host.

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

    curl -p 127.0.0.1:5001/score
    

    El servidor envía la siguiente respuesta:

    {"message": "Hello, World!"}
    
  7. Después de realizar las pruebas, seleccione Ctrl + C para finalizar el servidor.

Ahora puede modificar el archivo de script de puntuación (score.py) y probar los cambios ejecutando el servidor de nuevo con el comando azmlinfsrv --entry_script score.py.

Integrar con Visual Studio Code

Para usar VS Code y la extensión de Python para depurar con el paquete azureml-inference-server-http, puede usar los modos Iniciar y Adjuntar.

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

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

    2. Agregue la siguiente configuración al archivo 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 la sesión de depuración en VS Code seleccionando Ejecutar>Iniciar depuración o use el método abreviado de teclado F5.

  • Para el modo Adjuntar, inicie el servidor HTTP de inferencia de Azure Machine Learning en una ventana de comandos y use VS Code con la extensión de Python para asociarlo al proceso:

    Nota:

    Para Linux, instale primero el paquete gdb ejecutando el comando sudo apt-get install -y gdb.

    1. Agregue la siguiente configuración al archivo 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. En una ventana de comandos, inicie el servidor HTTP de inferencia mediante el comando azmlinfsrv --entry_script score.py.

    3. Inicie la sesión de depuración en VS Code:

      1. Seleccione Ejecutar>Iniciar depuración o use el método abreviado de teclado F5.

      2. En la ventana de comandos, vea los registros del servidor de inferencia y busque el id. de proceso del comando azmlinfsrv (no el gunicorn):

        Recorte de pantalla que muestra una ventana de comandos que muestra los registros del servidor HTTP de inferencia y el id. de proceso del comando azmlinfsrv resaltado.

      3. En el depurador de VS Code, escriba el identificador de proceso del comando azmlinfsrv.

        Si no ve el selector de procesos de VS Code, puede escribir manualmente el id. de proceso en el campo processId del archivo launch.json para esa área de trabajo.

En ambos modos, puede establecer puntos de interrupción y depurar el script paso a paso.

Usar un ejemplo completo

El siguiente procedimiento ejecuta el servidor localmente con archivos de ejemplo (script de puntuación, archivo de modelo y entorno) desde el repositorio de ejemplo de Azure Machine Learning. Para obtener más ejemplos de cómo usar estos archivos de ejemplo, consulte 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. El paquete se incluye como una biblioteca dependiente del paquete azureml-defaults en el archivo 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. 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 HTTP de inferencia especificando el script de puntuación y el archivo de modelo:

    El directorio del modelo especificado en el parámetro model_dir se define mediante la variable AZUREML_MODEL_DIR y se recupera en el script de puntuación.

    En este caso, especifique el directorio actual ./ porque el subdirectorio se especifica en el script de puntuación como model/sklearn_regression_model.pkl.

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

    Cuando el servidor se inicia e invoca correctamente el script de puntuación, se abre el registro de inicio de ejemplo. De lo contrario, el registro muestra mensajes de error.

  5. Pruebe el script de puntuación con datos de ejemplo:

    Abra otra ventana de comandos y cambie al mismo directorio de trabajo donde se ejecuta el comando.

    Use la utilidad 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
    

    Cuando no hay ningún problema en el script de puntuación, el script devuelve el resultado de puntuación. Si se producen problemas, puede intentar actualizar el script de puntuación e iniciar el servidor de nuevo para probar el script actualizado.

Revisar rutas del servidor

El servidor HTTP de inferencia escucha en el puerto 5001 de forma predeterminada en las rutas siguientes:

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

Revisar parámetros del servidor

El servidor HTTP de inferencia acepta los parámetros siguientes:

Parámetro Obligatorio Valor predeterminado Description
entry_script True N/D Identifica la ruta de acceso relativa o absoluta al script de puntuación.
model_dir False N/D Identifica la ruta de acceso relativa o absoluta al directorio que contiene el modelo usado para la inferencia.
port False 5001 Especifica el puerto de servicio del servidor.
worker_count False 1 Proporciona el número de subprocesos de trabajo para procesar solicitudes simultáneas.
appinsights_instrumentation_key False N/D Proporciona la clave de instrumentación a Application Insights donde se publican los registros.
access_control_allow_origins False N/D Habilita CORS para los orígenes especificados, donde varios orígenes están separados por una coma (,), como microsoft.com, bing.com.

Explorar procesamiento de solicitud de servidor

En los pasos siguientes se muestra cómo el servidor HTTP de inferencia de Azure Machine Learning (azmlinfsrv) controla 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. El servidor envía la solicitud a través del servidor de Interfaz de puerta de enlace de servidor web (WSGI), que envía la solicitud a una aplicación de trabajo de Flask:

  4. La aplicación de trabajo Flask controla la solicitud, lo que incluye cargar el script de entrada y todas las dependencias.

  5. El script de entrada recibe la solicitud. El script de entrada realiza una llamada de inferencia al modelo cargado y devuelve una respuesta:

Diagrama que muestra cómo el servidor HTTP de inferencia procesa las solicitudes entrantes.

Explorar registros de servidor

Hay dos maneras de obtener datos de registro para la prueba del servidor HTTP de inferencia:

  • Ejecute el paquete azureml-inference-server-http localmente y vea la salida de los registros.
  • Use puntos de conexión en línea y vea los registros de contenedor. El registro del servidor de inferencia se denomina <versión> del servidor HTTP de inferencia de Azure Machine Learning.

Nota:

El formato de registro ha cambiado desde la versión 0.8.0. Si el registro usa un estilo diferente del esperado, actualice el paquete azureml-inference-server-http a la versión más reciente.

Visualizar registros de inicio

Cuando se inicia el servidor, los registros muestran la configuración del servidor inicial 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 siguiendo el ejemplo de un extremo a otro, el registro se muestra de la siguiente manera:

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.

Comprender formato de datos de registro

Todos los registros del servidor HTTP de inferencia, excepto el script del iniciador, presentan datos en el formato siguiente:

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

La entrada consta de los siguientes componentes:

  • <UTC Time>: hora a la que se introdujo la entrada en el registro.
  • <pid>: id. del proceso asociado a la entrada.
  • <level>: primer carácter del nivel de registro de la entrada, como E para ERROR, I para INFO, etc.
  • <logger name>: nombre del recurso asociado a la entrada de registro.
  • <message>: contenido del mensaje de registro.

Hay seis niveles de registro en Python con valores numéricos asignados según la gravedad:

Nivel de registro Valor numérico
CRITICAL (CRÍTICA) 50
ERROR 40
ADVERTENCIA 30
INFO 20
DEBUG 10
NOTSET 0

Solucionar problemas de servidor

En las secciones siguientes se proporcionan sugerencias básicas de solución de problemas para el servidor HTTP de inferencia de Azure Machine Learning. Para solucionar problemas de puntos de conexión en línea, consulte Solucionar problemas de implementación de puntos de conexión en línea.

Compruebe los paquetes instalados

Siga estos pasos para solucionar los problemas que puedan aparecer con los paquetes instalados.

  1. Recopile información sobre los paquetes instalados y las versiones del entorno de Python.

  2. Confirme 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 Azure Machine Learning que se muestra en el registro de inicio.

    En algunos casos, el solucionador de dependencias pip instala versiones de paquete inesperadas. Es posible que tenga que ejecutar pip para corregir los paquetes y versiones instalados.

  3. Si especifica Flask o sus dependencias en el entorno, quite estos elementos.

    • Los paquetes dependientes incluyen flask, jinja2, itsdangerous, werkzeug, markupsafe y click.
    • flask aparece como una dependencia en el paquete de servidor. El mejor enfoque es permitir que el servidor de inferencia instale el paquete flask.
    • Cuando el servidor de inferencia está configurado para admitir nuevas versiones de Flask, el servidor recibe automáticamente las actualizaciones del paquete a medida que están disponibles.

Comprobar versión del servidor

El paquete de servidor azureml-inference-server-http se publica en PyPI. La página PyPI enumera el registro de cambios y todas las versiones anteriores.

Si usa una versión anterior del paquete, actualice la configuración a la más reciente. En la tabla siguiente se resumen las versiones estables, los problemas comunes y los ajustes recomendados:

Versión del paquete Descripción Problema Resolución
0.4.x Agrupadas en imágenes de entrenamiento con fecha de 20220601 o anterior y versiones .1.34 de paquete azureml-defaults a través de 1.43. La versión estable más reciente es 0.4.13. En las versiones del servidor anteriores a la 0.4.11, es posible que encuentre problemas de dependencia de Flask, como "can't import name Markup from jinja2". Realice la actualización a las versiones 0.4.13 o 0.8.x, la versión más reciente, si es posible.
0.6.x Preinstalado en imágenes de inferencia con fecha de 20220516 y versiones anteriores. La versión estable más reciente es 0.6.1. N/D N/D
0.7.x Admite Flask 2. La versión estable más reciente es 0.7.7. N/D N/D
0.8.x Se ha cambiado el formato de registro. Finalizó la compatibilidad con Python 3.6. N/D N/D

Comprobar dependencias del paquete

Los paquetes dependientes más relevantes para el paquete de servidor azureml-inference-server-http incluyen:

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

Si especificó el paquete azureml-defaults en el entorno de Python, el paquete azureml-inference-server-http es dependiente. La dependencia se instala automáticamente.

Sugerencia

Si usa el SDK de Python v1 y no especifica explícitamente el paquete azureml-defaults en el entorno de Python, es posible que el SDK agregue automáticamente el paquete. Sin embargo, la versión del empaquetador está bloqueada en relación con la versión del SDK. Por ejemplo, si la versión del SDK es 1.38.0, la entrada azureml-defaults==1.38.0 se agrega a los requisitos pip del entorno.

TypeError durante el inicio del servidor

Es posible que encuentre los siguientes TypeError 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

Este error se produce cuando tiene Flask 2 instalado en el entorno de Python, pero la versión del paquete azureml-inference-server-http no es compatible con Flask 2. La compatibilidad con Flask 2 está disponible en la versión del paquete azureml-inference-server-http 0.7.0 y versiones posteriores, y la versión del paquete azureml-defaults 1.44 y versiones posteriores.

  • Si no usa el paquete Flask 2 en una imagen de Docker de Azure Machine Learning, use la versión más reciente del paquete de azureml-inference-server-http o azureml-defaults.

  • Si usa el paquete Flask 2 en una imagen de Docker de Azure Machine Learning, confirme que la versión de compilación de la imagen es julio de 2022 o posterior.

    La versión de la imagen la pueden encontrar en los registros del contenedor. Por ejemplo:

    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 fecha de compilación de la imagen aparece después de la notación Materialization Build. En el ejemplo anterior, la versión de la imagen es 20220708 o el 8 de julio de 2022. La imagen de este ejemplo es compatible con Flask 2.

    Si no ve un mensaje similar en el registro de contenedor, la imagen no está actualizada y debe actualizarse. Si usa una imagen de arquitectura de dispositivo unificado de proceso (CUDA) y no encuentra una imagen más reciente, compruebe si la imagen está en desuso en AzureML-Containers. Puede encontrar reemplazos designados para imágenes en desuso.

    Si usa el servidor con un punto de conexión en línea, también puede encontrar los registros en la sección Registros de la página Puntos de conexión de 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 servidor aplica el paquete openmpi4.1.0-ubuntu20.04 con una versión que coincida con el conjunto de herramientas del SDK local. Sin embargo, es posible que la versión instalada no sea la versión más reciente disponible de la imagen.

Para la versión 1.43 del SDK, el servidor instala la versión del paquete openmpi4.1.0-ubuntu20.04:20220616 de forma predeterminada, pero esta versión del paquete no es compatible con SDK 1.43. Asegúrese de usar el SDK más reciente para la implementación.

Si no puede actualizar la imagen, puede evitar temporalmente el problema anclando las entradas azureml-defaults==1.43 o azureml-inference-server-http~=0.4.13 en el archivo de entorno. Estas entradas dirigen al servidor para instalar la versión anterior con flask 1.0.x.

ImportError o ModuleNotFoundError durante el inicio del servidor

Es posible que encuentre ImportError o ModuleNotFoundError en módulos concretos, como opencensus, jinja2, markupsafe o click, durante el inicio del servidor. En el ejemplo siguiente se muestra el mensaje de error:

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

Los errores de importación y del módulo se producen cuando se usa la versión 0.4.10, o cualquier versión anterior, del servidor que no ancle la dependencia de Flask a una versión compatible. Para evitar el problema, instale una versión posterior del servidor.