بناء نموذج TensorFlow ModelServer

يوضح لك هذا البرنامج التعليمي كيفية استخدام مكونات TensorFlow Serving لإنشاء TensorFlow ModelServer القياسي الذي يكتشف الإصدارات الجديدة من نموذج TensorFlow المدرب ويخدمها ديناميكيًا. إذا كنت تريد فقط استخدام الخادم القياسي لخدمة نماذجك، فراجع البرنامج التعليمي الأساسي لخدمة TensorFlow .

يستخدم هذا البرنامج التعليمي نموذج انحدار Softmax البسيط الذي تم تقديمه في البرنامج التعليمي TensorFlow لتصنيف الصور المكتوبة بخط اليد (بيانات MNIST). إذا كنت لا تعرف ما هو TensorFlow أو MNIST، فراجع البرنامج التعليمي MNIST For ML Beginners .

يتكون رمز هذا البرنامج التعليمي من جزأين:

  • ملف Python mnist_saved_model.py الذي يقوم بتدريب وتصدير إصدارات متعددة من النموذج.

  • ملف C++ main.cc وهو TensorFlow ModelServer القياسي الذي يكتشف النماذج المصدرة الجديدة ويدير خدمة gRPC لخدمتها.

يمر هذا البرنامج التعليمي بالمهام التالية:

  1. تدريب وتصدير نموذج TensorFlow.
  2. إدارة إصدارات النموذج باستخدام TensorFlow Serving ServerCore .
  3. قم بتكوين الدفعات باستخدام SavedModelBundleSourceAdapterConfig .
  4. خدمة الطلب مع TensorFlow Serving ServerCore .
  5. تشغيل واختبار الخدمة.

قبل البدء، قم أولاً بتثبيت Docker

تدريب وتصدير نموذج TensorFlow

أولاً، إذا لم تكن قد قمت بذلك بعد، فقم باستنساخ هذا المستودع على جهازك المحلي:

git clone https://github.com/tensorflow/serving.git
cd serving

امسح دليل التصدير إذا كان موجودًا بالفعل:

rm -rf /tmp/models

تدريب (مع 100 تكرار) وتصدير الإصدار الأول من النموذج:

tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
  --training_iteration=100 --model_version=1 /tmp/mnist

تدريب (مع تكرارات 2000) وتصدير الإصدار الثاني من النموذج:

tools/run_in_docker.sh python tensorflow_serving/example/mnist_saved_model.py \
  --training_iteration=2000 --model_version=2 /tmp/mnist

كما ترون في mnist_saved_model.py ، يتم التدريب والتصدير بنفس الطريقة التي يتم بها البرنامج التعليمي الأساسي لـ TensorFlow Serving . لأغراض العرض التوضيحي، أنت تقوم عن قصد بطلب تكرارات التدريب للتشغيل الأول وتصديرها كـ v1، أثناء تدريبها بشكل طبيعي للتشغيل الثاني وتصديرها كـ v2 إلى نفس الدليل الأصلي - كما نتوقع أن يحقق الأخير دقة تصنيف أفضل بسبب التدريب المكثف. يجب أن تشاهد بيانات التدريب لكل تدريب يتم تشغيله في الدليل /tmp/mnist الخاص بك:

$ ls /tmp/mnist
1  2

ServerCore

الآن تخيل أن الإصدارين 1 و2 من النموذج يتم إنشاؤهما ديناميكيًا في وقت التشغيل، أثناء تجربة خوارزميات جديدة، أو أثناء تدريب النموذج باستخدام مجموعة بيانات جديدة. في بيئة الإنتاج، قد ترغب في إنشاء خادم يمكنه دعم الطرح التدريجي، حيث يمكن اكتشاف الإصدار 2 أو تحميله أو تجربته أو مراقبته أو إرجاعه أثناء تقديم الإصدار 1. وبدلاً من ذلك، قد ترغب في إزالة الإصدار 1 قبل ذكر الإصدار 2. يدعم TensorFlow Serving كلا الخيارين - فبينما يكون أحدهما مفيدًا للحفاظ على التوفر أثناء عملية النقل، فإن الآخر مفيد لتقليل استخدام الموارد (مثل ذاكرة الوصول العشوائي).

Manager خدمة TensorFlow يفعل ذلك بالضبط. إنه يتعامل مع دورة الحياة الكاملة لنماذج TensorFlow بما في ذلك تحميلها وتقديمها وتفريغها بالإضافة إلى انتقالات الإصدار. في هذا البرنامج التعليمي، ستبني خادمك فوق TensorFlow Serving ServerCore ، والذي يغلف AspiredVersionsManager داخليًا.

int main(int argc, char** argv) {
  ...

  ServerCore::Options options;
  options.model_server_config = model_server_config;
  options.servable_state_monitor_creator = &CreateServableStateMonitor;
  options.custom_model_config_loader = &LoadCustomModelConfig;

  ::google::protobuf::Any source_adapter_config;
  SavedModelBundleSourceAdapterConfig
      saved_model_bundle_source_adapter_config;
  source_adapter_config.PackFrom(saved_model_bundle_source_adapter_config);
  (*(*options.platform_config_map.mutable_platform_configs())
      [kTensorFlowModelPlatform].mutable_source_adapter_config()) =
      source_adapter_config;

  std::unique_ptr<ServerCore> core;
  TF_CHECK_OK(ServerCore::Create(options, &core));
  RunServer(port, std::move(core));

  return 0;
}

يأخذ ServerCore::Create() معلمة ServerCore::Options. فيما يلي بعض الخيارات الشائعة الاستخدام:

  • ModelServerConfig الذي يحدد النماذج التي سيتم تحميلها. يتم الإعلان عن النماذج إما من خلال model_config_list ، الذي يعلن عن قائمة ثابتة من النماذج، أو من خلال custom_model_config ، الذي يحدد طريقة مخصصة للإعلان عن قائمة النماذج التي قد يتم تحديثها في وقت التشغيل.
  • PlatformConfigMap الذي يعين اسم النظام الأساسي (مثل tensorflow ) إلى PlatformConfig ، والذي يُستخدم لإنشاء SourceAdapter . يقوم SourceAdapter بتكييف StoragePath (المسار الذي يتم فيه اكتشاف إصدار النموذج) مع Model Loader (يقوم بتحميل إصدار النموذج من مسار التخزين ويوفر واجهات انتقال الحالة إلى Manager ). إذا كان PlatformConfig يحتوي على SavedModelBundleSourceAdapterConfig ، فسيتم إنشاء SavedModelBundleSourceAdapter ، وهو ما سنشرحه لاحقًا.

يعد SavedModelBundle أحد المكونات الرئيسية لخدمة TensorFlow. إنه يمثل نموذج TensorFlow الذي تم تحميله من مسار معين ويوفر نفس Session::Run مثل TensorFlow لتشغيل الاستدلال. يقوم SavedModelBundleSourceAdapter بتكييف مسار التخزين مع Loader<SavedModelBundle> بحيث يمكن إدارة عمر النموذج بواسطة Manager . يرجى ملاحظة أن SavedModelBundle هو خليفة SessionBundle المهمل. يتم تشجيع المستخدمين على استخدام SavedModelBundle حيث سيتم قريبًا إزالة دعم SessionBundle .

مع كل هذه الأمور، يقوم ServerCore داخليًا بما يلي:

  • إنشاء مثيل FileSystemStoragePathSource الذي يراقب مسارات تصدير النموذج المعلنة في model_config_list .
  • إنشاء مثيل SourceAdapter باستخدام PlatformConfigMap مع النظام الأساسي النموذجي المعلن في model_config_list وتوصيل FileSystemStoragePathSource به. بهذه الطريقة، كلما تم اكتشاف إصدار نموذج جديد ضمن مسار التصدير، يقوم SavedModelBundleSourceAdapter بتكييفه مع Loader<SavedModelBundle> .
  • إنشاء مثيل لتطبيق محدد Manager يسمى AspiredVersionsManager الذي يدير جميع مثيلات Loader التي تم إنشاؤها بواسطة SavedModelBundleSourceAdapter . يقوم ServerCore بتصدير واجهة Manager عن طريق تفويض الاستدعاءات إلى AspiredVersionsManager .

عندما يتوفر إصدار جديد، يقوم AspiredVersionsManager بتحميل الإصدار الجديد، ويقوم بإلغاء تحميل الإصدار القديم ضمن سلوكه الافتراضي. إذا كنت تريد البدء في التخصيص، فنحن نشجعك على فهم المكونات التي يتم إنشاؤها داخليًا وكيفية تكوينها.

ومن الجدير بالذكر أن TensorFlow Serving تم تصميمه من الصفر ليكون مرنًا للغاية وقابل للتوسيع. يمكنك إنشاء العديد من المكونات الإضافية لتخصيص سلوك النظام، مع الاستفادة من المكونات الأساسية العامة مثل ServerCore و AspiredVersionsManager . على سبيل المثال، يمكنك إنشاء مكون إضافي لمصدر البيانات يراقب التخزين السحابي بدلاً من التخزين المحلي، أو يمكنك إنشاء مكون إضافي لسياسة الإصدار يقوم بنقل الإصدار بطريقة مختلفة - في الواقع، يمكنك أيضًا إنشاء مكون إضافي لنموذج مخصص يخدم نماذج غير TensorFlow. هذه المواضيع خارج نطاق هذا البرنامج التعليمي. ومع ذلك، يمكنك الرجوع إلى المصدر المخصص والبرامج التعليمية المخصصة القابلة للعرض لمزيد من المعلومات.

الخلط

ميزة الخادم النموذجية الأخرى التي نريدها في بيئة الإنتاج هي التجميع. عادةً ما تحقق مسرعات الأجهزة الحديثة (وحدات معالجة الرسومات، وما إلى ذلك) المستخدمة في استدلال التعلم الآلي أفضل كفاءة حسابية عند تشغيل طلبات الاستدلال على دفعات كبيرة.

يمكن تشغيل عملية الدفع عن طريق توفير SessionBundleConfig المناسب عند إنشاء SavedModelBundleSourceAdapter . في هذه الحالة قمنا بتعيين BatchingParameters بقيم افتراضية إلى حد كبير. يمكن ضبط عملية الدفع عن طريق تعيين قيم المهلة المخصصة وحجم الدفعة وما إلى ذلك. لمزيد من التفاصيل، يرجى الرجوع إلى BatchingParameters .

SessionBundleConfig session_bundle_config;
// Batching config
if (enable_batching) {
  BatchingParameters* batching_parameters =
      session_bundle_config.mutable_batching_parameters();
  batching_parameters->mutable_thread_pool_name()->set_value(
      "model_server_batch_threads");
}
*saved_model_bundle_source_adapter_config.mutable_legacy_config() =
    session_bundle_config;

عند الوصول إلى الدفعة الكاملة، يتم دمج طلبات الاستدلال داخليًا في طلب واحد كبير (الموتر)، ويتم استدعاء tensorflow::Session::Run() (وهو المكان الذي تأتي منه زيادة الكفاءة الفعلية على وحدات معالجة الرسومات).

يخدم مع المدير

كما هو مذكور أعلاه، تم تصميم TensorFlow Serving Manager ليكون مكونًا عامًا يمكنه التعامل مع تحميل النماذج التي تم إنشاؤها بواسطة أنظمة التعلم الآلي التعسفية، وتقديمها، وتفريغها، ونقل إصدارها. تم بناء واجهات برمجة التطبيقات الخاصة به حول المفاهيم الأساسية التالية:

  • Servable : Servable هو أي كائن غير شفاف يمكن استخدامه لخدمة طلبات العميل. يتسم حجم ومستوى التفاصيل القابلة للعرض بالمرونة، بحيث يمكن أن تتضمن الخدمة الفردية القابلة للعرض أي شيء بدءًا من جزء واحد من جدول البحث إلى نموذج واحد يتم تعلمه آليًا إلى مجموعة من النماذج. يمكن أن يكون العرض من أي نوع وواجهة.

  • الإصدار القابل للعرض : يتم إصدار الإصدارات القابلة للعرض ويمكن Manager خدمة TensorFlow إدارة إصدار واحد أو أكثر من الإصدارات القابلة للعرض. يسمح تعيين الإصدار بتحميل أكثر من إصدار واحد للخدمة بشكل متزامن، مما يدعم التشغيل التدريجي والتجريب.

  • الدفق القابل للعرض : الدفق القابل للعرض هو تسلسل إصدارات قابل للعرض، مع أرقام الإصدارات المتزايدة.

  • النموذج : يتم تمثيل نموذج التعلم الآلي بواسطة واحد أو أكثر من العناصر القابلة للعرض. أمثلة على العناصر القابلة للعرض هي:

    • جلسة TensorFlow أو الأغلفة المحيطة بها، مثل SavedModelBundle .
    • أنواع أخرى من نماذج التعلم الآلي.
    • جداول البحث عن المفردات
    • تضمين جداول البحث.

    يمكن تمثيل النموذج المركب على هيئة العديد من العناصر القابلة للعرض المستقلة، أو كنموذج مركب واحد قابل للعرض. قد يتوافق أيضًا العرض القابل للعرض مع جزء من النموذج، على سبيل المثال مع جدول بحث كبير مقسم عبر العديد من مثيلات Manager .

لوضع كل هذا في سياق هذا البرنامج التعليمي:

  • يتم تمثيل نماذج TensorFlow بنوع واحد قابل للعرض - SavedModelBundle . يتكون SavedModelBundle داخليًا من tensorflow:Session مقترنًا ببعض البيانات التعريفية حول الرسم البياني الذي تم تحميله في الجلسة وكيفية تشغيله للاستدلال.

  • يوجد دليل نظام ملفات يحتوي على دفق من صادرات TensorFlow، كل منها في دليل فرعي خاص بها واسمها هو رقم الإصدار. يمكن اعتبار الدليل الخارجي بمثابة تمثيل متسلسل للتدفق القابل للعرض لنموذج TensorFlow الذي يتم تقديمه. تتوافق كل عملية تصدير مع العناصر القابلة للخدمة التي يمكن تحميلها.

  • يراقب AspiredVersionsManager تدفق التصدير، ويدير دورة حياة جميع العناصر القابلة للخدمة SavedModelBundle بشكل ديناميكي.

TensorflowPredictImpl::Predict ثم فقط:

  • يطلب SavedModelBundle من المدير (من خلال ServerCore).
  • يستخدم generic signatures لتعيين أسماء الموتر المنطقية في PredictRequest لأسماء الموتر الحقيقية وربط القيم بالموترات.
  • يدير الاستدلال.

اختبار وتشغيل الخادم

انسخ الإصدار الأول من التصدير إلى المجلد المراقب:

mkdir /tmp/monitored
cp -r /tmp/mnist/1 /tmp/monitored

ثم قم بتشغيل الخادم:

docker run -p 8500:8500 \
  --mount type=bind,source=/tmp/monitored,target=/models/mnist \
  -t --entrypoint=tensorflow_model_server tensorflow/serving --enable_batching \
  --port=8500 --model_name=mnist --model_base_path=/models/mnist &

سيرسل الخادم رسائل سجل كل ثانية تقول "إصدار طموح للعرض ..."، مما يعني أنه عثر على التصدير، ويقوم بتتبع وجوده المستمر.

لنقم بتشغيل العميل باستخدام --concurrency=10 . سيؤدي هذا إلى إرسال طلبات متزامنة إلى الخادم وبالتالي تشغيل منطق الدفع الخاص بك.

tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
  --num_tests=1000 --server=127.0.0.1:8500 --concurrency=10

مما يؤدي إلى إخراج يبدو كالتالي:

...
Inference error rate: 13.1%

ثم ننسخ الإصدار الثاني من التصدير إلى المجلد المراقب ونعيد تشغيل الاختبار:

cp -r /tmp/mnist/2 /tmp/monitored
tools/run_in_docker.sh python tensorflow_serving/example/mnist_client.py \
  --num_tests=1000 --server=127.0.0.1:8500 --concurrency=10

مما يؤدي إلى إخراج يبدو كالتالي:

...
Inference error rate: 9.5%

وهذا يؤكد أن خادمك يكتشف تلقائيًا الإصدار الجديد ويستخدمه للعرض!