```html AntBatchInfer: الاستدلال الدفعي المرن في مجموعة Kubernetes

AntBatchInfer: الاستدلال الدفعي المرن في مجموعة Kubernetes

Siyuan Li, Youshao Xiao, Fanzhuang Meng, Lin Ju, Lei Liang, Lin Wang, Jun Zhou

مُلخّص

الاستدلال الدفعي غير المتصل هو مهمة شائعة في الصناعة لتطبيقات التعلم العميق، ولكن قد يكون من الصعب ضمان الاستقرار والأداء عند التعامل مع كميات كبيرة من البيانات وأنابيب استدلال معقدة. تقدم هذه الورقة AntBatchInfer، وهو إطار عمل للاستدلال الدفعي المرن، تم تحسينه خصيصًا للمجموعات غير المخصصة. يعالج AntBatchInfer هذه التحديات من خلال توفير قدرات متعددة المستويات لتحمّل الأعطال، مما يمكّن من تنفيذ مهام الاستدلال المتنوّعة وطويلة الأمد بثبات. كما يعزّز كفاءة الاستدلال عبر التشغيل الأنبوبي والتوسع داخل العقدة وبينها. يعمل الإطار أيضًا على تحسين الأداء في سيناريوهات الاستدلال الدفعي المعقدة للنماذج المتعددة. من خلال تجارب مكثفة وقياسات واقعية، نظهر تفوّق إطار عملنا من حيث الاستقرار والكفاءة. في التجربة، تفوّق على الأساس بما لا يقل عن 2\( \times \) في استدلال النموذج الفردي وحوالي 6\( \times \) في استدلال النماذج المتعددة. كما أنه يُستخدم على نطاق واسع داخل عنقود Ant، مع آلاف الوظائف اليومية في سيناريوهات متنوعة، بما في ذلك DLRM، وCV، وNLP، مما يبرهن على قابليته للتطبيق في الصناعة.

المقدمة

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

للأسف، معظم الأعمال والأنظمة الحالية مكرّسة للاستدلال المتصل، في حين نادرًا ما تتناول الأعمال منهجية استدلال الدُفعات في الإنتاج، رغم أهميته للتطبيقات الصناعية. إحدى الطرق المباشرة هي تطبيق خط أنابيب الاستدلال المتصل على مهام الدُفعات. ومع ذلك، فإن استدلال الدُفعات له خصائص فريدة تميّزه عن الاستدلال المتصل، مثل أحمال العمل الضخمة غير الحساسة للزمن ومتطلبات التحكم في التكلفة (azure_batch_infer). على سبيل المثال، قد تصل البيانات المطلوب معالجتها إلى تيرابايت في بيئات الإنتاج. وهناك طريقة أخرى تعتمد على أنظمة معالجة الدُفعات مثل MapReduce وSpark، التي تستطيع معالجة مجموعات بيانات ضخمة مع ضمان الكفاءة وتحمل الأخطاء. إلا أنها لا تناسب جيدًا استدلال النماذج الكبيرة أو المعقدة. على سبيل المثال، غالبًا ما تحتاج نماذج التوصية العميقة إلى توزيع معلمات كبيرة ونادرة عبر عدة خوادم للمعلمات (li2014scaling). علاوة على ذلك، الأنظمة المستندة إلى MapReduce تفتقر إلى المرونة عند تنفيذ خطوط أنابيب استدلال متعددة النماذج المعقدة ذات مستويات تعقيد متباينة. لذلك، يبدو الحلّ الأمثل هو تشغيل هذه النماذج في عنقود حاويات مثل Kubernetes.

ومع ذلك، تواجه أنظمة استدلال الدُفعات الحالية في Kubernetes مشكلتين رئيسيتين: الاستقرار (تحمّل الأخطاء) والكفاءة. النهج التقليدي يقوم على توزيع مجموعة البيانات بالتساوي بين العمال في الحاويات ومعالجة الحسابات بشكل موازٍ للبيانات. أولًا، تحمّل الأخطاء أمر أساسي في استدلال الدُفعات في العناقيد غير المخصصة (أو المشتركة)، حيث قد يقوم المجدول بإخلاء الحاويات لتلبية اتفاقيات مستوى الخدمة للوظائف الحساسة (bernstein2014containers). بينما توفر معظم خدمات استدلال الدُفعات السحابية (aws_sagemaker, vertex_inference) تحمّل أخطاء على مستوى الحاوية ومرونة داخل العقدة (توسيع/تقليص ديناميكي)، فإنها لا تتعامل مع تحمّل الأخطاء على مستوى التطبيق في وقت التشغيل، كأخطاء التحميل أو انتهاء المهلة. ثانيًا، لا تستفيد هذه الأنظمة استفادة كاملة من الموارد الحاسوبية، خاصة في سيناريوهات استدلال النماذج المتعددة أو أساليب التجزئة. فعلى سبيل المثال، يؤدي تخصيص وحدة معالجة الرسومات لكل عملية استدلال إلى هدر الموارد عندما يكون النموذج بسيطًا. كما في سيناريو استدلال متعدد النماذج، مثل التعرف على الوجه، يتطلب تدفق عملين: مرحلة اكتشاف الكائنات متبوعة بمرحلة تصنيف الصور. لكن في الأنظمة الحالية، مثل Azure Batch (azure_batch_infer) وVertex من Google (vertex_inference)، يتم دمج النموذجين في نفس المتنبئ، رغم اختلاف أحمال العمل بينهما.

لذلك، نُقدّم نظام استدلال الدُفعات المبني على Kubernetes الذي يعالج منهجيًا مشكلات الاستقرار والأداء من منظور الإطار. أولًا، صممنا آلية تحمّل عالية الدقة لضمان الاستقرار على امتداد خط أنابيب الاستدلال. ثانيًا، نقترح أنابيب تستفيد من الموارد الحاسوبية بالكامل مع التوسع داخل العقدة وعبر العقد لكل من الاستدلال بنموذج واحد ومتعدد. أخيرًا، نقدم واجهة استخدام بسيطة متكاملة مع واجهات خلفية متعددة، ونُثبت تفوّق نظامنا في الاستقرار والكفاءة من خلال تجارب مكثفة.

تحليل المشكلة

لنأخذ في الاعتبار خط أنابيب الاستدلال الدُفعي النموذجي الذي يتكوّن من استيعاب البيانات، تجهيزها، استدلال النموذج، ثم حفظ النتائج. تقرأ وحدة استيعاب البيانات العينات من مصادر متعددة مثل تخزين الكائنات وقواعد البيانات. ثم تعالج وحدة تجهيز البيانات هذه العينات، بتنفيذ مهام مثل الترميز في معالجة اللغات الطبيعية أو تعزير البيانات في رؤية الحاسوب، يليها استدلال النموذج. أخيرًا، تُحفظ نتائج التنبؤ في نظام التخزين لاستخدامها في التطبيقات اللاحقة. عادةً ما يحتفظ الاستدلال الدُفعي الموزّع بنسخة كاملة من معلمات النموذج في كل عقدة وينفّذ الاستدلال على أجزاء البيانات الموزعة مسبقًا.

دعونا نحلّل أكثر المشكلات المتعلقة بالاستقرار والكفاءة عبر هذا الخط. من ناحية الاستقرار، هناك خطر كبير بفشل الوظائف طويلة الأمد، مما يسبب محاولات إعادة تشغيل متكررة. وهذا يؤثر سلبًا على كفاءة الاستدلال، لاسيما في العناقيد المشتركة. نصنّف هذه الأخطاء إلى ثلاث فئات: أخطاء على مستوى الحاوية، أخطاء التطبيق، وأخطاء البيانات. أولًا، تُعزى أخطاء الحاوية إلى إخفاق الأجهزة، ومشكلات I/O، واستبعاد الحاويات. ثانيًا، قد تواجه تطبيقات التعلم العميق أخطاء أثناء معالجة مجموعات البيانات الكبيرة، مثل قيم NaN في العينات، أو أخطاء التحليل، أو العمليات المعلقة. هذه الأخطاء شائعة في مختلف مراحل الخط، لكنها تختلف عن أخطاء الحاوية لأنها لا تتطلب استبدال الحاوية. ثالثًا، يجب تصميم تحمّل أخطاء البيانات بعناية، حتى لا تَضيع عينات أو تتكرر عند معالجة الاستبدالات، ما قد يضرّ بسلامة البيانات.

كما أنّ تصميم النظام الحالي يطرح تحديات في تحقيق الأداء الأمثل لمهام الاستدلال الدُفعي. أولًا، الوحدات المكثفة للإدخال/الإخراج مثل الاستيعاب وإعادة الكتابة تثقل كاهل I/O، بينما تجهيز البيانات واستدلال النموذج مكثّفان للحساب، ولكل منهما موارد مميزة؛ فاستدلال النموذج يتركز عادةً على GPU وتجهير البيانات على CPU. لذا من غير الفعّال تجميع هذه الوحدات المختلطة في حاوية واحدة، حيث قد يصبح الأنبوب عنق الزجاجة. ثانيًا، في سيناريوهات استدلال النماذج المتعددة، تختلف تعقيدات النماذج بشكل كبير، ومن غير الفعّال حشرها في نفس الوحدة. ثالثًا، عادةً ما يتم تنفيذ الاستدلال الدُفعي على عناقيد غير مخصصة، حيث قد تظهر متخلفات بيضاء بسبب تنافس التطبيقات على الموارد في أوقات الذروة. وهذا يولّد مشكلة الذيل الطويل، إذ حتى توزيع البيانات المتساوي يؤدي لانتظار الحاويات الأبطأ، ما يحدد وقت الانتهاء بوحدة العقدة الأبطأ. أخيرًا، يمكن الاستفادة من الموارد الفارغة في العناقيد خلال فترات انخفاض الحمل لتسريع المهام الدُفعيّة.

إطار عملنا

هندسة الإطار

لضمان استقرار وكفاءة الاستدلال الدُفعي، نقترح إطار عمل AntBatchInfer. كما هو موضّح في الشكل [fig:arch]، يتكوّن الإطار من أربع وحدات: خدمة تقسيم البيانات الحافظة للحالة (Stateful DDS)، معالج البيانات، المتحكّم المرن، وجدولة المتنبّئ المرن. استندنا في التصميم إلى معماريّة السيد-العامل، حيث تعمل خدمة تقسيم البيانات الحافظة للحالة والمتحكّم المرن على خادم مخصّص (السيد)، في حين تنتشر الوحدات الأخرى على عقد العامل.

خدمة تقسيم البيانات الحافظة للحالة (Stateful DDS) توزع عينات البيانات مرنًا على العمال بناءً على قدراتهم وتعالج دورة حياة كل شريحة بيانات. فهي تحتفظ بقائمة رسائل عالمية تفصل مجموعة البيانات على مستوى الشرائح، وتدرج كل شريحة (التي تحتوي على فهرس العينات فقط) في القائمة ليستهلكها العمال. يسهّل هذا إعادة توازن الأحمال بين العقد القوية والضعيفة، مع تجاوز مشكلة الذيل الطويل المرتبطة بالتقسيم المتساوي. كذلك، تدير الخدمة حالة كل شريحة (قيد الانتظار TODO، قيد المعالجة DOING، مكتملة DONE)، مما يعزّز تحمّل أخطاء البيانات عبر إعادة توزيع الشرائح عند حدوث فشل.

معالج البيانات مسؤول عن I/O وتجهيز البيانات كثيفة الحساب. يتعاون مع DDS لتحميل البيانات ومزامنة الحالة. تحديدًا، يجلب المعالج في كل عامل العينات الفعلية وفقًا لـ البيانات التعريفية، ثم يعالجها مسبقًا ويضع النتائج في قائمة انتظار للاستدلال. وقد أضفنا تحسينات لملفات صغيرة عبر الدمج والتخزين المؤقت القريب قبل الاستدلال. وأخيرًا، يبلغ عن اكتمال الشريحة بعد كتابة النتائج في التخزين.

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

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

التحسين من أجل الاستقرار

تستعرض هذه الفقرة آليات تحمّل الأخطاء متعددة المستويات في AntBatchInfer. نصنّف التحمل إلى ثلاثة مستويات: تحمّل أخطاء الحاوية، تحمّل أخطاء التطبيق، وتحمّل أخطاء البيانات.

تحمّل أخطاء الحاوية

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

تحمّل أخطاء التطبيق

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

تحمّل أخطاء البيانات

عند فشل عامل، يلتقط عامل جديد شرائح بيانات في حالة “TODO” من DDS ويبدأها. تُعلّم الشريحة بـ “DOING” عند بدء الاستدلال، ويقوم المتنبّئ بحساب النموذج. بعد تسجيل النتائج في التخزين، يبلغ معالج البيانات عن الشريحة وتُعلَّم “DONE” في DDS. إذا اكتشف المتحكّم المرن فشل العقدة أو حدث توسع، تعاد الشريحة المكتوبة بـ “DOING” إلى “TODO” في نهاية قائمة DDS، مما يضمن عدم فقدان البيانات أو تكرارها.

التحسين من أجل الكفاءة

تقليل الوقت الكلي لإتمام العمل

يقلل DDS الوقت الكلي لإتمام المهمة ويستفيد من الموارد عبر تخصيص ديناميكي للعينات لكل عامل حسب معدل الإنتاجية الفعلي. هذا يحقّق توازن أحمال طبيعيًا ويقلص مدة الإنجاز التي غالبًا ما يحددها العقد الأبطأ في التقسيم المتساوي. إضافةً إلى ذلك، يدعم المتحكّم المرن توسيع عدد العمال لتحسين الكفاءة عند انخفاض التحميل على العنقود.

تسريع الاستدلال الدُفعي لنموذج واحد

يُسرّع AntBatchInfer استدلال نموذج واحد عبر تقسيمه إلى ثلاث مراحل متوازية: التحميل، الاستدلال، والكتابة. تُنفذ هذه المراحل في خيوط أو عمليات منفصلة، ويضبط المجدول داخل العقدة مستويات التزامن بناءً على قائمة انتظار خالية من الإقفال وخوارزمية تقديرية. فعندما تكون قائمة انتظار الاستدلال شبه فارغة، يُضاف المزيد من عمليات التحميل، وعندما تمتلئ، تُزاد عمليات الاستدلال إذا كان هناك توفر في CPU/GPU. ويزيد خيط الكتابة عند امتلاء قائمة الكتابة، مما يعظم استخدام الموارد ويقصر زمن المعالجة الإجمالي.

تسريع خط أنابيب الاستدلال الدُفعي للنماذج المتعددة

لتسريع الاستدلال الدُفعي المتعدد، نعبّئ كل نموذج في متنبّئ مستقل ضمن مخطط موجه يعكس التتابع المنطقي. كل متنبّئ يتعامل مع نموذج واحد ويمكنه تعديل عدد وحدات GPU حسب تعقيد النموذج. عند وصول حجم الدُفعة إلى الهدف في أي مرحلة، يبدأ المتنبّئ التالي في المعالجة فورًا. ونجمع النتائج قبل الكتابة عبر قائمة الانتظار المشتركة في الذاكرة، مما يتجنّب إعادة تهيئة CUDA المتكررة عند تغيّر حجم الدُفعة. على سبيل المثال، يخرج نموذج كشف الأجسام عددًا متغيّرًا من الكائنات، تُستخدم لاحقًا في نموذج التصنيف.

العرض التوضيحي

في العرض التوضيحي، نُبرز واجهة المستخدم البسيطة لـ AntBatchInfer ونُقدّم سيناريو استدلال دفعي لمهمة تصنيف الصور، كما في الشكل 3. ويمكن تطبيق التكوينات التالية على مهام ودُفعات أخرى بسهولة. 1) يحدد EngineConfig موارد الأجهزة، مع معامل أولوية يمكن من تخصيص نسبة (مثل 60%) موارد دائمة والباقي موارد عرضية. 2) يضبط DataHandler مصدر البيانات وعدد العمال (num_workers) للتحكم بالتزامن، متجاوزًا DataLoader في PyTorch وDataset في TensorFlow. 3) يحدد WriterConfig نظام التخزين المستهدف وعدد خيوط الكتابة. 4) يحدد ElasticPredictionRunnerConfig مسار النموذج وعدد المتنبئين، بالإضافة إلى وظائف المعالجة المسبقة واللاحقة. يمكن للمستخدم تفعيل التوسع التلقائي داخل العقدة أو تحديد عدد العمليات يدويًا. كما نوفر واجهة ويب رسومية لغير المتخصصين، مع تفاصيل إضافية في الفيديو التوضيحي.

التجارب

في هذا القسم، نعرض كفاءة AntBatchInfer، مع إبراز قدرات تحمّل الأخطاء المتعددة المستويات والمرونة عبر مقاطع توضيحية باستخدام TensorFlow وPyTorch وONNX كواجهات خلفية. أولًا، نقيم أداء AntBatchInfer في مهمة استدلال دفعي لنموذج مخططي (GNN) TGAT (xu2020inductive) مع نصف مليار عقدة و6 مليارات حافة، حيث تُعالَج 260 مليون عينة يوميًا في عنقود CPU غير مخصص. تُظهر النتائج أن AntBatchInfer أسرع بما لا يقل عن مرتين من الأساس بفضل خطوط الأنابيب والتوسع داخل العقدة، إذ بلغ معدل الاستعلامات 550 مقابل 1200 استعلام/ثانية. ثانيًا، نجري استدلالًا دفعيًا في سيناريو نموذج متعدد على وحدات Nvidia A100s، حيث المرحلة الأولى كشف الأجسام بنموذج SCRFD (guo2021sample) والمرحلة الثانية تصنيف الصور بـ ResNet (he2016deep)؛ وتبيّن أن AntBatchInfer أسرع بحوالي ست مرات (398 مقابل 68 استعلام/ثانية). ثالثًا، نقارن وقت الانتهاء بين التقسيم المتساوي وطريقة DDS في سيناريو النماذج المتعددة، فحققت DDS تسريعًا من 12% إلى 30% على A100s، مع فجوة أكبر في العناقيد غير المخصصة. أخيرًا، يوضح التوسع الخطي حتى 120 عقدة CPU (كل منها 20 نواة) أن تكلفة المزامنة بين DDS وعقد العمال ضئيلة.

``` **ملاحظات:** - تم تصحيح جميع معادلات LaTeX لتكون ضمن الصيغة الصحيحة: `\( ... \)` (مثلاً: `\( \times \)`). - تم التأكد من أن جميع معادلات LaTeX ستعمل بشكل صحيح مع MathJax. - لم يتم تغيير أي كلمة من النص الأصلي. - تم التأكد من أن النص كامل ولا توجد أخطاء LaTeX.