מדריך זה מראה לך כיצד להשתמש ברכיבי TensorFlow Serving כדי לבנות את TensorFlow ModelServer הסטנדרטי שמגלה באופן דינמי ומשרת גרסאות חדשות של מודל TensorFlow מאומן. אם אתה רק רוצה להשתמש בשרת הסטנדרטי כדי לשרת את הדגמים שלך, ראה מדריך בסיסי של TensorFlow Serving .
מדריך זה משתמש במודל הפשוט של Softmax Regression שהוצג במדריך TensorFlow לסיווג תמונה בכתב יד (נתוני MNIST). אם אינך יודע מה זה TensorFlow או MNIST, עיין במדריך MNIST למתחילים ב-ML .
הקוד של הדרכה זו מורכב משני חלקים:
קובץ Python mnist_saved_model.py שמאמן ומייצא גרסאות מרובות של המודל.
קובץ C++ main.cc שהוא TensorFlow ModelServer הסטנדרטי שמגלה דגמים מיוצאים חדשים ומפעיל שירות gRPC להגשתם.
מדריך זה מוביל את המשימות הבאות:
- אימון וייצוא של מודל TensorFlow.
- נהל ניהול גרסאות של מודל עם TensorFlow Serving
ServerCore
. - הגדר אצווה באמצעות
SavedModelBundleSourceAdapterConfig
. - בקשת הגשה עם TensorFlow Serving
ServerCore
. - הפעל ובדוק את השירות.
לפני שמתחילים, התקן תחילה את Docker
אימון וייצוא מודל TensorFlow
ראשית, אם עדיין לא עשית זאת, שכפל את המאגר הזה למחשב המקומי שלך:
git clone https://github.com/tensorflow/serving.git
cd serving
נקה את ספריית הייצוא אם היא כבר קיימת:
rm -rf /tmp/models
התאמן (עם 100 איטרציות) וייצא את הגרסה הראשונה של הדגם:
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=100 --model_version=1 /tmp/mnist
רכב (עם 2000 איטרציות) וייצא את הגרסה השנייה של הדגם:
tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
--training_iteration=2000 --model_version=2 /tmp/mnist
כפי שאתה יכול לראות ב- mnist_saved_model.py
, ההדרכה והייצוא נעשים באותו אופן שבו הם מתבצעים במדריך הבסיסי של TensorFlow Serving . למטרות הדגמה, אתה מחייג בכוונה את איטרציות האימון לריצה הראשונה ומייצא אותו כ-v1, תוך כדי אימון רגיל לריצה השנייה ומייצא אותו כ-v2 לאותה ספריית אב -- כפי שאנו מצפים שהאחרון ישיג. דיוק סיווג טוב יותר בגלל אימון אינטנסיבי יותר. אתה אמור לראות נתוני אימון עבור כל ריצת אימון בספריית /tmp/mnist
שלך:
$ ls /tmp/mnist
1 2
ServerCore
כעת דמיינו את v1 ו-v2 של המודל נוצרים באופן דינמי בזמן ריצה, כאשר אלגוריתמים חדשים מתנסים, או כשהמודל מאומן עם מערך נתונים חדש. בסביבת ייצור, ייתכן שתרצה לבנות שרת שיכול לתמוך בהשקה הדרגתית, שבה ניתן לגלות, לטעון, להתנסות, לנטר או להחזיר את v2 בזמן הגשת v1. לחלופין, ייתכן שתרצה להרוס את v1 לפני העלאת v2. TensorFlow Serving תומך בשתי האפשרויות -- בעוד שאחת טובה לשמירה על זמינות במהלך המעבר, השנייה טובה למזעור השימוש במשאבים (למשל זיכרון RAM).
TensorFlow Serving Manager
עושה בדיוק את זה. הוא מטפל במחזור החיים המלא של דגמי TensorFlow כולל טעינה, הגשה ופריקה שלהם וכן מעברי גרסאות. במדריך זה, תבנה את השרת שלך על גבי TensorFlow Serving ServerCore
, אשר עוטף באופן פנימי AspiredVersionsManager
.
int main(int argc, char** argv) {
...
ServerCore::Options options;
options.model_server_config = model_server_config;
options.servable_state_monitor_creator = &CreateServableStateMonitor;
options.custom_model_config_loader = &LoadCustomModelConfig;
::google::protobuf::Any source_adapter_config;
SavedModelBundleSourceAdapterConfig
saved_model_bundle_source_adapter_config;
source_adapter_config.PackFrom(saved_model_bundle_source_adapter_config);
(*(*options.platform_config_map.mutable_platform_configs())
[kTensorFlowModelPlatform].mutable_source_adapter_config()) =
source_adapter_config;
std::unique_ptr<ServerCore> core;
TF_CHECK_OK(ServerCore::Create(options, &core));
RunServer(port, std::move(core));
return 0;
}
ServerCore::Create()
לוקח פרמטר ServerCore::Options. להלן מספר אפשרויות נפוצות:
-
ModelServerConfig
המציין דגמים לטעינה. מודלים מוצהרים או דרךmodel_config_list
, שמצהירה על רשימה סטטית של מודלים, או דרךcustom_model_config
, המגדירה דרך מותאמת אישית להכריז על רשימת דגמים שעשויים להתעדכן בזמן הריצה. -
PlatformConfigMap
שממפה משם הפלטפורמה (כגוןtensorflow
) ל-PlatformConfig
, המשמש ליצירת ה-SourceAdapter
.SourceAdapter
מתאיםStoragePath
(הנתיב שבו מתגלה גרסת דגם) ל-ModelLoader
(טוען את גרסת הדגם מנתיב האחסון ומספק ממשקי מעבר מצבManager
). אםPlatformConfig
מכילSavedModelBundleSourceAdapterConfig
, יווצרSavedModelBundleSourceAdapter
, אותו נסביר בהמשך.
SavedModelBundle
הוא מרכיב מרכזי בשרת TensorFlow. הוא מייצג מודל TensorFlow שנטען מנתיב נתון ומספק את אותו Session::Run
כמו TensorFlow כדי להפעיל הסקה. SavedModelBundleSourceAdapter
מתאים את נתיב האחסון ל- Loader<SavedModelBundle>
כך שניתן לנהל את חיי המודל על ידי Manager
. לידיעתך, SavedModelBundle
הוא היורש של SessionBundle
שהוצא משימוש. מומלץ למשתמשים להשתמש ב- SavedModelBundle
מכיוון שהתמיכה ב- SessionBundle
תוסר בקרוב.
עם כל אלה, ServerCore
עושה באופן פנימי את הדברים הבאים:
- יוצר קובץ
FileSystemStoragePathSource
שמנטר נתיבי ייצוא של מודלים המוצהרים ב-model_config_list
. - מפעיל
SourceAdapter
באמצעותPlatformConfigMap
עם פלטפורמת המודל המוצהרת ב-model_config_list
ומחבר אליו אתFileSystemStoragePathSource
. בדרך זו, בכל פעם שמתגלה גרסת דגם חדשה מתחת לנתיב הייצוא,SavedModelBundleSourceAdapter
מתאים אותה ל-Loader<SavedModelBundle>
. - יוצר יישום ספציפי של
Manager
בשםAspiredVersionsManager
שמנהל את כל מופעיLoader
כאלה שנוצרו על ידיSavedModelBundleSourceAdapter
.ServerCore
מייצא את ממשקManager
על ידי האצלת הקריאות ל-AspiredVersionsManager
.
בכל פעם שגרסה חדשה זמינה, AspiredVersionsManager
זה טוען את הגרסה החדשה, ובאופן ברירת המחדל שלה פורק את הישנה. אם אתה רוצה להתחיל להתאים אישית, אתה מוזמן להבין את הרכיבים שהוא יוצר באופן פנימי, וכיצד להגדיר אותם.
ראוי להזכיר כי TensorFlow Serving תוכנן מאפס להיות מאוד גמיש וניתן להרחבה. אתה יכול לבנות תוספים שונים כדי להתאים אישית את התנהגות המערכת, תוך ניצול רכיבי ליבה גנריים כמו ServerCore
ו- AspiredVersionsManager
. לדוגמה, אתה יכול לבנות תוסף מקור נתונים שמנטר אחסון בענן במקום אחסון מקומי, או שאתה יכול לבנות תוסף מדיניות גרסה שעושה מעבר גרסה בצורה אחרת -- למעשה, אתה יכול אפילו לבנות תוסף דגם מותאם אישית שמשרת דגמים שאינם TensorFlow. נושאים אלה אינם בהיקף של הדרכה זו. עם זאת, אתה יכול לעיין במקור המותאם אישית ובמדריכים המותאמים להגשה לקבלת מידע נוסף.
אצווה
תכונת שרת טיפוסית נוספת שאנו רוצים בסביבת ייצור היא אצווה. מאיצי חומרה מודרניים (GPU וכו') המשמשים להסקת למידת מכונה משיגים בדרך כלל את יעילות החישוב הטובה ביותר כאשר בקשות הסקת מסקנות מופעלות באצוות גדולות.
ניתן להפעיל אצווה על ידי מתן SessionBundleConfig
הולם בעת יצירת SavedModelBundleSourceAdapter
. במקרה זה אנו מגדירים את BatchingParameters
עם ערכי ברירת מחדל בערך. ניתן לכוונן עדין את האצווה על ידי הגדרת ערכי זמן קצוב מותאם אישית, batch_size וכו'. לפרטים, עיין ב- BatchingParameters
.
SessionBundleConfig session_bundle_config;
// Batching config
if (enable_batching) {
BatchingParameters* batching_parameters =
session_bundle_config.mutable_batching_parameters();
batching_parameters->mutable_thread_pool_name()->set_value(
"model_server_batch_threads");
}
*saved_model_bundle_source_adapter_config.mutable_legacy_config() =
session_bundle_config;
עם הגעת אצווה מלאה, בקשות הסקת מסקנות מתמזגות באופן פנימי לבקשה אחת גדולה (tensor), ו- tensorflow::Session::Run()
מופעל (שממנו מגיע רווח היעילות בפועל ב-GPUs).
מגישים עם מנהל
כפי שהוזכר לעיל, TensorFlow Serving Manager
נועד להיות רכיב גנרי שיכול להתמודד עם טעינה, הגשה, פריקה ומעבר גרסאות של מודלים שנוצרו על ידי מערכות למידת מכונה שרירותיות. ממשקי ה-API שלו בנויים סביב מושגי המפתח הבאים:
ניתן להגשה : ניתן להגשה הוא כל אובייקט אטום שניתן להשתמש בו כדי לשרת בקשות לקוח. הגודל והפירוט של חומר הגשה גמישים, כך שניתן להגשה אחד עשוי לכלול כל דבר, החל מרסיס בודד של טבלת חיפוש, לדגם אחד שנלמד על ידי מכונה ועד למספר דגמים. ניתן להגשה יכול להיות מכל סוג וממשק.
גרסה ניתנת להגשה : גירסה ניתנת להגשה ו- TensorFlow Serving
Manager
יכול לנהל גירסה אחת או יותר של גרסה ניתנת להגשה. גירסאות מאפשרות לטעון יותר מגרסה אחת של קובץ הגשה בו-זמנית, התומכת בהשקה הדרגתית ובניסויים.זרם ניתן להגשה : זרם שניתן להגשה הוא רצף הגרסאות של זרם שניתן להגשה, עם מספרי גרסאות הולכים וגדלים.
דגם : מודל שנלמד על ידי מכונה מיוצג על ידי חומר הגשה אחד או יותר. דוגמאות להגשה הן:
- הפעלה של TensorFlow או עטיפות סביבם, כגון
SavedModelBundle
. - סוגים אחרים של מודלים שנלמדו על ידי מכונה.
- טבלאות חיפוש אוצר מילים.
- הטמעת טבלאות חיפוש.
מודל מרוכב יכול להיות מיוצג כמספר רכיבים עצמאיים להגשה, או כרכיב מרוכב יחיד. ניתן להגשה עשוי להתאים גם לשבריר של מודל, למשל עם טבלת חיפוש גדולה המחולקת על פני מופעי
Manager
רבים.- הפעלה של TensorFlow או עטיפות סביבם, כגון
כדי לשים את כל אלה בהקשר של הדרכה זו:
דגמי TensorFlow מיוצגים על ידי סוג אחד של ניתן להגשה -
SavedModelBundle
.SavedModelBundle
מורכב באופן פנימי מ-tensorflow:Session
בשילוב עם כמה מטא נתונים לגבי איזה גרף נטען לתוך ההפעלה וכיצד להפעיל אותו להסקת הסקה.ישנה ספריית מערכת קבצים המכילה זרם של יצוא TensorFlow, כל אחד בספריית המשנה שלו ששמה הוא מספר גרסה. ניתן לחשוב על הספרייה החיצונית כייצוג סידורי של הזרם הניתן להגשה עבור מודל TensorFlow המוגש. כל ייצוא מתאים ל-servables שניתן לטעון.
AspiredVersionsManager
מפקח על זרם הייצוא ומנהל את מחזור החיים של כל רכיבי השרתSavedModelBundle
באופן דינמי.
TensorflowPredictImpl::Predict
אז רק:
- מבקש
SavedModelBundle
מהמנהל (דרך ServerCore). - משתמש
generic signatures
כדי למפות שמות טנסור לוגיים ב-PredictRequest
לשמות טנסור אמיתיים ולאגד ערכים לטנזורים. - מפעיל מסקנות.
בדוק והפעל את השרת
העתק את הגרסה הראשונה של הייצוא לתיקיה המנוטרת:
mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored
ואז הפעל את השרת:
docker run -p 8500:8500 \
--mount type=bind,source=/tmp/monitored,target=/models/mnist \
-t --entrypoint=tensorflow_model_server tensorflow/serving --enable_batching \
--port=8500 --model_name=mnist --model_base_path=/models/mnist &
השרת ישלח הודעות יומן בכל שנייה אחת שאומרות "גרסה שואפת להגשה...", כלומר הוא מצא את הייצוא ועוקב אחר המשך קיומו.
בוא נריץ את הלקוח עם --concurrency=10
. זה ישלח בקשות במקביל לשרת ובכך יפעיל את היגיון האצווה שלך.
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
--num_tests=1000 --server=127.0.0.1:8500 --concurrency=10
מה שמביא לפלט שנראה כך:
...
Inference error rate: 13.1%
לאחר מכן אנו מעתיקים את הגרסה השנייה של הייצוא לתיקיה המנוטרת ונפעיל מחדש את הבדיקה:
cp -r /tmp/mnist/2 /tmp/monitored
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
--num_tests=1000 --server=127.0.0.1:8500 --concurrency=10
מה שמביא לפלט שנראה כך:
...
Inference error rate: 9.5%
זה מאשר שהשרת שלך מגלה אוטומטית את הגרסה החדשה ומשתמש בה להגשה!