共用方式為


進階的輸入腳本製作

適用於: Python SDK azureml v1

本文說明如何撰寫特定使用案例的輸入腳本。

必要條件

本文假設您已經有想要使用 Azure Machine Learning 部署的定型機器學習模型。 若要深入了解模型部署,請參閱將機器學習模型部署至 Azure

自動產生 Swagger 結構描述

若要自動產生 Web 服務的結構描述,請在其中一個已定義類型物件的建構函式中提供輸入和/或輸出的範例。 類型和範例會用來自動建立結構描述。 接著 Azure Machine Learning 會在部署期間為 Web 服務建立 OpenAPI 應用程式 (先前為 Swagger 規格)。

警告

您不得針對範例輸入或輸出使用敏感性或私人資料。 AML 裝載推斷的 Swagger 頁面會公開範例資料。

目前支援下列類型:

  • pandas
  • numpy
  • pyspark
  • 標準 Python 物件

若要使用結構描述產生,請在您的相依性檔案中包含開放原始碼 inference-schema 套件版本 1.1.0 或更新版本。 如需此套件的詳細資訊,請參閱 GitHub 上的 InferenceSchema。 若要針對自動化 Web 服務耗用量產生符合的 swagger,評分指令碼 run() 函式必須有下列各項的 API 圖形:

  • 類型為 StandardPythonParameterType 的第一個參數,名為 Inputs 並為巢狀
  • 類型為 StandardPythonParameterType 的選擇性第二個參數,名為 GlobalParameters
  • 傳回類型為 StandardPythonParameterType 的字典,名為 Results 並為巢狀

input_sampleoutput_sample 變數中定義輸入和輸出範例格式,這些格式代表 Web 服務的要求和回應格式。 在 run() 函式的輸入和輸出函式裝飾項目中使用這些範例。 下列 scikit-learn 範例會使用結構描述產生。

Power BI 相容端點

下列範例示範如何根據上述指示定義 API 圖形。 從 Power BI 使用已部署的 Web 服務時,支援此方法。

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

提示

指令碼的傳回值可以是可序列化為 JSON 的任何 Python 物件。 例如,如果您的模型傳回包含多個資料行的 Pandas 資料框架,您可能會使用類似下列程式碼的輸出裝飾項目:

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

二進位 (即映像) 資料

如果您的模型接受二進位資料 (例如影像),則您必須修改用於部署的 score.py 檔案來接受未經處理的 HTTP 要求。 若要接受未經處理資料,請在您的輸入腳本中使用 AMLRequest 類別,並將 @rawhttp 裝飾項目新增至 run() 函式。

以下是可接受二進位資料的 score.py 範例:

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)

重要

AMLRequest 類別位於 azureml.contrib 命名空間中。 此命名空間中的實體會因為我們致力於改善本服務而經常變更。 此命名空間中的任何項目均應視為預覽,而且 Microsoft 不會完全支援。

如果您需要在本機開發環境中測試此項目,您可以使用下列命令安裝元件:

pip install azureml-contrib-services

注意

不建議使用 500 做為自訂狀態碼,如 azureml-fe 端,狀態碼將會重寫為 502

  • 狀態碼會透過 azureml-fe 傳遞,然後傳送至用戶端。
  • azureml-fe 只會將從模型端傳回的 500 重寫為 502,用戶端會收到 502。
  • 但是,如果 azureml-fe 本身傳回 500,用戶端仍會收到 500。

AMLRequest 類別只允許您存取 score.py 檔案中未經處理的張貼資料 (沒有用戶端元件)。 您可以從用戶端像平常一樣張貼資料。 例如,下列 Python 程式碼會讀取影像檔案並張貼資料:

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)

跨原始來源資源分享是一種允許從另一個網域要求網頁上資源的方式。 CORS 可透過與用戶端要求一起傳送的 HTTP 標頭,並隨服務回應傳回來運作。 如需 CORS 和有效標頭的詳細資訊,請參閱 Wikipedia 中的跨原始來源資源分享

若要將模型部署設定為支援 CORS,請在您的輸入腳本中使用 AMLResponse 類別。 這個類別可讓您在回應物件上設定標頭。

下列範例會針對來自輸入腳本的回應設定 Access-Control-Allow-Origin 標頭:

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)

重要

AMLResponse 類別位於 azureml.contrib 命名空間中。 此命名空間中的實體會因為我們致力於改善本服務而經常變更。 此命名空間中的任何項目均應視為預覽,而且 Microsoft 不會完全支援。

如果您需要在本機開發環境中測試此項目,您可以使用下列命令安裝元件:

pip install azureml-contrib-services

警告

Azure Machine Learning 只會將 POST 和 GET 要求路由至執行評分服務的容器。 這可能會因為瀏覽器使用對預先正式發行前小眾測試版 CORS 要求的 OPTIONS 要求而造成錯誤。

載入已註冊的模型

有兩種方式可在您的輸入腳本中尋找模型:

  • AZUREML_MODEL_DIR:包含模型位置路徑的環境變數
  • Model.get_model_path:使用已註冊的模型名稱傳回模型檔案路徑的 API

AZUREML_MODEL_DIR

AZUREML_MODEL_DIR 是在服務部署期間建立的環境變數。 您可以使用此環境變數,尋找部署模型的位置。

下表描述 AZUREML_MODEL_DIR 的值,視部署的模型數目而定:

部署 環境變數值
單一模型 模型所在資料夾的路徑。
多個模型 所有模型所在資料夾的路徑。 模型是依據此資料夾中的名稱和版本來尋找 ($MODEL_NAME/$VERSION)

在模型註冊和部署期間,會將模型放在 AZUREML_MODEL_DIR 路徑中,並保留其原始檔案名稱。

若要取得輸入腳本中模型檔案的路徑,請將環境變數與您要尋找的檔案路徑結合。

單一模型範例

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

多個模型範例

在此案例中,會在工作區中註冊兩個模型:

  • my_first_model:包含一個檔案 (my_first_model.pkl) 且只有一個版本 (1)
  • my_second_model:包含一個檔案 (my_second_model.pkl) 且有兩個版本 (12)

部署服務時,會在部署作業中提供這兩個模型:

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)

在裝載服務的 Docker 映像中,AZUREML_MODEL_DIR 環境變數包含模型所在的目錄。 在此目錄中,每個模型都位於 MODEL_NAME/VERSION 的目錄路徑中。 其中 MODEL_NAME 是已註冊模型的名稱,而 VERSION 是模型的版本。 組成已註冊模型的檔案會儲存在這些目錄中。

在此範例中,路徑是 $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

當您註冊模型時,您會提供用來管理登錄中模型的模型名稱。 您可以使用此名稱搭配 Model.get_model_path()方法,以擷取本機檔案系統上的模型檔案的路徑。 如果您註冊資料夾或檔案集合,此 API 會傳回包含這些檔案的目錄路徑。

當您註冊模型時,您會為其命名。 名稱會對應至放置模型的位置,不論是在本機或在服務部署期間。

特定架構範例

如需特定機器學習使用案例的更多輸入腳本範例,請參閱下列文章: