Criação de um script de entrada avançado

APLICA-SE A:Python SDK azureml v1

Este artigo explica como escrever scripts de entrada para casos de uso especializados.

Pré-requisitos

Este artigo pressupõe que você já tenha um modelo de aprendizado de máquina treinado que pretende implantar com o Azure Machine Learning. Para saber mais sobre a implantação de modelos, consulte Implantar modelos de aprendizado de máquina no Azure.

Gere automaticamente um esquema do Swagger

Para gerar automaticamente um esquema para seu serviço Web, forneça uma amostra da entrada e/ou saída no construtor para um dos objetos de tipo definidos. O tipo e o exemplo são usados para criar automaticamente o esquema. Em seguida, o Azure Machine Learning cria uma especificação OpenAPI (anteriormente, especificação Swagger) para o serviço Web durante a implantação.

Aviso

Você não deve usar dados confidenciais ou privados para entrada ou saída de amostra. A página Swagger para inferência hospedada em AML expõe os dados de exemplo.

Estes tipos são atualmente suportados:

  • pandas
  • numpy
  • pyspark
  • Objeto Python padrão

Para usar a geração de esquema, inclua o pacote de código inference-schema aberto versão 1.1.0 ou superior em seu arquivo de dependências. Para obter mais informações sobre este pacote, consulte InferenceSchema no GitHub. Para gerar Swagger em conformidade para consumo automatizado de serviços Web, a função run() do script de pontuação deve ter a forma de API de:

  • Um primeiro parâmetro do tipo StandardPythonParameterType, chamado Inputs e aninhado
  • Um segundo parâmetro opcional do tipo StandardPythonParameterType, chamado GlobalParameters
  • Retornar um dicionário do tipo StandardPythonParameterType, chamado Resultados e aninhado

Defina os formatos de exemplo de entrada e saída nas input_sample variáveis e output_sample , que representam os formatos de solicitação e resposta para o serviço Web. Use essas amostras nos decoradores de função de entrada e saída na run() função. O exemplo de scikit-learn a seguir usa a geração de esquema.

Ponto de extremidade compatível com Power BI

O exemplo a seguir demonstra como definir a forma da API de acordo com as instruções anteriores. Esse método é suportado para consumir o serviço Web implantado do Power BI.

import json
import pickle
import numpy as np
import pandas as pd
import azureml.train.automl
from sklearn.externals import joblib
from sklearn.linear_model import Ridge

from inference_schema.schema_decorators import input_schema, output_schema
from inference_schema.parameter_types.standard_py_parameter_type import StandardPythonParameterType
from inference_schema.parameter_types.numpy_parameter_type import NumpyParameterType
from inference_schema.parameter_types.pandas_parameter_type import PandasParameterType


def init():
    global model
    # Replace filename if needed.
    model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')
    # Deserialize the model file back into a sklearn model.
    model = joblib.load(model_path)


# providing 3 sample inputs for schema generation
numpy_sample_input = NumpyParameterType(np.array([[1,2,3,4,5,6,7,8,9,10],[10,9,8,7,6,5,4,3,2,1]],dtype='float64'))
pandas_sample_input = PandasParameterType(pd.DataFrame({'name': ['Sarah', 'John'], 'age': [25, 26]}))
standard_sample_input = StandardPythonParameterType(0.0)

# This is a nested input sample, any item wrapped by `ParameterType` will be described by schema
sample_input = StandardPythonParameterType({'input1': numpy_sample_input, 
                                        'input2': pandas_sample_input, 
                                        'input3': standard_sample_input})

sample_global_parameters = StandardPythonParameterType(1.0) # this is optional
sample_output = StandardPythonParameterType([1.0, 1.0])
outputs = StandardPythonParameterType({'Results':sample_output}) # 'Results' is case sensitive

@input_schema('Inputs', sample_input) 
# 'Inputs' is case sensitive

@input_schema('GlobalParameters', sample_global_parameters) 
# this is optional, 'GlobalParameters' is case sensitive

@output_schema(outputs)

def run(Inputs, GlobalParameters): 
    # the parameters here have to match those in decorator, both 'Inputs' and 
    # 'GlobalParameters' here are case sensitive
    try:
        data = Inputs['input1']
        # data will be convert to target format
        assert isinstance(data, np.ndarray)
        result = model.predict(data)
        return result.tolist()
    except Exception as e:
        error = str(e)
        return error

Gorjeta

O valor de retorno do script pode ser qualquer objeto Python serializável para JSON. Por exemplo, se seu modelo retornar um dataframe Pandas que contém várias colunas, você pode usar um decorador de saída semelhante ao código a seguir:

output_sample = pd.DataFrame(data=[{"a1": 5, "a2": 6}])
@output_schema(PandasParameterType(output_sample))
...
result = model.predict(data)
return result

Dados binários (ou seja, de imagem)

Se seu modelo aceita dados binários, como uma imagem, você deve modificar o arquivo de score.py usado para sua implantação para aceitar solicitações HTTP brutas. Para aceitar dados brutos, use a AMLRequest classe em seu script de entrada e adicione o @rawhttp decorador à run() função.

Aqui está um exemplo de um score.py que aceita dados binários:

from azureml.contrib.services.aml_request import AMLRequest, rawhttp
from azureml.contrib.services.aml_response import AMLResponse
from PIL import Image
import json


def init():
    print("This is init()")
    

@rawhttp
def run(request):
    print("This is run()")
    
    if request.method == 'GET':
        # For this example, just return the URL for GETs.
        respBody = str.encode(request.full_path)
        return AMLResponse(respBody, 200)
    elif request.method == 'POST':
        file_bytes = request.files["image"]
        image = Image.open(file_bytes).convert('RGB')
        # For a real-world solution, you would load the data from reqBody
        # and send it to the model. Then return the response.

        # For demonstration purposes, this example just returns the size of the image as the response.
        return AMLResponse(json.dumps(image.size), 200)
    else:
        return AMLResponse("bad request", 500)

Importante

A AMLRequest classe está no azureml.contrib namespace. As entidades neste namespace mudam frequentemente à medida que trabalhamos para melhorar o serviço. Qualquer coisa neste namespace deve ser considerada uma visualização que não é totalmente suportada pela Microsoft.

Se você precisar testar isso em seu ambiente de desenvolvimento local, poderá instalar os componentes usando o seguinte comando:

pip install azureml-contrib-services

Nota

500 não é recomendado como um código de status personalizado, pois no lado azureml-fe, o código de status será reescrito para 502.

  • O código de status é passado através do azureml-fe, em seguida, enviado para o cliente.
  • O azureml-fe apenas reescreve o 500 retornado do lado do modelo para ser 502, o cliente recebe 502.
  • Mas se o azureml-fe em si retorna 500, o lado do cliente ainda recebe 500.

A AMLRequest classe só permite que você acesse os dados brutos postados no arquivo score.py , não há nenhum componente do lado do cliente. A partir de um cliente, você posta dados normalmente. Por exemplo, o código Python a seguir lê um arquivo de imagem e posta os dados:

import requests

uri = service.scoring_uri
image_path = 'test.jpg'
files = {'image': open(image_path, 'rb').read()}
response = requests.post(uri, files=files)

print(response.json)

Partilha de recursos transversais à origem (CORS)

O compartilhamento de recursos entre origens é uma maneira de permitir que recursos em uma página da Web sejam solicitados de outro domínio. O CORS funciona através de cabeçalhos HTTP enviados com o pedido do cliente e devolvidos com a resposta do serviço. Para obter mais informações sobre CORS e cabeçalhos válidos, consulte Compartilhamento de recursos entre origens na Wikipédia.

Para configurar a implantação do modelo para dar suporte ao CORS, use a AMLResponse classe no script de entrada. Essa classe permite que você defina os cabeçalhos no objeto de resposta.

O exemplo a seguir define o Access-Control-Allow-Origin cabeçalho para a resposta do script de entrada:

from azureml.contrib.services.aml_request import AMLRequest, rawhttp
from azureml.contrib.services.aml_response import AMLResponse


def init():
    print("This is init()")

@rawhttp
def run(request):
    print("This is run()")
    print("Request: [{0}]".format(request))
    if request.method == 'GET':
        # For this example, just return the URL for GET.
        # For a real-world solution, you would load the data from URL params or headers
        # and send it to the model. Then return the response.
        respBody = str.encode(request.full_path)
        resp = AMLResponse(respBody, 200)
        resp.headers["Allow"] = "OPTIONS, GET, POST"
        resp.headers["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST"
        resp.headers['Access-Control-Allow-Origin'] = "http://www.example.com"
        resp.headers['Access-Control-Allow-Headers'] = "*"
        return resp
    elif request.method == 'POST':
        reqBody = request.get_data(False)
        # For a real-world solution, you would load the data from reqBody
        # and send it to the model. Then return the response.
        resp = AMLResponse(reqBody, 200)
        resp.headers["Allow"] = "OPTIONS, GET, POST"
        resp.headers["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST"
        resp.headers['Access-Control-Allow-Origin'] = "http://www.example.com"
        resp.headers['Access-Control-Allow-Headers'] = "*"
        return resp
    elif request.method == 'OPTIONS':
        resp = AMLResponse("", 200)
        resp.headers["Allow"] = "OPTIONS, GET, POST"
        resp.headers["Access-Control-Allow-Methods"] = "OPTIONS, GET, POST"
        resp.headers['Access-Control-Allow-Origin'] = "http://www.example.com"
        resp.headers['Access-Control-Allow-Headers'] = "*"
        return resp
    else:
        return AMLResponse("bad request", 400)

Importante

A AMLResponse classe está no azureml.contrib namespace. As entidades neste namespace mudam frequentemente à medida que trabalhamos para melhorar o serviço. Qualquer coisa neste namespace deve ser considerada uma visualização que não é totalmente suportada pela Microsoft.

Se você precisar testar isso em seu ambiente de desenvolvimento local, poderá instalar os componentes usando o seguinte comando:

pip install azureml-contrib-services

Aviso

O Azure Machine Learning apenas encaminha solicitações POST e GET para os contêineres que executam o serviço de pontuação. Isso pode causar erros devido a navegadores que usam solicitações OPTIONS para solicitações CORS de pré-voo.

Carregar modelos registados

Existem duas formas de localizar modelos no script de entrada:

  • AZUREML_MODEL_DIR: Uma variável de ambiente que contém o caminho para o local do modelo
  • Model.get_model_path: Uma API que retorna o caminho para o arquivo de modelo usando o nome do modelo registrado

AZUREML_MODEL_DIR

AZUREML_MODEL_DIR é uma variável de ambiente criada durante a implantação do serviço. Pode utilizar esta variável de ambiente para encontrar a localização dos modelos implementados.

A tabela a seguir descreve o valor de AZUREML_MODEL_DIR dependendo do número de modelos implantados:

Implementação Valor da variável de ambiente
Modelo único O caminho para a pasta que contém o modelo.
Vários modelos O caminho para a pasta que contém todos os modelos. Os modelos estão localizados por nome e versão nesta pasta ($MODEL_NAME/$VERSION)

Durante o registro e a implantação do modelo, os modelos são colocados no caminho AZUREML_MODEL_DIR e seus nomes de arquivo originais são preservados.

Para obter o caminho para um arquivo de modelo em seu script de entrada, combine a variável de ambiente com o caminho do arquivo que você está procurando.

Exemplo de modelo único

# Example when the model is a file
model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'sklearn_regression_model.pkl')

# Example when the model is a folder containing a file
file_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'my_model_folder', 'sklearn_regression_model.pkl')

Exemplo de modelo múltiplo

Nesse cenário, dois modelos são registrados com o espaço de trabalho:

  • my_first_model: Contém um arquivo (my_first_model.pkl) e há apenas uma versão, 1
  • my_second_model: Contém um ficheiro (my_second_model.pkl) e existem duas versões, 1 e 2

Quando o serviço foi implantado, ambos os modelos são fornecidos na operação de implantação:

first_model = Model(ws, name="my_first_model", version=1)
second_model = Model(ws, name="my_second_model", version=2)
service = Model.deploy(ws, "myservice", [first_model, second_model], inference_config, deployment_config)

Na imagem do Docker que hospeda o serviço, a AZUREML_MODEL_DIR variável de ambiente contém o diretório onde os modelos estão localizados. Neste diretório, cada um dos modelos está localizado em um caminho de diretório de MODEL_NAME/VERSION. Onde MODEL_NAME é o nome do modelo registado e VERSION é a versão do modelo. Os arquivos que compõem o modelo registrado são armazenados nesses diretórios.

Neste exemplo, os caminhos seriam $AZUREML_MODEL_DIR/my_first_model/1/my_first_model.pkl e $AZUREML_MODEL_DIR/my_second_model/2/my_second_model.pkl.

# Example when the model is a file, and the deployment contains multiple models
first_model_name = 'my_first_model'
first_model_version = '1'
first_model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), first_model_name, first_model_version, 'my_first_model.pkl')
second_model_name = 'my_second_model'
second_model_version = '2'
second_model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), second_model_name, second_model_version, 'my_second_model.pkl')

get_model_path

Quando regista um modelo, fornece um nome de modelo que é utilizado para gerir o modelo no registo. Utilize este nome com o método Model.get_model_path() para obter o caminho do ficheiro do modelo ou dos ficheiros no sistema de ficheiros local. Se você registrar uma pasta ou uma coleção de arquivos, essa API retornará o caminho do diretório que contém esses arquivos.

Quando regista um modelo, dá-lhe um nome. O nome corresponde ao local onde o modelo é colocado, localmente ou durante a implantação do serviço.

Exemplos específicos do quadro

Consulte os seguintes artigos para obter mais exemplos de scripts de entrada para casos de uso específicos de aprendizado de máquina: