بالإضافة إلى واجهات برمجة تطبيقات 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 API الموضحة في هذه الصفحة لكائنات 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)" }
$