يشرح هذا المستند كيفية توسيع خدمة 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
بشكل منفصل باستخدام واجهات برمجة التطبيقات ذات المستوى الأدنى، على سبيل المثال، إذا كان SourceAdapter
بحاجة إلى الاحتفاظ ببعض الحالة، و/أو إذا كانت الحالة بحاجة إلى المشاركة بين مثيلات Loader
.
يوجد تطبيق مرجعي لخريطة تجزئة بسيطة قابلة للعرض تستخدم 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();
متقدم: ترتيب مثيلات متعددة قابلة للعرض لمشاركة الحالة
يمكن لـ SourceAdapters أن يضم الحالة المشتركة بين العديد من العناصر القابلة للخدمة المنبعثة. على سبيل المثال:
تجمع مؤشرات الترابط المشتركة أو الموارد الأخرى التي تستخدمها العديد من الخدمات.
بنية بيانات مشتركة للقراءة فقط تستخدمها العديد من العناصر القابلة للعرض، لتجنب الوقت والمساحة الزائدة لتكرار بنية البيانات في كل مثيل قابل للعرض.
الحالة المشتركة التي يكون وقت وحجم التهيئة لا يكاد يذكر (على سبيل المثال تجمعات الخيوط) يمكن إنشاؤها بفارغ الصبر بواسطة SourceAdapter، والذي يقوم بعد ذلك بتضمين مؤشر لها في كل محمل قابل للعرض. يجب تأجيل إنشاء حالة مشتركة مكلفة أو كبيرة إلى أول استدعاء قابل للتطبيق Loader::Load()، أي يحكمه المدير. بشكل متماثل، يجب أن يؤدي استدعاء Loader::Unload() إلى الخدمة النهائية القابلة للخدمة باستخدام الحالة المشتركة الباهظة الثمن/الكبيرة إلى تدميرها.