Udostępnij za pośrednictwem


Tworzenie zaawansowanego skryptu wejściowego

DOTYCZY: Zestaw SDK języka Python azureml w wersji 1

W tym artykule wyjaśniono, jak pisać skrypty wejściowe dla wyspecjalizowanych przypadków użycia.

Wymagania wstępne

W tym artykule założono, że masz już wytrenowany model uczenia maszynowego, który zamierzasz wdrożyć za pomocą usługi Azure Machine Edukacja. Aby dowiedzieć się więcej na temat wdrażania modelu, zobacz Wdrażanie modeli uczenia maszynowego na platformie Azure.

Automatyczne generowanie schematu struktury Swagger

Aby automatycznie wygenerować schemat dla usługi internetowej, podaj próbkę danych wejściowych i/lub wyjściowych w konstruktorze dla jednego ze zdefiniowanych obiektów typu. Typ i przykład służą do automatycznego tworzenia schematu. Usługa Azure Machine Edukacja następnie tworzy specyfikację interfejsu OpenAPI (wcześniej specyfikację struktury Swagger) dla usługi internetowej podczas wdrażania.

Ostrzeżenie

Nie można używać poufnych ani prywatnych danych dla przykładowych danych wejściowych lub wyjściowych. Strona struktury Swagger dla wnioskowania hostowanego w języku AML uwidacznia przykładowe dane.

Te typy są obecnie obsługiwane:

  • pandas
  • numpy
  • pyspark
  • Standardowy obiekt języka Python

Aby użyć generowania schematu, dołącz pakiet open source inference-schema w wersji 1.1.0 lub nowszej w pliku zależności. Aby uzyskać więcej informacji na temat tego pakietu, zobacz InferenceSchema w witrynie GitHub. Aby wygenerować zgodną strukturę Swagger na potrzeby zautomatyzowanego użycia usługi internetowej, funkcja run() skryptu oceniania musi mieć kształt interfejsu API:

  • Pierwszy parametr typu StandardPythonParameterType, nazwane dane wejściowe i zagnieżdżone
  • Opcjonalny drugi parametr typu StandardPythonParameterType, o nazwie GlobalParameters
  • Zwracanie słownika typu StandardPythonParameterType, o nazwie Wyniki i zagnieżdżone

Zdefiniuj przykładowe formaty danych wejściowych i wyjściowych w input_sample zmiennych i output_sample , które reprezentują formaty żądania i odpowiedzi dla usługi internetowej. Użyj tych przykładów w dekoratorach funkcji wejściowych i wyjściowych w run() funkcji. Poniższy przykład biblioteki scikit-learn używa generowania schematu.

Punkt końcowy zgodny z usługą Power BI

W poniższym przykładzie pokazano, jak zdefiniować kształt interfejsu API zgodnie z poprzednią instrukcją. Ta metoda jest obsługiwana w przypadku korzystania z wdrożonej usługi internetowej z usługi 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

Napiwek

Wartość zwracana ze skryptu może być dowolnym obiektem języka Python, który można serializować do formatu JSON. Jeśli na przykład model zwraca ramkę danych biblioteki Pandas zawierającą wiele kolumn, możesz użyć dekoratora wyjściowego podobnego do następującego kodu:

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

Dane binarne (czyli obraz)

Jeśli model akceptuje dane binarne, takie jak obraz, należy zmodyfikować plik score.py używany do wdrożenia, aby akceptował nieprzetworzone żądania HTTP. Aby zaakceptować nieprzetworzone dane, użyj AMLRequest klasy w skry skrywcie wpisu i dodaj @rawhttp dekorator do run() funkcji.

Oto przykład akceptowania score.py danych binarnych:

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)

Ważne

Klasa AMLRequest znajduje się w azureml.contrib przestrzeni nazw. Jednostki w tej przestrzeni nazw zmieniają się często, gdy pracujemy nad ulepszeniem usługi. Wszystkie elementy w tej przestrzeni nazw powinny być traktowane jako wersja zapoznawcza, która nie jest w pełni obsługiwana przez firmę Microsoft.

Jeśli chcesz to przetestować w lokalnym środowisku projektowym, możesz zainstalować składniki przy użyciu następującego polecenia:

pip install azureml-contrib-services

Uwaga

Kod stanu 500 nie jest zalecany jako niestandardowy kod stanu, jak po stronie azureml-fe, kod stanu zostanie przepisany na 502.

  • Kod stanu jest przekazywany przez azureml-fe, a następnie wysyłany do klienta.
  • Tylko azureml-fe zapisuje ponownie 500 zwróconych z boku modelu do 502, klient otrzymuje 502.
  • Ale jeśli sam azureml-fe zwraca 500, po stronie klienta nadal otrzymuje 500.

Klasa AMLRequest umożliwia dostęp tylko do nieprzetworzonych danych opublikowanych w pliku score.py , nie ma składnika po stronie klienta. Od klienta dane są ogłaszane normalnie. Na przykład następujący kod w języku Python odczytuje plik obrazu i publikuje dane:

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)

Współużytkowanie zasobów między źródłami (CORS)

Współużytkowanie zasobów między źródłami to sposób zezwalania na żądanie zasobów na stronie internetowej z innej domeny. Mechanizm CORS działa za pośrednictwem nagłówków HTTP wysyłanych z żądaniem klienta i zwracanych z odpowiedzią usługi. Aby uzyskać więcej informacji na temat mechanizmu CORS i prawidłowych nagłówków, zobacz Współużytkowanie zasobów między źródłami w Wikipedii.

Aby skonfigurować wdrożenie modelu w celu obsługi mechanizmu CORS, użyj AMLResponse klasy w skrytecie wejściowym. Ta klasa umożliwia ustawienie nagłówków w obiekcie odpowiedzi.

Poniższy przykład ustawia Access-Control-Allow-Origin nagłówek odpowiedzi ze skryptu wpisu:

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)

Ważne

Klasa AMLResponse znajduje się w azureml.contrib przestrzeni nazw. Jednostki w tej przestrzeni nazw zmieniają się często, gdy pracujemy nad ulepszeniem usługi. Wszystkie elementy w tej przestrzeni nazw powinny być traktowane jako wersja zapoznawcza, która nie jest w pełni obsługiwana przez firmę Microsoft.

Jeśli chcesz to przetestować w lokalnym środowisku projektowym, możesz zainstalować składniki przy użyciu następującego polecenia:

pip install azureml-contrib-services

Ostrzeżenie

Usługa Azure Machine Edukacja kieruje tylko żądania POST i GET do kontenerów z uruchomioną usługą oceniania. Może to spowodować błędy z powodu przeglądarek przy użyciu żądań OPTIONS do żądań CORS przed lotem.

Ładowanie zarejestrowanych modeli

Są dwa sposoby lokalizowania modeli w skrypcie wejściowym:

  • AZUREML_MODEL_DIR: zmienna środowiskowa zawierająca ścieżkę do lokalizacji modelu
  • Model.get_model_path: interfejs API, który zwraca ścieżkę do pliku modelu przy użyciu zarejestrowanej nazwy modelu

AZUREML_MODEL_DIR

AZUREML_MODEL_DIR jest zmienną środowiskową utworzoną podczas wdrażania usługi. Za pomocą tej zmiennej środowiskowej możesz znaleźć lokalizację wdrożonych modeli.

W poniższej tabeli opisano wartość w AZUREML_MODEL_DIR zależności od liczby wdrożonych modeli:

Wdrożenie Wartość zmiennej środowiskowej
Pojedynczy model Ścieżka do folderu zawierającego model.
Wiele modeli Ścieżka do folderu zawierającego wszystkie modele. Modele znajdują się według nazwy i wersji w tym folderze ($MODEL_NAME/$VERSION)

Podczas rejestracji i wdrażania modelu modele są umieszczane w ścieżce AZUREML_MODEL_DIR, a ich oryginalne nazwy plików są zachowywane.

Aby uzyskać ścieżkę do pliku modelu w skrybacie wejściowym, połącz zmienną środowiskową ze ścieżką pliku, której szukasz.

Przykład pojedynczego 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')

Przykład wielu modeli

W tym scenariuszu dwa modele są rejestrowane w obszarze roboczym:

  • my_first_model: zawiera jeden plik (my_first_model.pkl) i jest tylko jedna wersja, 1
  • my_second_model: zawiera jeden plik (my_second_model.pkl) i istnieją dwie wersje i 12

Po wdrożeniu usługi oba modele są udostępniane w operacji wdrażania:

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)

Na obrazie platformy Docker hostujący usługę zmienna AZUREML_MODEL_DIR środowiskowa zawiera katalog, w którym znajdują się modele. W tym katalogu każdy z modeli znajduje się w ścieżce MODEL_NAME/VERSIONkatalogu . Gdzie MODEL_NAME jest nazwą zarejestrowanego modelu i VERSION jest wersją modelu. Pliki tworzące zarejestrowany model są przechowywane w tych katalogach.

W tym przykładzie ścieżki to $AZUREML_MODEL_DIR/my_first_model/1/my_first_model.pkl i $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

Podczas rejestrowania modelu należy podać nazwę modelu, która jest używana do zarządzania modelem w rejestrze. Ta nazwa jest używana z metodą Model.get_model_path(), aby pobrać ścieżkę pliku bądź plików modelu w lokalnym systemie plików. Jeśli zarejestrujesz folder lub kolekcję plików, ten interfejs API zwróci ścieżkę katalogu zawierającego te pliki.

Podczas rejestrowania modelu należy nadać mu nazwę. Nazwa odpowiada miejscu umieszczania modelu lokalnie lub podczas wdrażania usługi.

Przykłady specyficzne dla platformy

Zobacz następujące artykuły, aby uzyskać więcej przykładów skryptów wejściowych dla konkretnych przypadków użycia uczenia maszynowego: