מסמך זה מסביר כיצד להרחיב את TensorFlow Serving עם סוג חדש של הגשה. סוג servable הבולט הוא SavedModelBundle
, אבל זה יכול להיות שימושי כדי להגדיר סוגים אחרים של servables, לשרת נתונים שהולכים יחד עם המודל שלך. דוגמאות כוללות: טבלת חיפוש אוצר מילים, לוגיקה של שינוי תכונות. כל C ++ בכיתה יכול להיות servable, למשל int
, std::map<string, int>
או כל מעמד מוגדר הבינארי - נכנה אותו YourServable
.
הגדרת Loader
ו SourceAdapter
עבור YourServable
כדי לאפשר TensorFlow הגשה לנהל ומגישים YourServable
, אתה צריך להגדיר שני דברים:
Loader
בכיתה שנטען, מספק גישה, ופורק מופע שלYourServable
.SourceAdapter
כי מעמיסי instantiates מכמה נתיבי מערכת קבצים למשל בפורמט נתונים בסיסי. כחלופה לSourceAdapter
, אתה יכול לכתוב שלםSource
. עם זאת, מאזSourceAdapter
הגישה נפוצה יותר ויותר מודולרי, אנו מתמקדים כאן.
Loader
ההפשטה מוגדרת core/loader.h
. זה דורש ממך להגדיר שיטות לטעינה, גישה ופריקה של סוג ההגשה שלך. הנתונים שמהם נטען ה-servable יכולים להגיע מכל מקום, אבל מקובל שהם מגיעים מנתיב מערכת אחסון. הבה נניח כי זהו המקרה עבור YourServable
. תן לנו עוד להניח שכבר יש לך Source<StoragePath>
כי אתה מרוצה (אם לא, לראות את המקור המותאם אישית מסמך).
בנוסף שלך Loader
, תצטרך להגדיר SourceAdapter
כי instantiates Loader
מנתיב אחסון נתון. רוב-דוגמאות פשוטות ניתן לציין שני האובייקטים תמציתי עם SimpleLoaderSourceAdapter
בכיתה (ב core/simple_loader.h
). שימוש-במקרים מתקדמים יכולים לבחור כדי לציין Loader
ו SourceAdapter
כיתות בנפרד באמצעות ממשקי API ברמה נמוכה יותר, למשל אם SourceAdapter
צריך לשמור על כמה המדינה, ו / או אם הצרכים המדינה להיות משותף בין Loader
מקרים.
ישנו יישום התייחסות של servable HashMap פשוטה המשתמשת SimpleLoaderSourceAdapter
ב servables/hashmap/hashmap_source_adapter.cc
. אתה עלול למצוא את זה נוח כדי ליצור עותק של HashmapSourceAdapter
ואז לשנות אותו כדי שיתאים לצרכים שלך.
יישום HashmapSourceAdapter
מורכב משני חלקים:
ההיגיון לטעון HashMap מקובץ, ב
LoadHashmapFromFile()
.שימוש
SimpleLoaderSourceAdapter
להגדירSourceAdapter
פולט HashMap מעמיס מבוסס עלLoadHashmapFromFile()
. החדשSourceAdapter
ניתן מופעים מהודעת פרוטוקול תצורת הסוגHashmapSourceAdapterConfig
. נכון לעכשיו, הודעת התצורה מכילה רק את פורמט הקובץ, ולצורך יישום הפניה נתמך רק פורמט פשוט יחיד.הערת קריאת
Detach()
ב וההורס. קריאה זו נדרשת כדי להימנע ממרוצים בין מצב הרס לבין כל קריאות מתמשכות של הבורא למבדה בשרשורים אחרים. (למרות שלמתאם המקור הפשוט הזה אין שום מצב, מחלקת הבסיס בכל זאת אוכפת שה-Detach() נקרא.)
הסדרת YourServable
מתנגד לטעון מנהל
הנה איך לחבר החדש שלך SourceAdapter
עבור YourServable
מעמיס למקור בסיסי של נתיבי אחסון, ואת המנהל (עם טיפול בשגיאות רע; קוד אמיתי צריך להיות יותר זהיר):
ראשית, צור מנהל:
std::unique_ptr<AspiredVersionsManager> manager = ...;
לאחר מכן, צור YourServable
מתאם מקור וחבר אותו המנהל:
auto your_adapter = new YourServableSourceAdapter(...);
ConnectSourceToTarget(your_adapter, manager.get());
לבסוף, צור מקור נתיב פשוט וחבר אותו למתאם שלך:
std::unique_ptr<FileSystemStoragePathSource> path_source;
// Here are some FileSystemStoragePathSource config settings that ought to get
// it working, but for details please see its documentation.
FileSystemStoragePathSourceConfig config;
// We just have a single servable stream. Call it "default".
config.set_servable_name("default");
config.set_base_path(FLAGS::base_path /* base path for our servable files */);
config.set_file_system_poll_wait_seconds(1);
TF_CHECK_OK(FileSystemStoragePathSource::Create(config, &path_source));
ConnectSourceToTarget(path_source.get(), your_adapter.get());
גישה טעון YourServable
עצמים
הנה איך להשיג ידית כדי טעון YourServable
, ולהשתמש בו:
auto handle_request = serving::ServableRequest::Latest("default");
ServableHandle<YourServable*> servable;
Status status = manager->GetServableHandle(handle_request, &servable);
if (!status.ok()) {
LOG(INFO) << "Zero versions of 'default' servable have been loaded so far";
return;
}
// Use the servable.
(*servable)->SomeYourServableMethod();
מתקדם: ארגון של מספר מופעים שניתנים להגשה לשיתוף מצב
מתאמי מקור יכולים להכיל מצב המשותף בין מספר שרתים שנפלטים. לדוגמה:
מאגר שרשורים משותף או משאב אחר שבו משתמשים רבים שניתן להגיש.
מבנה נתונים משותף לקריאה-בלבד שבו משתמשים רבים שניתן להגשה, כדי למנוע את הזמן והמקום של שכפול מבנה הנתונים בכל מופע שניתן להגשה.
מצב משותף שזמן האתחול שלו וגודלו זניחים (למשל בריכות שרשורים) יכול להיווצר בשקיקה על ידי ה-SourceAdapter, אשר לאחר מכן מטמיע אליו מצביע בכל מטעין הניתן להגשה שנפלט. יש לדחות את היצירה של מצב משותף יקר או גדול לקריאת Loader::Load() הרלוונטית הראשונה, כלומר מנוהלת על ידי המנהל. באופן סימטרי, הקריאה Loader::Unload() לשרת הסופי באמצעות המצב המשותף יקר/גדול אמורה להרוס אותו.