Compartilhar via


Depurar script de pontuação com o servidor HTTP de inferência do Azure Machine Learning

O servidor HTTP de inferência do Azure Machine Learning é um pacote Python que expõe sua função de pontuação como um ponto de extremidade HTTP e encapsula o código do servidor Flask e as dependências em um pacote singular. Ele está incluído nas imagens predefinidas do Docker para inferência que são usadas na implantação de um modelo com o Azure Machine Learning. Usando o pacote sozinho, você pode implantar o modelo localmente para produção e também pode validar facilmente seu script de pontuação (entrada) em um ambiente de desenvolvimento local. Se houver um problema com o script de pontuação, o servidor retornará um erro e o local em que o erro ocorreu.

O servidor também pode ser usado para criar portas de validação em um pipeline de implantação e integração contínua. Por exemplo, você pode iniciar o servidor com o script do candidato e execute o conjunto de testes no ponto de extremidade local.

Este artigo tem como alvo principalmente usuários que desejam usar o servidor de inferência para depurar localmente, mas também ajudará você a entender como usar o servidor de inferência com pontos de extremidade online.

Depuração do ponto de extremidade local online

Depurar pontos de extremidade localmente antes de implantá-los na nuvem pode ajudar você a capturar erros em seu código e configuração anteriormente. Para depurar pontos de extremidade localmente, você pode usar:

Este artigo se concentra no servidor HTTP de inferência do Azure Machine Learning.

A tabela a seguir fornece uma visão geral dos cenários para ajudar você a escolher o mais adequado.

Cenário Servidor HTTP de inferência Ponto de extremidade local
Atualizar o ambiente Python local, sem a recomposição de imagem do Docker Sim Não
Criar script de pontuação Sim Sim
Atualizar configurações de implantação (implantação, ambiente, código, modelo) Não Sim
Integrar o Depurador do VS Code Sim Sim

Ao executar o servidor HTTP de inferência localmente, você poderá se concentrar na depuração do script de pontuação sem ser afetado pelas configurações do contêiner de implantação.

Pré-requisitos

  • Requer: Python >=3,8
  • Anaconda

Dica

O servidor HTTP de inferência do Azure Machine Learning é executado em sistemas operacionais baseados no Windows e no Linux.

Instalação

Observação

Para evitar conflitos de pacote, instale o servidor em um ambiente virtual.

Para instalar o azureml-inference-server-http package, execute o seguinte comando em seu cmd/terminal:

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

Depurar o script de pontuação localmente

Para depurar seu script de pontuação localmente, você pode testar como o servidor se comporta com um script de pontuação fictício, usar o VS Code para depurar com o pacote azureml-inference-server-http ou testar o servidor com um script de pontuação real, um arquivo de modelo e um arquivo de ambiente do repositório de exemplos.

Testar o comportamento do servidor com um script de pontuação fictício

  1. Crie um diretório para salvar seus arquivos:

    mkdir server_quickstart
    cd server_quickstart
    
  2. Para evitar conflitos de pacote, crie um ambiente virtual e ative-o:

    python -m venv myenv
    source myenv/bin/activate
    

    Dica

    Após o teste, execute deactivate para desativar o ambiente virtual do Python.

  3. Instale o pacote azureml-inference-server-http do feed pypi:

    python -m pip install azureml-inference-server-http
    
  4. Crie o script de entrada (score.py). O seguinte exemplo cria um 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 o servidor e defina score.py como o script de entrada:

    azmlinfsrv --entry_script score.py
    

    Observação

    O servidor é hospedado em 0.0.0.0, o que significa que ele escutará todos os endereços IP do computador de hospedagem.

  6. Envie uma solicitação de pontuação para o servidor usando curl:

    curl -p 127.0.0.1:5001/score
    

    O servidor deve responder assim.

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

Após o teste, você pode pressionar Ctrl + C para encerrar o servidor. Agora você pode mudar o script de pontuação (score.py) e testar suas alterações executando o servidor novamente (azmlinfsrv --entry_script score.py).

Como fazer a integração com o Visual Studio Code

Há duas formas de usar o VSCode (Visual Studio Code) e a Extensão Python para depurar com o pacote azureml-inferência-server-http (Modos Iniciar e Anexar).

  • Modo de inicialização: configure o launch.json no VS Code e inicie o servidor HTTP de inferência do Azure Machine Learning no VS Code.

    1. Inicie o VS Code e abra a pasta que contém o script (score.py).

    2. Adicione a seguinte configuração a launch.json para esse workspace no 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 uma sessão de depuração no VS Code. Selecione "Executar" –> "Iniciar Depuração" (ou F5).

  • Modo de anexação: inicie o servidor HTTP de inferência do Azure Machine Learning em uma linha de comando e use a extensão do VS Code + Python para anexá-lo ao processo.

    Observação

    Se você estiver usando o ambiente Linux, primeiro instale o pacote gdb executando sudo apt-get install -y gdb.

    1. Adicione a seguinte configuração a launch.json para esse workspace no 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 o servidor de inferência usando a CLI (azmlinfsrv --entry_script score.py).

    3. Inicie uma sessão de depuração no VS Code.

      1. No VS Code, selecione "Executar" –> "Iniciar Depuração" (ou F5).
      2. Insira a ID do processo do azmlinfsrv (não o gunicorn) usando os logs (do servidor de inferência) exibidos na CLI. Captura de tela da CLI que mostra a ID do processo do servidor.

      Observação

      Se o seletor de processo não for exibido, insira manualmente a ID do processo no campo processId de launch.json.

De ambas as formas, você pode definir o ponto de interrupção e depurar passo a passo.

Exemplo de ponta a ponta

Nesta seção, executaremos o servidor localmente com arquivos de exemplo (script de pontuação, arquivo de modelo e ambiente) em nosso repositório de exemplo. Os arquivos de exemplo também são usados em nosso artigo para Implantar e pontuar um modelo de machine learning usando um ponto de extremidade online

  1. Clone o repositório de exemplo.

    git clone --depth 1 https://github.com/Azure/azureml-examples
    cd azureml-examples/cli/endpoints/online/model-1/
    
  2. Crie e ative um ambiente virtual com conda. Neste exemplo, o pacote azureml-inference-server-http é instalado automaticamente porque está incluído como uma biblioteca dependente do pacote azureml-defaults no conda.yml da maneira indicada abaixo.

    # 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. Analise seu script de pontuação.

    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. Execute o servidor de inferência com a especificação do script de pontuação e do arquivo de modelo. O diretório de modelo especificado (parâmetro model_dir) será definido como variável AZUREML_MODEL_DIR e recuperado no script de pontuação. Nesse caso, especificamos o diretório atual (./) já que o subdiretório é especificado no script de pontuação como model/sklearn_regression_model.pkl.

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

    O exemplo de log de inicialização será mostrado se o servidor foi iniciado e o script de pontuação foi invocado com êxito. Caso contrário, haverá mensagens de erro no log.

  5. Teste o script de pontuação com um exemplo de dados. Abra outro terminal e vá para o mesmo diretório de trabalho para executar o comando. Use o comando curl a fim de enviar uma solicitação de exemplo para o servidor e receber um resultado de pontuação.

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

    O resultado da pontuação será retornado se não houver nenhum problema no script de pontuação. Se você encontrar algo errado, poderá tentar atualizar o script de pontuação e iniciar o servidor novamente para testar o script atualizado.

Rotas do servidor

O servidor está escutando na porta 5001 (como padrão) nessas rotas.

Name Rota
Investigação de atividade 127.0.0.1:5001/
Pontuação 127.0.0.1:5001/pontuação
OpenAPI (Swagger) 127.0.0.1:5001/swagger.json

Parâmetros do Servidor

A tabela a seguir contém os parâmetros aceitos pelo servidor:

Parâmetro Obrigatório Padrão Descrição
entry_script True N/D O caminho relativo ou absoluto para o script de pontuação.
model_dir Falso N/D O caminho relativo ou absoluto para o diretório que contém o modelo usado para inferência.
porta Falso 5001 A porta de serviço do servidor.
worker_count Falso 1 O número de threads de trabalho que processarão solicitações simultâneas.
appinsights_instrumentation_key Falso N/D A chave de instrumentação para os insights do aplicativo em que os logs serão publicados.
access_control_allow_origins Falso N/D Habilite o CORS para as origens especificadas. Separe várias origens com ",".
Exemplo: "microsoft.com, bing.com"

Fluxo de solicitação

As etapas a seguir explicam como a inferência do servidor HTTP do Azure Machine Learning (azmlinfsrv) lida com as solicitações de entrada:

  1. Um wrapper da CLI do Python fica em torno da pilha de rede do servidor e é usado para iniciar o servidor.
  2. Um cliente envia uma solicitação ao servidor.
  3. Quando uma solicitação é recebida, ela passa pelo servidor WSGI e, em seguida, é expedida para uma das funções de trabalho.
  4. As solicitações são então tratadas por um aplicativo Flask, que carrega o script de entrada e dependências.
  5. Por fim, a solicitação é enviada ao script de entrada. Em seguida, o script de entrada faz uma chamada de inferência para o modelo carregado e retorna uma resposta.

Diagrama do processo do servidor HTTP.

Entendendo logs

Aqui descrevemos os logs do servidor HTTP de inferência do Azure Machine Learning. Você pode obter o log ao executar o azureml-inference-server-http localmente ou ao obter logs de contêiner se estiver usando pontos de extremidade online.

Observação

O formato de registro em log foi alterado desde a versão 0.8.0. Se você encontrar seu log em um estilo diferente, atualize o pacote azureml-inference-server-http para a versão mais recente.

Dica

Se você estiver usando pontos de extremidade online, o log do servidor de inferência começará com Azure Machine Learning Inferencing HTTP server <version>.

Logs de inicialização

Quando o servidor é iniciado, as configurações do servidor são exibidas pela primeira vez pelos logs da seguinte maneira:

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 exemplo, quando você inicia o servidor seguindo o exemplo de ponta a ponta:

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 log

Os logs do servidor de inferência são gerados no seguinte formato, exceto para os scripts do inicializador, pois eles não fazem parte do pacote Python:

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

Aqui, <pid> é a ID do processo e <level> é o primeiro caractere do nível de registro em log – E para ERRO, I para INFORMAÇÃO, etc.

Há seis níveis de registro em log no Python, com números associados à gravidade:

Nível de log Valor numérico
CRÍTICO 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
NOTSET 0

Guia de Solução de Problemas

Nesta seção, forneceremos dicas básicas de solução de problemas para o servidor HTTP de inferência do Azure Machine Learning. Se você quiser solucionar problemas de pontos de extremidade online, confira também Solução de problemas de implantação de pontos de extremidade online

Etapas básicas

As etapas básicas para solução de problemas são:

  1. Reunir informações de versão para seu ambiente do Python.
  2. Verificar se a versão do pacote python azureml-inference-server-http especificada no arquivo de ambiente corresponde à versão do servidor HTTP de Inferência do AzureML exibida no log de inicialização. Às vezes, o resolvedor de dependência do pip leva a versões inesperadas de pacotes instalados.
  3. Se você tiver especificado o Flask (e suas dependências) em seu ambiente, remova-os. As dependências incluem Flask, Jinja2, itsdangerous, Werkzeug, MarkupSafee click. O Flask é listado como uma dependência no pacote do servidor e é melhor permitir que nosso servidor o instale. Dessa forma, quando o servidor der suporte a novas versões do Flask, você as obterá automaticamente.

Versão do servidor __

O pacote do servidor azureml-inference-server-http é publicado no PyPI. Você pode encontrar nossa lista de alterações e todas as versões anteriores em nossa página PyPI. Atualize para a versão mais recente se você estiver usando uma versão anterior.

  • 0.4.x: A versão agrupada em imagens de treinamento ≤ 20220601 e em azureml-defaults>=1.34,<=1.43. 0.4.13 é a última versão estável. Se você usar o servidor antes da versão 0.4.11, poderá ver problemas de dependência do Flask, como não poder importar o nome Markup de jinja2. É recomendável atualizar para 0.4.13 ou 0.8.x (a versão mais recente), se possível.
  • 0.6.x: A versão pré-instalada em imagens de inferência ≤ 20220516. A última versão estável é 0.6.1.
  • 0.7.x: A primeira versão que dá suporte ao Flask 2. A última versão estável é 0.7.7.
  • 0.8.x: O formato de log foi alterado e o suporte ao Python 3.6 foi descartado.

Dependências do pacote

Os pacotes mais relevantes para o servidor azureml-inference-server-http são os seguintes pacotes:

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

Se você especificou azureml-defaults em seu ambiente Python, o pacote azureml-inference-server-http é dependente e será instalado automaticamente.

Dica

Se você estiver usando o SDK do Python v1 e não especificar azureml-defaults explicitamente em seu ambiente python, o SDK poderá adicionar o pacote para você. No entanto, ele o bloqueará na versão em que o SDK está. Por exemplo, se a versão do SDK for 1.38.0, ela adicionará azureml-defaults==1.38.0 aos requisitos de pip do ambiente.

Perguntas frequentes

1. Encontrei o seguinte erro durante a inicialização do 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

Você tem o Flask 2 instalado em seu ambiente Python, mas está executando uma versão de azureml-inference-server-http que não dá suporte ao Flask 2. O suporte para Flask 2 é adicionado azureml-inference-server-http>=0.7.0, que também está em azureml-defaults>=1.44.

  • Se você não estiver usando esse pacote em uma imagem do Docker do AzureML, use a versão mais recente azureml-inference-server-http ou azureml-defaults.

  • Se você estiver usando esse pacote com uma imagem do Docker do AzureML, verifique se está usando uma imagem interna ou após julho de 2022. A versão da imagem está disponível nos logs de contêiner. Você deve encontrar um log semelhante ao seguinte:

    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 | 
    

    A data de compilação da imagem é exibida após “Compilação de Materialização”, que no exemplo acima é 20220708, ou 8 de julho de 2022. Essa imagem é compatível com o Flask 2. Se você não vir uma faixa como essa no log de contêineres, sua imagem estará desatualizada e deverá ser atualizada. Se você estiver usando uma imagem CUDA e não conseguir encontrar uma imagem mais recente, verifique se sua imagem foi preterida em Contêineres do AzureML. Se for, você deve encontrar substituições.

  • Se você estiver usando o servidor com um ponto de extremidade online, você também poderá encontrar os logs em “Logs de implantação” na página de ponto de extremidade online no Estúdio do Azure Machine Learning. Se você implantar com o SDK v1 e não especificar explicitamente uma imagem em sua configuração de implantação, o padrão será usar uma versão de openmpi4.1.0-ubuntu20.04 que corresponda ao conjunto de ferramentas do SDK local, que pode não ser a versão mais recente da imagem. Por exemplo, o SDK 1.43 usará o padrão openmpi4.1.0-ubuntu20.04:20220616, o que é incompatível. Certifique-se de usar o SDK mais recente para sua implantação.

  • Se, por algum motivo, você não conseguir atualizar a imagem, poderá evitar temporariamente o problema fixando azureml-defaults==1.43 ou azureml-inference-server-http~=0.4.13, que instalará o servidor de versão mais antigo com Flask 1.0.x.

2. Encontrei um ImportError ou ModuleNotFoundError nos módulos opencensus, jinja2, MarkupSafe ou click durante a inicialização, como a seguinte mensagem:

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

As versões mais antigas (<= 0.4.10) do servidor não fixaram a dependência do Flask em versões compatíveis. Esse problema foi corrigido na versão mais recente do servidor.

Próximas etapas