Geavanceerde scriptinvoer ontwerpen

VAN TOEPASSING OP: Python SDK azureml v1

In dit artikel wordt uitgelegd hoe u invoerscripts schrijft voor gespecialiseerde use cases.

Vereisten

In dit artikel wordt ervan uitgegaan dat u al een getraind machine learning-model hebt dat u wilt implementeren met Azure Machine Learning. Zie Machine Learning-modellen implementeren in Azure voor meer informatie over modelimplementatie.

Automatisch een Swagger-schema genereren

Als u automatisch een schema voor uw webservice wilt genereren, geeft u een voorbeeld van de invoer en/of uitvoer in de constructor op voor een van de gedefinieerde typeobjecten. Het type en het voorbeeld worden gebruikt om het schema automatisch te maken. Azure Machine Learning maakt vervolgens een OpenAPI-specificatie (voorheen Swagger-specificatie) voor de webservice tijdens de implementatie.

Waarschuwing

U mag geen gevoelige of persoonlijke gegevens gebruiken voor voorbeeldinvoer of uitvoer. De Swagger-pagina voor AML-gehoste deductie toont de voorbeeldgegevens.

Deze typen worden momenteel ondersteund:

  • pandas
  • numpy
  • pyspark
  • Standaard Python-object

Als u schemageneratie wilt gebruiken, moet u het opensource-pakket inference-schema versie 1.1.0 of hoger opnemen in uw afhankelijkhedenbestand. Zie InferenceSchema op GitHub voor meer informatie over dit pakket. Als u conform Swagger wilt genereren voor geautomatiseerd webserviceverbruik, moet de functie scorescriptuitvoering() de API-vorm hebben van:

  • Een eerste parameter van het typeStandardPythonParameterType, invoeren geneste
  • Een optionele tweede parameter van het type StandardPythonParameterType, genaamd GlobalParameters
  • Retourneert een woordenlijst van het type StandardPythonParameterType, met de naam Resultaten en genest

Definieer de indelingen voor invoer- en uitvoervoorbeelden in de input_sample en output_sample variabelen, die de aanvraag- en antwoordindelingen voor de webservice vertegenwoordigen. Gebruik deze voorbeelden in de decorators voor invoer- en uitvoerfuncties voor de run() functie. In het volgende scikit-learn-voorbeeld wordt gebruikgemaakt van schemageneratie.

Compatibel power BI-eindpunt

In het volgende voorbeeld ziet u hoe u een API-shape definieert volgens de voorgaande instructie. Deze methode wordt ondersteund voor het gebruik van de geïmplementeerde webservice vanuit 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

De retourwaarde van het script kan elk Python-object zijn dat serialiseerbaar is voor JSON. Als uw model bijvoorbeeld een Pandas-dataframe retourneert dat meerdere kolommen bevat, kunt u een uitvoer-decorator gebruiken die vergelijkbaar is met de volgende code:

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

Binaire (dat wil gezegd, afbeeldingsgegevens)

Als uw model binaire gegevens accepteert, zoals een afbeelding, moet u het score.py-bestand dat voor uw implementatie wordt gebruikt, wijzigen om onbewerkte HTTP-aanvragen te accepteren. Als u onbewerkte gegevens wilt accepteren, gebruikt u de AMLRequest klasse in uw invoerscript en voegt u de @rawhttp decorator toe aan de run() functie.

Hier volgt een voorbeeld van een score.py bestand dat binaire gegevens accepteert:

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)

Belangrijk

De AMLRequest klasse bevindt zich in de azureml.contrib naamruimte. Entiteiten in deze naamruimte veranderen regelmatig naarmate we de service verbeteren. Alles in deze naamruimte moet worden beschouwd als een voorbeeld dat niet volledig wordt ondersteund door Microsoft.

Als u dit wilt testen in uw lokale ontwikkelomgeving, kunt u de onderdelen installeren met behulp van de volgende opdracht:

pip install azureml-contrib-services

Notitie

500 wordt niet aanbevolen als een aangepaste statuscode, zoals bij azureml-fe, de statuscode wordt herschreven naar 502.

  • De statuscode wordt doorgegeven via azureml-fe en vervolgens verzonden naar de client.
  • De azureml-fe herschrijft alleen de 500 die van de modelzijde is geretourneerd naar 502, de client ontvangt 502.
  • Maar als de azureml-fe zelf 500 retourneert, ontvangt de clientzijde nog steeds 500.

Met AMLRequest de klasse hebt u alleen toegang tot de onbewerkte geposte gegevens in het score.py-bestand . Er is geen onderdeel aan de clientzijde. Vanaf een client plaatst u gegevens als normaal. De volgende Python-code leest bijvoorbeeld een afbeeldingsbestand en plaatst de gegevens:

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)

CORS (Cross-Origin Resource Sharing, cross-origin-resource delen)

Cross-origin resource sharing is een manier om resources op een webpagina te laten aanvragen vanuit een ander domein. CORS werkt via HTTP-headers die worden verzonden met de clientaanvraag en geretourneerd met het serviceantwoord. Zie Cross-origin resource sharing in Wikipedia voor meer informatie over CORS en geldige headers.

Als u uw modelimplementatie wilt configureren ter ondersteuning van CORS, gebruikt u de AMLResponse klasse in uw invoerscript. Met deze klasse kunt u de headers voor het antwoordobject instellen.

In het volgende voorbeeld wordt de Access-Control-Allow-Origin header voor het antwoord van het invoerscript ingesteld:

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)

Belangrijk

De AMLResponse klasse bevindt zich in de azureml.contrib naamruimte. Entiteiten in deze naamruimte veranderen regelmatig naarmate we de service verbeteren. Alles in deze naamruimte moet worden beschouwd als een voorbeeld dat niet volledig wordt ondersteund door Microsoft.

Als u dit wilt testen in uw lokale ontwikkelomgeving, kunt u de onderdelen installeren met behulp van de volgende opdracht:

pip install azureml-contrib-services

Waarschuwing

Azure Machine Learning routeert alleen POST- en GET-aanvragen naar de containers waarop de scoreservice wordt uitgevoerd. Dit kan fouten veroorzaken vanwege browsers die OPTIONS-aanvragen gebruiken voor CORS-aanvragen vóór de vlucht.

Geregistreerde modellen laden

Er zijn twee manieren om modellen in uw invoerscript te lokaliseren:

  • AZUREML_MODEL_DIR: Een omgevingsvariabele met het pad naar de modellocatie
  • Model.get_model_path: Een API die het pad naar het modelbestand retourneert met behulp van de geregistreerde modelnaam

AZUREML_MODEL_DIR

AZUREML_MODEL_DIR is een omgevingsvariabele die is gemaakt tijdens de service-implementatie. U kunt deze omgevingsvariabele gebruiken om de locatie van de geïmplementeerde modellen te vinden.

In de volgende tabel wordt de waarde beschreven, AZUREML_MODEL_DIR afhankelijk van het aantal geïmplementeerde modellen:

Implementatie Waarde van omgevingsvariabele
Enkel model Het pad naar de map met het model.
Meerdere modellen Het pad naar de map met alle modellen. Modellen bevinden zich op naam en versie in deze map ($MODEL_NAME/$VERSION)

Tijdens modelregistratie en implementatie worden modellen in het AZUREML_MODEL_DIR pad geplaatst en blijven de oorspronkelijke bestandsnamen behouden.

Als u het pad naar een modelbestand in uw invoerscript wilt ophalen, combineert u de omgevingsvariabele met het bestandspad dat u zoekt.

Voorbeeld van één model

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

Voorbeeld van meerdere modellen

In dit scenario worden twee modellen geregistreerd bij de werkruimte:

  • my_first_model: Bevat één bestand (my_first_model.pkl) en er is slechts één versie, 1
  • my_second_model: Bevat één bestand (my_second_model.pkl) en er zijn twee versies, 1 en 2

Wanneer de service is geïmplementeerd, worden beide modellen geleverd in de implementatiebewerking:

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)

In de Docker-installatiekopieën die als host fungeert voor de service, bevat de AZUREML_MODEL_DIR omgevingsvariabele de map waarin de modellen zich bevinden. In deze map bevindt elk van de modellen zich in een mappad van MODEL_NAME/VERSION. Waar MODEL_NAME is de naam van het geregistreerde model en VERSION is de versie van het model. De bestanden waaruit het geregistreerde model bestaat, worden opgeslagen in deze mappen.

In dit voorbeeld zijn de paden en $AZUREML_MODEL_DIR/my_first_model/1/my_first_model.pkl$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

Wanneer u een model registreert, geeft u een modelnaam op die wordt gebruikt voor het beheren van het model in het register. U gebruikt deze naam met de methode Model.get_model_path() om het pad van het modelbestand of de modelbestanden in het lokale bestandssysteem op te halen. Als u een map of een verzameling bestanden registreert, retourneert deze API het pad van de map die deze bestanden bevat.

Wanneer u een model registreert, geeft u het een naam. De naam komt overeen met waar het model wordt geplaatst, lokaal of tijdens de implementatie van de service.

Frameworkspecifieke voorbeelden

Zie de volgende artikelen voor meer voorbeelden van invoerscripts voor specifieke machine learning-use cases: