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 che sia già disponibile un modello di Machine Learning con training che si intende distribuire con Azure Machine Learning. Per altre informazioni sulla distribuzione del modello, vedere Come distribuire e dove.

Si genera automaticamente uno schema di Swagger

Per generare automaticamente uno schema per il servizio Web, fornire un esempio dell'input e/o dell'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 (Swagger) per il servizio Web durante la distribuzione.

Avviso

Non è necessario 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 https://github.com/Azure/InferenceSchema. Per generare swagger conforme per l'utilizzo automatizzato del servizio Web, la funzione script di assegnazione dei punteggi deve avere una forma API:

  • 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 input_sample variabili e output_sample , che rappresentano i formati di richiesta e risposta per il servizio Web. Usare questi esempi negli elementi Decorator della funzione di input e output nella run() funzione . Nell'esempio scikit-learn seguente viene usata la generazione dello schema.

Endpoint compatibile con Power BI

Nell'esempio seguente viene illustrato come definire la forma API in base all'istruzione precedente. Questo metodo è supportato per l'utilizzo del servizio Web distribuito da Power BI. Altre informazioni su come usare il servizio Web 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 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 image)

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

Ecco un esempio di che score.py 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 quando si lavora per migliorare il servizio. Qualsiasi elemento in questo spazio dei nomi deve essere considerato un'anteprima non completamente supportata da Microsoft.

Se è necessario testarlo 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 verrà passato tramite azureml-fe e quindi inviato al client.
  • Azureml-fe riscriverà solo i 500 restituiti dal lato modello in modo che siano 502, il client riceverà 502.
  • Tuttavia, se azureml-fe stesso restituisce 500, il lato client riceverà comunque 500.

La AMLRequest classe consente solo di accedere ai dati pubblicati non elaborati nel score.py, non esiste alcun componente lato client. Da un client si pubblicano i dati come di consueto. Ad esempio, il codice Python seguente legge un file di immagine e pubblica 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 condivisione di risorse tra le origini è un modo per consentire la richiesta di risorse in una pagina Web da un altro dominio. CORS funziona tramite intestazioni HTTP inviate con la richiesta client e restituite con la risposta del servizio. Per altre informazioni su CORS e intestazioni valide, vedere Condivisione di risorse tra le origini in Wikipedia.

Per configurare la distribuzione del modello per supportare CORS, usare la AMLResponse classe 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 dallo 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 quando si lavora per migliorare il servizio. Qualsiasi elemento in questo spazio dei nomi deve essere considerato un'anteprima non completamente supportata da Microsoft.

Se è necessario testarlo 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. Ciò può causare errori dovuti ai browser che usano richieste OPTIONS per le richieste CORS pre-in anteprima.

Caricare i modelli registrati

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

  • AZUREML_MODEL_DIR: una variabile di ambiente contenente il percorso della posizione del modello.
  • Model.get_model_path: un'API che restituisce il percorso del file di 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.
Più modelli Percorso della cartella contenente tutti i modelli. I modelli si trovano in base al nome e alla 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 che si sta cercando.

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 più modelli

In questo scenario, due modelli vengono registrati 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.

Quando il servizio è stato distribuito, entrambi i modelli vengono forniti 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 AZUREML_MODEL_DIR variabile di ambiente contiene la directory in cui si trovano i modelli. In questa directory, ognuno dei modelli si trova in un percorso di directory di MODEL_NAME/VERSION. Dove MODEL_NAME è il nome del modello registrato ed 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, assegnargli un nome. Il nome corrisponde alla posizione in cui viene inserito il modello, in locale o durante la distribuzione del servizio.

Esempi specifici del framework

Di seguito sono riportati altri esempi di script di immissione per casi d'uso specifici di Machine Learning:

Passaggi successivi