Dela via


Avancerad startskriptredigering

GÄLLER FÖR: Python SDK azureml v1

Den här artikeln beskriver hur du skriver inmatningsskript för specialiserade användningsfall.

Förutsättningar

Den här artikeln förutsätter att du redan har en tränad maskininlärningsmodell som du tänker distribuera med Azure Mašinsko učenje. Mer information om modelldistribution finns i Distribuera maskininlärningsmodeller till Azure.

Generera ett Swagger-schema automatiskt

Om du vill generera ett schema för webbtjänsten automatiskt anger du ett exempel på indata och/eller utdata i konstruktorn för ett av de definierade typobjekten. Typen och exemplet används för att automatiskt skapa schemat. Azure Mašinsko učenje skapar sedan en OpenAPI-specifikation (tidigare Swagger-specifikation) för webbtjänsten under distributionen.

Varning

Du får inte använda känsliga eller privata data för exempelindata eller utdata. Swagger-sidan för AML-värdbaserad slutsatsdragning exponerar exempeldata.

Dessa typer stöds för närvarande:

  • pandas
  • numpy
  • pyspark
  • Python-standardobjekt

Om du vill använda schemagenerering inkluderar du paketversion 1.1.0 med öppen källkod inference-schema eller senare i din beroendefil. Mer information om det här paketet finns i InferenceSchema på GitHub. För att generera kompatibel Swagger för automatiserad webbtjänstförbrukning måste funktionen scoring script run() ha API-formen:

  • En första parameter av typen StandardPythonParameterType, med namnet Indata och kapslad
  • En valfri andra parameter av typen StandardPythonParameterType, med namnet GlobalParameters
  • Returnera en ordlista av typen StandardPythonParameterType, med namnet Resultat och kapslad

Definiera indata- och utdataexempelformaten i variablerna input_sample och output_sample som representerar formaten för begäran och svar för webbtjänsten. Använd dessa exempel i funktionsdekoratörerna för indata och utdata i run() funktionen. I följande scikit-learn-exempel används schemagenerering.

Power BI-kompatibel slutpunkt

I följande exempel visas hur du definierar API-form enligt föregående instruktion. Den här metoden stöds för användning av den distribuerade webbtjänsten från 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

Dricks

Returvärdet från skriptet kan vara alla Python-objekt som kan serialiseras till JSON. Om din modell till exempel returnerar en Pandas-dataram som innehåller flera kolumner kan du använda en utdatadekoratör som liknar följande kod:

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

Binära data (det vill: bild)

Om din modell accepterar binära data, till exempel en bild, måste du ändra den score.py fil som används för distributionen för att acceptera råa HTTP-begäranden. Om du vill acceptera rådata använder du AMLRequest klassen i ditt postskript och lägger till dekoratören @rawhttp i run() funktionen.

Här är ett exempel på en score.py som accepterar binära 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)

Viktigt!

Klassen AMLRequest finns i azureml.contrib namnområdet. Entiteter i det här namnområdet ändras ofta när vi arbetar för att förbättra tjänsten. Allt i det här namnområdet bör betraktas som en förhandsversion som inte stöds fullt ut av Microsoft.

Om du behöver testa detta i din lokala utvecklingsmiljö kan du installera komponenterna med hjälp av följande kommando:

pip install azureml-contrib-services

Kommentar

500 rekommenderas inte som anpassad statuskod, eftersom statuskoden skrivs om till 502 på azureml-fe-sidan.

  • Statuskoden skickas via azureml-fe och skickas sedan till klienten.
  • Azureml-fe skriver bara om de 500 som returneras från modellsidan till 502, klienten får 502.
  • Men om själva azureml-fe returnerar 500 får klientsidan fortfarande 500.

Med AMLRequest klassen kan du bara komma åt rådata i filen score.py , det finns ingen komponent på klientsidan. Från en klient publicerar du data som vanligt. Följande Python-kod läser till exempel en bildfil och publicerar 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)

Resursdelning för korsande ursprung (CORS)

Resursdelning mellan ursprung är ett sätt att tillåta att resurser på en webbsida begärs från en annan domän. CORS fungerar via HTTP-huvuden som skickas med klientbegäran och returneras med tjänstsvaret. Mer information om CORS och giltiga rubriker finns i Resursdelning mellan ursprung i Wikipedia.

Om du vill konfigurera modelldistributionen så att den AMLResponse stöder CORS använder du klassen i ditt inmatningsskript. Med den här klassen kan du ange rubrikerna för svarsobjektet.

I följande exempel anges Access-Control-Allow-Origin rubriken för svaret från postskriptet:

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)

Viktigt!

Klassen AMLResponse finns i azureml.contrib namnområdet. Entiteter i det här namnområdet ändras ofta när vi arbetar för att förbättra tjänsten. Allt i det här namnområdet bör betraktas som en förhandsversion som inte stöds fullt ut av Microsoft.

Om du behöver testa detta i din lokala utvecklingsmiljö kan du installera komponenterna med hjälp av följande kommando:

pip install azureml-contrib-services

Varning

Azure Mašinsko učenje dirigerar endast POST- och GET-begäranden till containrar som kör bedömningstjänsten. Detta kan orsaka fel på grund av webbläsare som använder OPTIONS-begäranden för cors-begäranden före flygning.

Läsa in registrerade modeller

Det finns två sätt att hitta modeller i ditt startskript:

  • AZUREML_MODEL_DIR: En miljövariabel som innehåller sökvägen till modellplatsen
  • Model.get_model_path: Ett API som returnerar sökvägen till modellfilen med det registrerade modellnamnet

AZUREML_MODEL_DIR

AZUREML_MODEL_DIR är en miljövariabel som skapas under tjänstdistributionen. Du kan använda den här miljövariabeln för att hitta platsen för de distribuerade modellerna.

I följande tabell beskrivs värdet AZUREML_MODEL_DIR för beroende på antalet distribuerade modeller:

Distribution Miljövariabelvärde
Enskild modell Sökvägen till mappen som innehåller modellen.
Flera modeller Sökvägen till mappen som innehåller alla modeller. Modeller finns efter namn och version i den här mappen ($MODEL_NAME/$VERSION)

Under modellregistrering och distribution placeras modeller i den AZUREML_MODEL_DIR sökvägen och deras ursprungliga filnamn bevaras.

Om du vill hämta sökvägen till en modellfil i ditt inmatningsskript kombinerar du miljövariabeln med den filsökväg du letar efter.

Exempel på en modell

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

Exempel på flera modeller

I det här scenariot registreras två modeller med arbetsytan:

  • my_first_model: Innehåller en fil (my_first_model.pkl) och det finns bara en version, 1
  • my_second_model: Innehåller en fil (my_second_model.pkl) och det finns två versioner, 1 och 2

När tjänsten distribuerades tillhandahålls båda modellerna i distributionsåtgärden:

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)

I Docker-avbildningen som är värd för tjänsten AZUREML_MODEL_DIR innehåller miljövariabeln katalogen där modellerna finns. I den här katalogen finns var och en av modellerna i en katalogsökväg för MODEL_NAME/VERSION. Var MODEL_NAME är namnet på den registrerade modellen och VERSION är modellens version. Filerna som utgör den registrerade modellen lagras i dessa kataloger.

I det här exemplet skulle sökvägarna vara $AZUREML_MODEL_DIR/my_first_model/1/my_first_model.pkl och $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

När du registrerar en modell anger du ett modellnamn som används för att hantera modellen i registret. Du använder det här namnet med metoden Model.get_model_path() för att hämta sökvägen till modellfilen eller filerna i det lokala filsystemet. Om du registrerar en mapp eller en samling filer returnerar det här API:et sökvägen till katalogen som innehåller filerna.

När du registrerar en modell ger du den ett namn. Namnet motsvarar var modellen placeras, antingen lokalt eller under tjänstdistributionen.

Ramverksspecifika exempel

I följande artiklar finns fler exempel på inmatningsskript för specifika användningsfall för maskininlärning: