انضم إلى مجتمع SIG TFX-Addons وساعد في جعل TFX أفضل!

RESTful API

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

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

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

{
  "error": <error message string>
}

نموذج حالة API

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

URL

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

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

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

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

نموذج Metadata API

تتبع API هذه عن كثب PredictionService.GetModelMetadata gRPC API. تقوم بإرجاع البيانات الوصفية لنموذج في 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 protos الخاص بـ 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 protos.

توقع API

تتبع API هذه عن كثب PredictionService.Predict gRPC API.

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 proto الخاص بواجهة برمجة تطبيقات gRPC وواجهة برمجة تطبيقات CMLE للتنبؤ . استخدم هذا التنسيق إذا كانت جميع موترلات الإدخال المسماة لها نفس البعد رقم 0 . إذا لم يفعلوا ذلك ، فاستخدم التنسيق العمودي الموضح لاحقًا أدناه.

في تنسيق الصف ، يتم تحديد المدخلات بمفتاح المثيلات في طلب 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 عشر، بعد (اثنان في المثال أعلاه، كما أن هناك نوعان من الكائنات في قائمة الحالات). إذا قمت بتسمية المدخلات التي لها بُعد مختلف من 0 ، فاستخدم التنسيق العمودي الموضح أدناه.

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

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

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

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

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

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

تعيين JSON

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

نوع بيانات TF قيمة JSON مثال على JSON ملاحظات
DT_BOOL خطأ صحيح خطأ صحيح
DT_STRING خيط "مرحبا بالعالم!" إذا كانت DT_STRING تمثل بايتات ثنائية (مثل وحدات بايت الصورة المتسلسلة أو protobuf) ، DT_STRING في 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} إلى النموذج الذي يتم تشغيله على الأجهزة بناءً على معيار {"x": 1435774380} العائمة IEEE 754 (مثل Intel أو AMD) ، فإن القيمة سوف يمكن تحويلها بصمت بواسطة الأجهزة underyling إلى 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 ) لا تعترف بتلك القيم (على الرغم من أن مواصفات جافا سكريبت يفعل).

تسمح واجهة برمجة تطبيقات 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 APIs قيد التنفيذ.

ابدأ 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 أصلاً على نظامك ، فاتبع تعليمات الإعداد للتثبيت بدلاً من ذلك ، وابدأ --rest_api_port بخيار --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)" }
$