این سند نحوه گسترش سرویس TensorFlow را با نوع جدیدی از سرویس پذیر توضیح می دهد. برجسته ترین نوع قابل سرویس دهی SavedModelBundle
است، اما تعریف انواع دیگری از سرویس پذیرها، برای ارائه داده هایی که با مدل شما مطابقت دارند، می تواند مفید باشد. مثالها عبارتند از: جدول جستجوی واژگان، منطق تبدیل ویژگی. هر کلاس C++ می تواند یک سرویس پذیر باشد، به عنوان مثال int
، std::map<string, int>
یا هر کلاسی که در باینری شما تعریف شده است - اجازه دهید آن را YourServable
بنامیم.
تعریف Loader
و SourceAdapter
برای YourServable
برای فعال کردن TensorFlow Serving برای مدیریت و سرویس YourServable
، باید دو چیز را تعریف کنید:
یک کلاس
Loader
که یک نمونه ازYourServable
را بارگیری می کند، به آن دسترسی می دهد و آن را تخلیه می کند.یک
SourceAdapter
که لودرها را از برخی قالبهای دادههای زیرین نمونهسازی میکند، بهعنوان مثال مسیرهای سیستم فایل. به عنوان جایگزینی برایSourceAdapter
، می توانید یکSource
کامل بنویسید. با این حال، از آنجایی که رویکردSourceAdapter
رایجتر و مدولارتر است، ما در اینجا روی آن تمرکز میکنیم.
انتزاع Loader
در core/loader.h
تعریف شده است. از شما میخواهد تا روشهایی را برای بارگیری، دسترسی و تخلیه نوع سرویسدهی خود تعریف کنید. دادههایی که سرویسپذیر از آن بارگیری میشود، میتواند از هر جایی باشد، اما معمولاً از مسیر سیستم ذخیرهسازی میآید. اجازه دهید فرض کنیم که این مورد برای YourServable
است. اجازه دهید فرض کنیم که شما از قبل یک Source<StoragePath>
دارید که از آن راضی هستید (اگر نه، به سند منبع سفارشی مراجعه کنید).
علاوه بر Loader
خود، باید یک SourceAdapter
تعریف کنید که یک Loader
از یک مسیر ذخیره سازی داده شده نمونه برداری می کند. اکثر موارد استفاده ساده می توانند دو شی را به طور خلاصه با کلاس SimpleLoaderSourceAdapter
(در core/simple_loader.h
) مشخص کنند. موارد استفاده پیشرفته ممکن است انتخاب کنند که کلاس های Loader
و SourceAdapter
را به طور جداگانه با استفاده از API های سطح پایین تر مشخص کنند، به عنوان مثال اگر SourceAdapter
نیاز به حفظ برخی وضعیت ها داشته باشد، و/یا اگر حالت نیاز به اشتراک گذاری بین نمونه های Loader
داشته باشد.
یک پیادهسازی مرجع از یک hashmap خدمتپذیر ساده وجود دارد که از SimpleLoaderSourceAdapter
در servables/hashmap/hashmap_source_adapter.cc
استفاده میکند. ممکن است برای شما راحت باشد که از HashmapSourceAdapter
کپی کنید و سپس آن را مطابق با نیاز خود تغییر دهید.
پیاده سازی HashmapSourceAdapter
دارای دو بخش است:
منطق بارگیری نقشه هاشمپ از یک فایل، در
LoadHashmapFromFile()
.استفاده از
SimpleLoaderSourceAdapter
برای تعریفSourceAdapter
که لودرهای hashmap را بر اساسLoadHashmapFromFile()
منتشر می کند.SourceAdapter
جدید را می توان از یک پیام پروتکل پیکربندی از نوعHashmapSourceAdapterConfig
نمونه سازی کرد. در حال حاضر، پیام پیکربندی فقط شامل فرمت فایل است و برای اجرای مرجع فقط یک قالب ساده پشتیبانی می شود.به فراخوانی
Detach()
در Destructor توجه کنید. این فراخوان برای اجتناب از مسابقه بین حالت تخریب و هرگونه فراخوانی مداوم از لامبدای خالق در رشتههای دیگر لازم است. (اگرچه این آداپتور منبع ساده هیچ حالتی ندارد، با این وجود کلاس پایه باعث میشود که 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();
پیشرفته: ترتیب چندین نمونه قابل سرویس برای اشتراک گذاری حالت
SourceAdapters میتواند حالتی را در خود جای دهد که بین چندین سرویس منتشر شده مشترک است. به عنوان مثال:
یک مخزن رشته مشترک یا منبع دیگری که چندین سرویسپذیر از آن استفاده میکنند.
یک ساختار داده مشترک فقط خواندنی که چندین سرویسپذیر از آن استفاده میکنند تا از سربار زمان و مکان تکرار ساختار داده در هر نمونه قابل سرویسگیری جلوگیری شود.
حالت مشترکی که زمان و اندازه اولیه آن ناچیز است (مثلاً thread pools) میتواند مشتاقانه توسط SourceAdapter ایجاد شود، که سپس یک اشارهگر به آن در هر بارکننده قابل ارائه منتشر شده تعبیه میکند. ایجاد حالت اشتراکی گران یا بزرگ باید به اولین تماس Loader::Load() قابل اجرا موکول شود، یعنی توسط مدیر اداره می شود. به طور متقارن، فراخوانی Loader::Unload به سرویسپذیر نهایی با استفاده از حالت اشتراکگذاری شده گران/بزرگ، باید آن را از بین ببرد.