إنشاء نوع جديد من الخدمة

يشرح هذا المستند كيفية توسيع خدمة 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 بشكل منفصل باستخدام واجهات برمجة التطبيقات ذات المستوى الأدنى، على سبيل المثال، إذا كان SourceAdapter بحاجة إلى الاحتفاظ ببعض الحالة، و/أو إذا كانت الحالة بحاجة إلى المشاركة بين مثيلات Loader .

يوجد تطبيق مرجعي لخريطة تجزئة بسيطة قابلة للعرض تستخدم SimpleLoaderSourceAdapter في servables/hashmap/hashmap_source_adapter.cc . قد تجد أنه من المناسب عمل نسخة من HashmapSourceAdapter ثم تعديلها لتناسب احتياجاتك.

يتكون تنفيذ HashmapSourceAdapter من جزأين:

  1. منطق تحميل hashmap من ملف في LoadHashmapFromFile() .

  2. استخدام 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();

متقدم: ترتيب مثيلات متعددة قابلة للعرض لمشاركة الحالة

يمكن لـ SourceAdapters أن يضم الحالة المشتركة بين العديد من العناصر القابلة للخدمة المنبعثة. على سبيل المثال:

  • تجمع مؤشرات الترابط المشتركة أو الموارد الأخرى التي تستخدمها العديد من الخدمات.

  • بنية بيانات مشتركة للقراءة فقط تستخدمها العديد من العناصر القابلة للعرض، لتجنب الوقت والمساحة الزائدة لتكرار بنية البيانات في كل مثيل قابل للعرض.

الحالة المشتركة التي يكون وقت وحجم التهيئة لا يكاد يذكر (على سبيل المثال تجمعات الخيوط) يمكن إنشاؤها بفارغ الصبر بواسطة SourceAdapter، والذي يقوم بعد ذلك بتضمين مؤشر لها في كل محمل قابل للعرض. يجب تأجيل إنشاء حالة مشتركة مكلفة أو كبيرة إلى أول استدعاء قابل للتطبيق Loader::Load()، أي يحكمه المدير. بشكل متماثل، يجب أن يؤدي استدعاء Loader::Unload() إلى الخدمة النهائية القابلة للعرض باستخدام الحالة المشتركة الباهظة الثمن/الكبيرة إلى تدميرها.