Vytváření pokročilých zaváděcích skriptů

PLATÍ PRO:Python SDK azureml v1

Tento článek vysvětluje, jak psát vstupní skripty pro specializované případy použití.

Požadavky

Tento článek předpokládá, že už máte natrénovaný model strojového učení, který chcete nasadit pomocí služby Azure Machine Učení. Další informace o nasazení modelu najdete v tématu Nasazení modelů strojového učení do Azure.

Automatické generování schématu Swaggeru

Pokud chcete automaticky vygenerovat schéma pro webovou službu, zadejte v konstruktoru ukázku vstupu a/nebo výstupu pro jeden z definovaných objektů typu. Typ a ukázka se používají k automatickému vytvoření schématu. Azure Machine Učení pak během nasazování vytvoří specifikaci OpenAPI (dříve specifikaci Swaggeru).

Upozorňující

Pro ukázkový vstup nebo výstup nesmíte používat citlivá ani soukromá data. Stránka Swagger pro odvozování hostované službou AML zveřejňuje ukázková data.

V současné době se podporují tyto typy:

  • pandas
  • numpy
  • pyspark
  • Standardní objekt Pythonu

Pokud chcete použít generování schématu, zahrňte do souboru závislostí opensourcový inference-schema balíček verze 1.1.0 nebo vyšší. Další informace o tomto balíčku najdete v tématu OdvozováníSchema na GitHubu. Aby bylo možné vygenerovat shodný Swagger pro automatizovanou spotřebu webových služeb, musí mít funkce run() skriptu bodování tvar rozhraní API:

  • První parametr typu StandardPythonParameterTypes názvem Vstupy a vnořený
  • Volitelný druhý parametr typu StandardPythonParameterTypes názvem GlobalParameters
  • Vrátí slovník typu StandardPythonParameterTypes názvem Výsledky a vnořený.

Definujte vstupní a výstupní ukázkové formáty v input_sample proměnných a output_sample které představují formáty požadavků a odpovědí pro webovou službu. Tyto ukázky použijte ve vstupních a výstupních dekorátorech run() funkce. Následující příklad scikit-learn používá generování schématu.

Koncový bod kompatibilní s Power BI

Následující příklad ukazuje, jak definovat obrazec rozhraní API podle předchozí instrukce. Tato metoda je podporovaná pro využívání nasazené webové služby z 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

Tip

Návratovou hodnotou skriptu může být libovolný objekt Pythonu, který je serializovatelný pro JSON. Pokud například váš model vrátí datový rámec Pandas, který obsahuje více sloupců, můžete použít výstupní dekorátor podobný následujícímu kódu:

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

Binární data (to znamená image)

Pokud váš model přijímá binární data, jako je image, musíte upravit soubor score.py použitý pro vaše nasazení tak, aby přijímal nezpracované požadavky HTTP. Pokud chcete přijmout nezpracovaná data, použijte AMLRequest třídu ve vstupním skriptu a přidejte @rawhttp dekorátor do run() funkce.

Tady je příklad score.py , který přijímá binární data:

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)

Důležité

Třída AMLRequest je v azureml.contrib oboru názvů. Entity v tomto oboru názvů se často mění při vylepšování služby. Cokoli v tomto oboru názvů by mělo být považováno za náhled, který Microsoft plně nepodporuje.

Pokud to potřebujete otestovat v místním vývojovém prostředí, můžete komponenty nainstalovat pomocí následujícího příkazu:

pip install azureml-contrib-services

Poznámka:

500 se nedoporučuje jako vlastní stavový kód, protože na straně azureml-fe se stavový kód přepíše na 502.

  • Stavový kód se předává prostřednictvím azureml-fe a pak se odešle klientovi.
  • Azureml-fe přepíše pouze 500 vrácených ze strany modelu na 502, klient obdrží 502.
  • Pokud ale samotná azureml-fe vrátí hodnotu 500, klientská strana stále obdrží hodnotu 500.

Třída AMLRequest umožňuje přístup pouze k nezpracovaným publikovaným datům v souboru score.py , neexistuje žádná komponenta na straně klienta. Z klienta publikujete data jako obvykle. Například následující kód Pythonu načte soubor obrázku a publikuje data:

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)

Sdílení prostředků mezi zdroji (CORS)

Sdílení prostředků mezi zdroji je způsob, jak umožnit vyžádání prostředků na webové stránce z jiné domény. CORS funguje prostřednictvím hlaviček HTTP odeslaných s požadavkem klienta a vráceným odpovědí služby. Další informace o CORS a platných hlavičkách najdete v tématu Sdílení zdrojů mezi zdroji na Wikipedii.

Pokud chcete nakonfigurovat nasazení modelu tak, aby podporovalo CORS, použijte AMLResponse třídu ve vstupním skriptu. Tato třída umožňuje nastavit hlavičky objektu odpovědi.

Následující příklad nastaví hlavičku Access-Control-Allow-Origin odpovědi ze vstupního skriptu:

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)

Důležité

Třída AMLResponse je v azureml.contrib oboru názvů. Entity v tomto oboru názvů se často mění při vylepšování služby. Cokoli v tomto oboru názvů by mělo být považováno za náhled, který Microsoft plně nepodporuje.

Pokud to potřebujete otestovat v místním vývojovém prostředí, můžete komponenty nainstalovat pomocí následujícího příkazu:

pip install azureml-contrib-services

Upozorňující

Azure Machine Učení směruje požadavky POST a GET pouze na kontejnery, na kterých běží služba vyhodnocování. To může způsobit chyby způsobené prohlížeči, které používají požadavky OPTIONS na požadavky CORS před testovací verzí.

Načtení registrovaných modelů

V zaváděcím skriptu je možné vyhledat modely dvěma způsoby:

  • AZUREML_MODEL_DIR: Proměnná prostředí obsahující cestu k umístění modelu
  • Model.get_model_path: Rozhraní API, které vrací cestu k souboru modelu pomocí registrovaného názvu modelu

AZUREML_MODEL_DIR

AZUREML_MODEL_DIR je proměnná prostředí vytvořená během nasazování služby. Pomocí této proměnné prostředí můžete zjistit umístění nasazených modelů.

Následující tabulka popisuje hodnotu AZUREML_MODEL_DIR v závislosti na počtu nasazených modelů:

Nasazení Hodnota proměnné prostředí
Jeden model Cesta ke složce obsahující model.
Více modelů Cesta ke složce obsahující všechny modely. Modely jsou umístěny podle názvu a verze v této složce ($MODEL_NAME/$VERSION)

Během registrace a nasazení modelu se modely umístí do cesty AZUREML_MODEL_DIR a jejich původní názvy souborů se zachovají.

Pokud chcete získat cestu k souboru modelu ve vstupním skriptu, zkombinujte proměnnou prostředí s cestou k souboru, kterou hledáte.

Příklad jednoho modelu

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

Příklad více modelů

V tomto scénáři jsou v pracovním prostoru zaregistrované dva modely:

  • my_first_model: Obsahuje jeden soubor (my_first_model.pkl) a existuje pouze jedna verze. 1
  • my_second_model: Obsahuje jeden soubor (my_second_model.pkl) a existují dvě verze a 12

Po nasazení služby jsou v operaci nasazení k dispozici oba modely:

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)

V imagi Dockeru, která hostuje službu, obsahuje proměnná prostředí adresář, AZUREML_MODEL_DIR ve kterém se nacházejí modely. V tomto adresáři se každý z modelů nachází v cestě k MODEL_NAME/VERSIONadresáři . Kde MODEL_NAME je název registrovaného modelu a VERSION jedná se o verzi modelu. Soubory, které tvoří registrovaný model, jsou uloženy v těchto adresářích.

V tomto příkladu by cesty byly $AZUREML_MODEL_DIR/my_first_model/1/my_first_model.pkl a $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

Při registraci modelu zadáte název modelu, který slouží ke správě modelu v registru. Pomocí tohoto názvu a metody Model.get_model_path() můžete načíst cestu k souborům modelu v místním systému souborů. Pokud zaregistrujete složku nebo kolekci souborů, vrátí toto rozhraní API cestu k adresáři, který tyto soubory obsahuje.

Při registraci modelu ho pojmenujete. Název odpovídá umístění modelu místně nebo během nasazení služby.

Příklady specifické pro architekturu

Další příklady vstupních skriptů pro konkrétní případy použití strojového učení najdete v následujících článcích: