ایجاد نوع جدیدی از سرویس پذیر

این سند نحوه گسترش سرویس TensorFlow را با نوع جدیدی از سرویس پذیر توضیح می دهد. برجسته ترین نوع قابل سرویس دهی SavedModelBundle است، اما تعریف انواع دیگری از سرویس پذیرها، برای ارائه داده هایی که با مدل شما مطابقت دارند، می تواند مفید باشد. مثال‌ها عبارتند از: جدول جستجوی واژگان، منطق تبدیل ویژگی. هر کلاس C++ می تواند یک سرویس پذیر باشد، به عنوان مثال int ، std::map<string, int> یا هر کلاسی که در باینری شما تعریف شده است - اجازه دهید آن را YourServable بنامیم.

تعریف Loader و SourceAdapter برای YourServable

برای فعال کردن TensorFlow Serving برای مدیریت و سرویس YourServable ، باید دو چیز را تعریف کنید:

  1. یک کلاس Loader که یک نمونه از YourServable را بارگیری می کند، به آن دسترسی می دهد و آن را تخلیه می کند.

  2. یک 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 دارای دو بخش است:

  1. منطق بارگیری نقشه هاشمپ از یک فایل، در LoadHashmapFromFile() .

  2. استفاده از 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 به سرویس‌پذیر نهایی با استفاده از حالت اشتراک‌گذاری شده گران/بزرگ، باید آن را از بین ببرد.