Condividi tramite


Creazione avanzata di script di immissione

SI APPLICA A:Python SDK azureml v1

Questo articolo illustra come scrivere script di immissione per casi d'uso specializzati.

Prerequisiti

Questo articolo presuppone la presenza di un modello di Machine Learning sottoposto a training da distribuire con Azure Machine Learning. Per altre informazioni sulla distribuzione dei modelli, vedere Distribuire modelli di Machine Learning in Azure.

Si genera automaticamente uno schema di Swagger

Per generare automaticamente uno schema per il servizio Web, specificare un esempio di input e/o output nel costruttore per uno degli oggetti di tipo definiti. Il tipo e l'esempio vengono usati per creare automaticamente lo schema. Azure Machine Learning crea quindi una specifica OpenAPI (in precedenza specifica Swagger) per il servizio Web durante la distribuzione.

Avviso

Non usare dati sensibili o privati per l'input o l'output di esempio. La pagina Swagger per l'inferenza ospitata in AML espone i dati di esempio.

Questi tipi sono attualmente supportati:

  • pandas
  • numpy
  • pyspark
  • Oggetto Python standard

Per usare la generazione dello schema, includere il pacchetto open source inference-schema versione 1.1.0 o successiva nel file delle dipendenze. Per altre informazioni su questo pacchetto, vedere InferenceSchema in GitHub. Per generare Swagger conforme per l'utilizzo automatizzato del servizio Web, la funzione run() degli script di assegnazione dei punteggi deve avere una forma API di:

  • Primo parametro di tipo StandardPythonParameterType, denominato Input e annidato
  • Secondo parametro facoltativo di tipo StandardPythonParameterType, denominato GlobalParameters
  • Restituisce un dizionario di tipo StandardPythonParameterType, denominato Results e annidato

Definire i formati di esempio di input e output nelle variabili input_sample e output_sample, che rappresentano i formati di richiesta e risposta per il servizio Web. Usare questi esempi negli elementi Decorator di funzione di input e output nella funzione run(). Nell'esempio scikit-learn seguente viene usata la generazione dello schema.

Endpoint compatibile con Power BI

L'esempio seguente illustra come definire la forma API in base all'istruzione precedente. Questo metodo è supportato per l'utilizzo del servizio Web distribuito da 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

Suggerimento

Il valore restituito dallo script può essere un qualsiasi oggetto Python serializzabile in JSON. Ad esempio, se il modello restituisce un dataframe Pandas contenente più colonne, è possibile usare un elemento Decorator di output simile al codice seguente:

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

Dati binari (ovvero immagine)

Se il modello accetta dati binari, ad esempio un'immagine, è necessario modificare il file score.py usato per la distribuzione per accettare richieste HTTP non elaborate. Per accettare dati non elaborati, usare la classe AMLRequest nello script di immissione e aggiungere l'elemento Decorator @rawhttp alla funzione run().

Ecco un esempio di un file score.py che accetta dati binari:

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

La classe AMLRequest si trova nello spazio dei nomi azureml.contrib. Le entità in questo spazio dei nomi cambiano di frequente poiché Microsoft è impegnata a migliorare il servizio. Qualsiasi elemento in questo spazio dei nomi deve essere pertanto considerato come anteprima non completamente supportata da Microsoft.

Se è necessario eseguire un test nell'ambiente di sviluppo locale, è possibile installare i componenti usando il comando seguente:

pip install azureml-contrib-services

Nota

500 non è consigliato come codice di stato personalizzato, come sul lato azureml-fe, il codice di stato verrà riscritto in 502.

  • Il codice di stato viene passato tramite azureml-fe, quindi inviato al client.
  • Azureml-fe riscrive solo i 500 restituiti dal lato del modello per essere 502, il client riceve 502.
  • Tuttavia, se azureml-fe restituisce 500, il lato client riceve comunque 500.

La AMLRequest classe consente solo di accedere ai dati pubblicati non elaborati nel file score.py , non esiste alcun componente lato client. Da un client è possibile inserire i dati come al solito. Ad esempio, il codice Python seguente legge un file di immagine e inserisce i dati:

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)

Condivisione di risorse tra le origini (CORS)

La funzionalità Condivisione di risorse tra le origini (CORS) rappresenta un modo per abilitare la richiesta di un numero limitato di risorse in una pagina Web da parte di un altro dominio. Per funzionare, CORS usa intestazioni HTTP inviate con la richiesta del client e restituite con la risposta del servizio. Per altre informazioni su CORS e sulle intestazioni valide, vedere la voce Cross-origin resource sharing su Wikipedia.

Per configurare la distribuzione modello per supportare CORS, usare la classe AMLResponse nello script di immissione. Questa classe consente di impostare le intestazioni sull'oggetto risposta.

Nell'esempio seguente viene impostata l'intestazione Access-Control-Allow-Origin per la risposta dello script di immissione:

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

La classe AMLResponse si trova nello spazio dei nomi azureml.contrib. Le entità in questo spazio dei nomi cambiano di frequente poiché Microsoft è impegnata a migliorare il servizio. Qualsiasi elemento in questo spazio dei nomi deve essere pertanto considerato come anteprima non completamente supportata da Microsoft.

Se è necessario eseguire un test nell'ambiente di sviluppo locale, è possibile installare i componenti usando il comando seguente:

pip install azureml-contrib-services

Avviso

Azure Machine Learning instrada solo le richieste POST e GET ai contenitori che eseguono il servizio di assegnazione dei punteggi. Questo può causare errori dovuti a browser che usano richieste OPTIONS per richieste CORS preliminari.

Caricare i modelli registrati

Sono disponibili due modalità per individuare i modelli nello script di immissione:

  • AZUREML_MODEL_DIR: variabile di ambiente contenente il percorso del modello
  • Model.get_model_path: API che restituisce il percorso del file del modello usando il nome del modello registrato

AZUREML_MODEL_DIR

AZUREML_MODEL_DIR è una variabile di ambiente creata durante la distribuzione del servizio. È possibile usare questa variabile di ambiente per trovare il percorso dei modelli distribuiti.

La tabella seguente descrive il valore di AZUREML_MODEL_DIR a seconda del numero di modelli distribuiti:

Distribuzione Valore della variabile di ambiente
Modello singolo Percorso della cartella contenente il modello.
Modelli multipli Percorso della cartella contenente tutti i modelli. I modelli sono ordinati per nome e versione in questa cartella ($MODEL_NAME/$VERSION).

Durante la registrazione e la distribuzione del modello, i modelli vengono inseriti nel percorso AZUREML_MODEL_DIR e i relativi nomi file originali vengono mantenuti.

Per ottenere il percorso di un file di modello nello script di immissione, combinare la variabile di ambiente con il percorso del file desiderato.

Esempio di modello singolo

# 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')

Esempio di modello multiplo

In questo scenario vengono registrati due modelli nell'area di lavoro:

  • my_first_model: contiene un file (my_first_model.pkl) e c'è una sola versione, 1
  • my_second_model: contiene un file (my_second_model.pkl) e sono disponibili due versioni 1 e 2

Dopo la distribuzione del servizio, vengono forniti entrambi i modelli nell'operazione di distribuzione:

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)

Nell'immagine Docker che ospita il servizio la variabile di ambiente AZUREML_MODEL_DIR contiene la directory in cui si trovano i modelli. In questa directory ogni modello si trova in un percorso di directory di MODEL_NAME/VERSION. Dove MODEL_NAME è il nome del modello registrato e VERSION è la versione del modello. I file che costituiscono il modello registrato vengono archiviati in queste directory.

In questo esempio i percorsi saranno $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 si registra un modello, specificare un nome del modello usato per la gestione del modello nel Registro di sistema. Questo nome viene usato con il metodo Model.get_model_path() per recuperare il percorso del file o dei file del modello nel file system locale. Se si registra una cartella o una raccolta di file, questa API restituisce il percorso della directory che contiene tali file.

Quando si registra un modello, è necessario assegnargli un nome. Il nome corrisponde alla posizione in cui si trova il modello, ovvero in locale o durante la distribuzione del servizio.

Esempi specifici in base al framework

Per altri esempi di script di immissione per casi d'uso specifici di Machine Learning, vedere gli articoli seguenti: