בנוסף לממשקי 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)" }
$