تأليف برنامج نصي متقدم للدخول

ينطبق على:Python SDK azureml v1

توضح هذه المقالة كيفية كتابة البرامج النصية لإدخال حالات الاستخدام المتخصصة.

المتطلبات الأساسية

تفترض هذه المقالة أن لديك بالفعل نموذج تعلم آلي مدرب تنوي نشره باستخدام Azure التعلم الآلي. لمعرفة المزيد حول نشر النموذج، راجع نشر نماذج التعلم الآلي إلى Azure.

إنشاء مخطط Swagger تلقائيا

لإنشاء مخطط تلقائيا لخدمة الويب الخاصة بك، قم بتوفير عينة من الإدخال و/أو الإخراج في الدالة الإنشائية لأحد كائنات النوع المُعرفة. يتم استخدام النوع والعينة لإنشاء المخطط تلقائيا. ثم يقوم Azure التعلم الآلي بإنشاء مواصفات OpenAPI (سابقا، مواصفات Swagger) لخدمة الويب أثناء النشر.

تحذير

يجب عدم استخدام البيانات الحساسة أو الخاصة لنموذج الإدخال أو الإخراج. تعرض صفحة Swagger للاستدلال المستضاف على Azure التعلم الآلي بيانات العينة.

هذه الأنواع مدعومة حاليا:

  • pandas
  • numpy
  • pyspark
  • كائن Python القياسي

لاستخدام إنشاء المخطط، قم بتضمين إصدار الحزمة مفتوحة المصدر inference-schema 1.1.0 أو أعلى في ملف التبعيات. لمزيد من المعلومات حول هذه الحزمة، راجع InferenceSchema على GitHub. من أجل إنشاء Swagger متوافقة لاستهلاك خدمة الويب التلقائي، يجب أن تحتوي وظيفة تسجيل البرنامج النصي run() على شكل API من:

  • معلمة أولى من النوع StandardPythonParameterType، تسمى Inputs ومتداخلة
  • معلمة ثانية اختيارية من النوع StandardPythonParameterType، تسمى GlobalParameters
  • إرجاع قاموس من النوع StandardPythonParameterType، يسمى النتائج ومتداخل

حدد تنسيقات نموذج الإدخال والإخراج في input_sample المتغيرات و output_sample، والتي تمثل تنسيقات الطلب والاستجابة لخدمة الويب. استخدم هذه العينات في مزخرفات دالة الإدخال والإخراج على الدالة run(). يستخدم المثال scikit-learn التالي إنشاء المخطط.

نقطة نهاية متوافقة مع Power BI

يوضح المثال التالي كيفية تعريف شكل واجهة برمجة التطبيقات وفقا للتعليمات السابقة. هذا الأسلوب مدعوم لاستهلاك خدمة الويب المنشورة من 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

تلميح

يمكن أن تكون القيمة المرجعة من البرنامج النصي أي كائن Python قابل للتسلسل إلى JSON. على سبيل المثال، إذا كان النموذج الخاص بك يرجع إطار بيانات 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 والعناوين الصالحة، راجع مشاركة الموارد عبر المنشأ في ويكيبيديا.

لتكوين نشر النموذج الخاص بك لدعم 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 التعلم الآلي طلبات POST و GET فقط إلى الحاويات التي تشغل خدمة التسجيل. يمكن أن يتسبب هذا في حدوث أخطاء بسبب المستعرضات التي تستخدم طلبات OPTIONS لطلبات CORS قبل الرحلة.

تحميل النماذج المسجلة

هناك طريقتان لتحديد موقع النماذج في البرنامج النصي للإدخال:

  • AZUREML_MODEL_DIR: متغير بيئة يحتوي على المسار إلى موقع النموذج
  • Model.get_model_path: واجهة برمجة تطبيقات تقوم بإرجاع المسار إلى ملف النموذج باستخدام اسم النموذج المسجل

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) وهناك إصداران، 1 و 2

عند نشر الخدمة، يتم توفير كلا النموذجين في عملية التوزيع:

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() لاسترداد مسار ملف النموذج أو الملفات على نظام الملف المحلي. إذا قمت بتسجيل مجلد أو مجموعة من الملفات، فترجع واجهة برمجة التطبيقات هذه مسار الدليل الذي يحتوي على هذه الملفات.

عند تسجيل نموذج، يمكنك إعطائها اسما. يتوافق الاسم مع مكان وضع النموذج، إما محليا أو أثناء نشر الخدمة.

أمثلة خاصة إطار العمل

راجع المقالات التالية لمزيد من أمثلة البرنامج النصي للإدخال لحالات استخدام التعلم الآلي المحددة: