واجهة برمجة التطبيقات المريحة

بالإضافة إلى واجهات برمجة تطبيقات gRPC، يدعم TensorFlow ModelServer أيضًا واجهات برمجة تطبيقات RESTful. تصف هذه الصفحة نقاط نهاية واجهة برمجة التطبيقات (API) هذه ومثالًا شاملاً حول الاستخدام.

الطلب والاستجابة عبارة عن كائن JSON. يعتمد تكوين هذا الكائن على نوع الطلب أو الفعل. راجع الأقسام المحددة لواجهة برمجة التطبيقات أدناه للحصول على التفاصيل.

في حالة حدوث خطأ، ستعيد جميع واجهات برمجة التطبيقات كائن JSON في نص الاستجابة مع error كمفتاح ورسالة الخطأ كقيمة:

{
  "error": <error message string>
}

واجهة برمجة تطبيقات حالة النموذج

تتبع واجهة برمجة التطبيقات (API) هذه واجهة برمجة تطبيقات ModelService.GetModelStatus gRPC عن كثب. تقوم بإرجاع حالة النموذج في ModelServer.

عنوان URL

GET http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]

يعد تضمين /versions/${VERSION} أو /labels/${LABEL} أمرًا اختياريًا. إذا تم إرجاع الحالة المحذوفة لجميع الإصدارات في الرد.

تنسيق الاستجابة

إذا نجحت، فسيتم إرجاع تمثيل JSON لـ GetModelStatusResponse protobuf.

واجهة برمجة تطبيقات بيانات التعريف النموذجية

تتبع واجهة برمجة التطبيقات (API) هذه واجهة برمجة تطبيقات PredictionService.GetModelMetadata gRPC عن كثب. تقوم بإرجاع البيانات التعريفية للنموذج في ModelServer.

عنوان URL

GET http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]/metadata

يعد تضمين /versions/${VERSION} أو /labels/${LABEL} أمرًا اختياريًا. إذا تم حذف البيانات التعريفية للنموذج لأحدث إصدار، فسيتم إرجاعها في الاستجابة.

تنسيق الاستجابة

إذا نجحت، فسيتم إرجاع تمثيل JSON لـ GetModelMetadataResponse protobuf.

تصنيف وتراجع API

تتبع واجهة برمجة التطبيقات (API) هذه عن كثب طرق Classify Regress الخاصة بـ PredictionService gRPC API.

عنوان URL

POST http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]:(classify|regress)

يعد تضمين /versions/${VERSION} أو /labels/${LABEL} أمرًا اختياريًا. إذا تم حذفه يتم استخدام أحدث إصدار.

تنسيق الطلب

يجب أن يكون نص الطلب الخاص بواجهات برمجة التطبيقات classify regress عبارة عن كائن JSON منسق على النحو التالي:

{
  // Optional: serving signature to use.
  // If unspecifed default serving signature is used.
  "signature_name": <string>,

  // Optional: Common context shared by all examples.
  // Features that appear here MUST NOT appear in examples (below).
  "context": {
    "<feature_name3>": <value>|<list>
    "<feature_name4>": <value>|<list>
  },

  // List of Example objects
  "examples": [
    {
      // Example 1
      "<feature_name1>": <value>|<list>,
      "<feature_name2>": <value>|<list>,
      ...
    },
    {
      // Example 2
      "<feature_name1>": <value>|<list>,
      "<feature_name2>": <value>|<list>,
      ...
    }
    ...
  ]
}

<value> هو رقم JSON (كامل أو عشري)، أو سلسلة JSON، أو كائن JSON يمثل البيانات الثنائية (راجع قسم ترميز القيم الثنائية أدناه للحصول على التفاصيل). <list> هي قائمة بهذه القيم. يشبه هذا التنسيق نماذج ClassificationRequest و RegressionRequest الأولية الخاصة بـ gRPC. يقبل كلا الإصدارين قائمة كائنات Example .

تنسيق الاستجابة

يقوم طلب classify بإرجاع كائن JSON في نص الاستجابة، بتنسيق كما يلي:

{
  "result": [
    // List of class label/score pairs for first Example (in request)
    [ [<label1>, <score1>], [<label2>, <score2>], ... ],

    // List of class label/score pairs for next Example (in request)
    [ [<label1>, <score1>], [<label2>, <score2>], ... ],
    ...
  ]
}

<label> عبارة عن سلسلة (والتي يمكن أن تكون سلسلة فارغة "" إذا لم يكن للنموذج تسمية مرتبطة بالنتيجة). <score> هو رقم عشري (نقطة عائمة).

يقوم طلب regress بإرجاع كائن JSON في نص الاستجابة، بتنسيق كما يلي:

{
  // One regression value for each example in the request in the same order.
  "result": [ <value1>, <value2>, <value3>, ...]
}

<value> هو رقم عشري.

سيلاحظ مستخدمو gRPC API تشابه هذا التنسيق مع نماذج ClassificationResponse و RegressionResponse .

توقع واجهة برمجة التطبيقات

تتبع واجهة برمجة التطبيقات هذه بشكل وثيق واجهة برمجة تطبيقات PredictionService.Predict gRPC.

عنوان URL

POST http://host:port/v1/models/${MODEL_NAME}[/versions/${VERSION}|/labels/${LABEL}]:predict

يعد تضمين /versions/${VERSION} أو /labels/${LABEL} أمرًا اختياريًا. إذا تم حذفه يتم استخدام أحدث إصدار.

تنسيق الطلب

يجب أن يكون نص الطلب لواجهة برمجة التطبيقات predict بتنسيق كائن JSON كما يلي:

{
  // (Optional) Serving signature to use.
  // If unspecifed default serving signature is used.
  "signature_name": <string>,

  // Input Tensors in row ("instances") or columnar ("inputs") format.
  // A request can have either of them but NOT both.
  "instances": <value>|<(nested)list>|<list-of-objects>
  "inputs": <value>|<(nested)list>|<object>
}

تحديد موترات الإدخال بتنسيق الصف.

يشبه هذا التنسيق نموذج PredictRequest لواجهة برمجة تطبيقات gRPC وواجهة برمجة تطبيقات التنبؤ CMLE . استخدم هذا التنسيق إذا كانت جميع موترات الإدخال المسماة لها نفس البعد الصفري . إذا لم يحدث ذلك، فاستخدم التنسيق العمودي الموضح لاحقًا أدناه.

في تنسيق الصف، يتم ربط المدخلات بمفتاح المثيلات في طلب JSON.

عندما يكون هناك إدخال مسمى واحد فقط، حدد قيمة مفتاح المثيلات لتكون قيمة الإدخال:

{
  // List of 3 scalar tensors.
  "instances": [ "foo", "bar", "baz" ]
}

{
  // List of 2 tensors each of [1, 2] shape
  "instances": [ [[1, 2]], [[3, 4]] ]
}

يتم التعبير عن الموترات بشكل طبيعي برموز متداخلة نظرًا لعدم الحاجة إلى تسوية القائمة يدويًا.

بالنسبة للمدخلات المسماة المتعددة، من المتوقع أن يكون كل عنصر كائنًا يحتوي على اسم الإدخال/زوج قيمة الموتر، واحد لكل إدخال مسمى. على سبيل المثال، ما يلي هو طلب بمثيلين، كل منهما يحتوي على مجموعة من ثلاثة موترات إدخال مسماة:

{
 "instances": [
   {
     "tag": "foo",
     "signal": [1, 2, 3, 4, 5],
     "sensor": [[1, 2], [3, 4]]
   },
   {
     "tag": "bar",
     "signal": [3, 4, 1, 2, 5]],
     "sensor": [[4, 5], [6, 8]]
   }
 ]
}

لاحظ أن كل إدخال مسمى ("علامة"، "إشارة"، "مستشعر") يُفترض ضمنيًا أن له نفس البعد الصفري ( اثنان في المثال أعلاه، حيث يوجد كائنان في قائمة المثيلات ). إذا قمت بتسمية مدخلات ذات بُعد 0 مختلف، فاستخدم التنسيق العمودي الموضح أدناه.

تحديد موتر الإدخال في تنسيق العمود.

استخدم هذا التنسيق لتحديد موترات الإدخال الخاصة بك، إذا كانت المدخلات الفردية المسماة لا تحتوي على نفس البعد الصفري أو كنت تريد تمثيلًا أكثر إحكاما. يشبه هذا التنسيق حقل inputs لطلب Predict gRPC.

في التنسيق العمودي، يتم ربط المدخلات بمفتاح الإدخال في طلب JSON.

يمكن أن تكون قيمة مفتاح الإدخال إما موتر إدخال واحد أو خريطة لاسم الإدخال للموترات (مدرجة في شكلها المتداخل الطبيعي). يمكن أن يكون لكل إدخال شكل عشوائي ولا يلزم مشاركة نفس البعد الصفري (المعروف أيضًا باسم حجم الدُفعة) كما هو مطلوب في تنسيق الصف الموضح أعلاه.

التمثيل العمودي للمثال السابق هو كما يلي:

{
 "inputs": {
   "tag": ["foo", "bar"],
   "signal": [[1, 2, 3, 4, 5], [3, 4, 1, 2, 5]],
   "sensor": [[[1, 2], [3, 4]], [[4, 5], [6, 8]]]
 }
}

لاحظ أن المدخلات هي كائن JSON وليست قائمة مثل المثيلات (المستخدمة في تمثيل الصف). بالإضافة إلى ذلك، يتم تحديد كافة المدخلات المسماة معًا، بدلاً من فتحها في صفوف فردية يتم تنفيذها بتنسيق الصف الموضح مسبقًا. وهذا يجعل التمثيل مضغوطًا (ولكن ربما أقل قابلية للقراءة).

تنسيق الاستجابة

يقوم طلب predict بإرجاع كائن JSON في نص الاستجابة.

يتم تنسيق الاستجابة لطلب في تنسيق الصف كما يلي:

{
  "predictions": <value>|<(nested)list>|<list-of-objects>
}

إذا كان ناتج النموذج يحتوي على موتر مسمى واحد فقط، فإننا نحذف الاسم والخرائط الرئيسية predictions إلى قائمة القيم العددية أو القائمة. إذا قام النموذج بإخراج عدة موترات مسماة، فإننا نخرج قائمة من الكائنات بدلاً من ذلك، على غرار الطلب في تنسيق الصف المذكور أعلاه.

يتم تنسيق الاستجابة لطلب بتنسيق عمودي على النحو التالي:

{
  "outputs": <value>|<(nested)list>|<object>
}

إذا كان مخرج النموذج يحتوي على موتر مسمى واحد فقط، فإننا نحذف الاسم outputs خرائط المفاتيح إلى قائمة القيم العددية أو القائمة. إذا قام النموذج بإخراج عدة موترات مسماة، فإننا نخرج كائنًا بدلاً من ذلك. يتوافق كل مفتاح لهذا الكائن مع موتر الإخراج المسمى. التنسيق مشابه للطلب بتنسيق العمود المذكور أعلاه.

إخراج القيم الثنائية

لا يميز TensorFlow بين السلاسل غير الثنائية والثنائية. كلها من النوع DT_STRING . تعتبر الموترات المسماة التي تحتوي على _bytes كلاحقة في اسمها ذات قيم ثنائية. يتم ترميز هذه القيم بشكل مختلف كما هو موضح في قسم ترميز القيم الثنائية أدناه.

رسم خرائط JSON

تدعم واجهات برمجة تطبيقات RESTful التشفير الأساسي بتنسيق JSON، مما يسهل مشاركة البيانات بين الأنظمة. بالنسبة للأنواع المدعومة، يتم وصف الترميزات على أساس كل نوع على حدة في الجدول أدناه. الأنواع غير المذكورة أدناه تشير ضمنيًا إلى أنها غير مدعومة.

نوع بيانات TF قيمة جسون مثال جيسون ملحوظات
DT_BOOL خطأ صحيح خطأ صحيح
DT_STRING خيط "مرحبا بالعالم!" إذا كان DT_STRING يمثل بايتات ثنائية (على سبيل المثال، بايتات الصور المتسلسلة أو protobuf)، فقم بتشفيرها في Base64. راجع ترميز القيم الثنائية لمزيد من المعلومات.
DT_INT8، DT_UINT8، DT_INT16، DT_INT32، DT_UINT32، DT_INT64، DT_UINT64 رقم 1، -10، 0 ستكون قيمة JSON رقمًا عشريًا.
DT_FLOAT، DT_DOUBLE رقم 1.1، -10.0، 0، NaN ، Infinity ستكون قيمة JSON عبارة عن رقم أو إحدى قيم الرموز المميزة الخاصة - NaN و Infinity و -Infinity . راجع توافق JSON لمزيد من المعلومات. يتم أيضًا قبول تدوين الأس.

دقة النقطة العائمة

يحتوي JSON على نوع بيانات رقم واحد. وبالتالي فمن الممكن توفير قيمة للمدخلات التي تؤدي إلى فقدان الدقة. على سبيل المثال، إذا كان الإدخال x هو نوع بيانات float ، وتم إرسال الإدخال {"x": 1435774380} إلى النموذج الذي يعمل على الأجهزة استنادًا إلى معيار النقطة العائمة IEEE 754 (على سبيل المثال Intel أو AMD)، فستكون القيمة يتم تحويله بصمت بواسطة الأجهزة السفلية إلى 1435774336 حيث لا يمكن تمثيل 1435774380 تمامًا في رقم الفاصلة العائمة 32 بت. عادةً، يجب أن تكون مدخلات الخدمة هي نفس توزيع التدريب، لذلك لن يكون هذا مشكلة بشكل عام لأن نفس التحويلات حدثت في وقت التدريب. ومع ذلك، في حالة الحاجة إلى الدقة الكاملة، تأكد من استخدام نوع بيانات أساسي في النموذج الخاص بك يمكنه التعامل مع الدقة المطلوبة و/أو التفكير في التحقق من جانب العميل.

ترميز القيم الثنائية

يستخدم JSON ترميز UTF-8. إذا كان لديك ميزة إدخال أو قيم موتر تحتاج إلى أن تكون ثنائية (مثل بايتات الصورة)، فيجب عليك تشفير Base64 للبيانات وتغليفها في كائن JSON يحتوي على b64 كمفتاح كما يلي:

{ "b64": <base64 encoded string> }

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

يظهر أدناه طلب تصنيف مع image (البيانات الثنائية) وميزات caption :

{
  "signature_name": "classify_objects",
  "examples": [
    {
      "image": { "b64": "aW1hZ2UgYnl0ZXM=" },
      "caption": "seaside"
    },
    {
      "image": { "b64": "YXdlc29tZSBpbWFnZSBieXRlcw==" },
      "caption": "mountains"
    }
  ]
}

مطابقة JSON

العديد من قيم الميزات أو الموتر هي أرقام الفاصلة العائمة. وبصرف النظر عن القيم المحدودة (مثل 3.14، 1.0 وما إلى ذلك) يمكن أن تحتوي هذه القيم على قيم NaN وقيم غير محدودة ( Infinity و- -Infinity ). لسوء الحظ، لا تتعرف مواصفات JSON ( RFC 7159 ) على هذه القيم (على الرغم من أن مواصفات JavaScript تتعرف عليها).

تسمح واجهة برمجة تطبيقات REST الموضحة في هذه الصفحة لكائنات JSON للطلب/الاستجابة بالحصول على مثل هذه القيم. وهذا يعني أن طلبات مثل الطلب التالي صالحة:

{
  "example": [
    {
      "sensor_readings": [ 1.0, -3.14, Nan, Infinity ]
    }
  ]
}

سيرفض محلل JSON المتوافق مع المعايير (الصارمة) هذا مع وجود خطأ تحليلي (بسبب رموز NaN و Infinity الممزوجة بالأرقام الفعلية). للتعامل بشكل صحيح مع الطلبات/الاستجابات في التعليمات البرمجية الخاصة بك، استخدم محلل JSON الذي يدعم هذه الرموز المميزة.

يتم التعرف على الرموز المميزة NaN و Infinity -Infinity بواسطة proto3 ووحدة Python JSON ولغة JavaScript.

مثال

يمكننا استخدام نموذج اللعبة half_plus_three لرؤية واجهات برمجة تطبيقات REST أثناء العمل.

ابدأ تشغيل ModelServer باستخدام نقطة نهاية REST API

قم بتنزيل نموذج half_plus_three من مستودع git :

$ mkdir -p /tmp/tfserving
$ cd /tmp/tfserving
$ git clone --depth=1 https://github.com/tensorflow/serving

سوف نستخدم Docker لتشغيل ModelServer. إذا كنت تريد تثبيت ModelServer محليًا على نظامك، فاتبع تعليمات الإعداد للتثبيت بدلاً من ذلك، وابدأ تشغيل ModelServer باستخدام خيار --rest_api_port لتصدير نقطة نهاية REST API (ليس هذا ضروريًا عند استخدام Docker).

$ cd /tmp/tfserving
$ docker pull tensorflow/serving:latest
$ docker run --rm -p 8501:8501 \
    --mount type=bind,source=$(pwd),target=$(pwd) \
    -e MODEL_BASE_PATH=$(pwd)/serving/tensorflow_serving/servables/tensorflow/testdata \
    -e MODEL_NAME=saved_model_half_plus_three -t tensorflow/serving:latest
...
.... Exporting HTTP/REST API at:localhost:8501 ...

قم بإجراء مكالمات REST API إلى ModelServer

في محطة طرفية مختلفة، استخدم أداة curl لإجراء استدعاءات REST API.

احصل على حالة النموذج كما يلي:

$ curl http://localhost:8501/v1/models/saved_model_half_plus_three
{
 "model_version_status": [
  {
   "version": "123",
   "state": "AVAILABLE",
   "status": {
    "error_code": "OK",
    "error_message": ""
   }
  }
 ]
}

ستبدو مكالمة predict كما يلي:

$ curl -d '{"instances": [1.0,2.0,5.0]}' -X POST http://localhost:8501/v1/models/saved_model_half_plus_three:predict
{
    "predictions": [3.5, 4.0, 5.5]
}

وتبدو مكالمة regress كما يلي:

$ curl -d '{"signature_name": "tensorflow/serving/regress", "examples": [{"x": 1.0}, {"x": 2.0}]}' \
  -X POST http://localhost:8501/v1/models/saved_model_half_plus_three:regress
{
    "results": [3.5, 4.0]
}

لاحظ أن regress متاح على اسم توقيع غير افتراضي ويجب تحديده بشكل صريح. يعرض عنوان URL أو نص الطلب غير الصحيح حالة خطأ HTTP.

$ curl -i -d '{"instances": [1.0,5.0]}' -X POST http://localhost:8501/v1/models/half:predict
HTTP/1.1 404 Not Found
Content-Type: application/json
Date: Wed, 06 Jun 2018 23:20:12 GMT
Content-Length: 65

{ "error": "Servable not found for request: Latest(half)" }
$