API RESTful

בנוסף לממשקי API של gRPC, TensorFlow ModelServer תומך גם בממשקי API של RESTful. דף זה מתאר את נקודות הקצה הללו של API ודוגמה מקצה לקצה על שימוש.

הבקשה והתגובה הם אובייקט JSON. ההרכב של אובייקט זה תלוי בסוג הבקשה או הפועל. עיין בסעיפים הספציפיים של ממשק API למטה לפרטים.

במקרה של שגיאה, כל ממשקי ה-API יחזירו אובייקט JSON בגוף התגובה עם error כמפתח והודעת השגיאה כערך:

{
  "error": <error message string>
}

API של סטטוס דגם

ממשק API זה עוקב מקרוב אחר ה-API של ModelService.GetModelStatus gRPC. זה מחזיר את המצב של מודל ב-ModelServer.

כתובת אתר

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.

כתובת אתר

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

הכללת /versions/${VERSION} או /labels/${LABEL} היא אופציונלית. אם הושמט, המטא-נתונים של המודל עבור הגרסה האחרונה מוחזרים בתגובה.

פורמט תגובה

אם מצליח, מחזיר ייצוג JSON של GetModelMetadataResponse protobuf.

סיווג ו-Regress API

ממשק API זה עוקב מקרוב אחר שיטות Classify Regress של PredictionService gRPC API.

כתובת אתר

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

הכללת /versions/${VERSION} או /labels/${LABEL} היא אופציונלית. אם הושמטה נעשה שימוש בגרסה העדכנית ביותר.

פורמט בקשה

גוף הבקשה עבור ממשקי ה-API 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 .

חיזוי API

ממשק API זה עוקב מקרוב אחר ממשק ה-API של PredictionService.Predict gRPC.

כתובת אתר

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

הכללת /versions/${VERSION} או /labels/${LABEL} היא אופציונלית. אם הושמטה נעשה שימוש בגרסה העדכנית ביותר.

פורמט בקשה

גוף הבקשה ל- predict API חייב להיות בפורמט של אובייקט 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 API ו- CMLE Predict API . השתמש בפורמט זה אם לכל טנסורי הקלט בעלי השם יש את אותו ממד 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 או שאתה רוצה ייצוג קומפקטי יותר. פורמט זה דומה לשדה inputs של בקשת ה-gRPC Predict .

בפורמט העמודות, קלט מקודם למפתח קלט בבקשת JSON.

הערך למפתח קלט יכול להיות טנזור קלט בודד או מפה של שם קלט לטנזורים (הרשומים בצורתם המקוננת הטבעית). לכל קלט יכול להיות צורה שרירותית ואינו חייב לחלוק את אותו ממד 0 (הידוע גם בגודל אצווה) כנדרש על פי פורמט השורה המתואר לעיל.

הייצוג העמודי של הדוגמה הקודמת הוא כדלקמן:

{
 "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

ממשקי API של RESTful תומכים בקידוד קנוני ב-JSON, מה שמקל על שיתוף הנתונים בין מערכות. עבור סוגים נתמכים, הקידודים מתוארים על בסיס סוג אחר סוג בטבלה שלהלן. סוגים שאינם מפורטים להלן נרמזים כבלתי נתמכים.

סוג נתונים TF ערך JSON דוגמה JSON הערות
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), אז הערך יהיה להיות מומר בשקט על ידי חומרת ה-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 ) אינו מזהה ערכים אלו (אם כי מפרט JavaScript כן).

REST API המתואר בדף זה מאפשר לאובייקטי JSON בקשה/תגובה לקבל ערכים כאלה. זה מרמז שבקשות כמו הבקשות הבאות תקפות:

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

מנתח JSON תואם תקנים (מחמירים) ידחה זאת בשגיאת ניתוח (עקב אסימוני NaN ו- Infinity מעורבבים עם מספרים בפועל). כדי לטפל בצורה נכונה בבקשות/תגובות בקוד שלך, השתמש במנתח JSON שתומך באסימונים אלה.

אסימוני NaN , Infinity , -Infinity מזוהים על ידי proto3 , מודול Python JSON ושפת JavaScript.

דוּגמָה

אנחנו יכולים להשתמש במודל toy half_plus_three כדי לראות ממשקי API של 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 זמינה בשם חתימה שאינו ברירת מחדל ויש לציין אותה במפורש. כתובת אתר או גוף שגויים של בקשה מחזירה סטטוס שגיאת 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)" }
$