بالأمس شغّلت نموذجًا لتدريب مُصغّر محليًا على ذاكرة 16 جيجابايت. في البداية كان الأمر على ما يرام، لكن بعد عشرين دورة فقط حدث OOM وانهار كل شيء. راقبت المراقبة ولاحظت أن تجزئة الذاكرة المؤقتة (cache) استهلكت كامل VRAM، فاضطررت لإعادة التشغيل. قضيت ساعة في التجربة والحَكْر.
هذه القصة جعلتني أنظر مرتين إلى إدارة KV Cache في OpenLoRA من OpenLedger. لقد صمّم آلية نقل ديناميكية: عندما تقترب ذاكرة GPU ما من الحد الأقصى، فإنه ينقل تلقائيًا جزءًا من الطلبات بالكامل إلى بطاقة أخرى. والأهم أنه أثناء عملية النقل يحتفظ بحالة الاستدلال، ولا يحتاج لإعادة الحساب.
بحثت فيما تستخدمه، ووجدت أنه يعتمد Segmented Gather Matrix-Vector Multiplication. وبكلام بسيط: يقوم بتخزين متجهات K وV الخاصة بطلبات مختلفة على شكل مقاطع (segments)، وعند الحاجة يتم جلبها على شكل كتل (blocks). لا يتم نقل الجدول كاملًا مرة واحدة، لذلك تكون كمية البيانات المنقولة أقل بكثير.
في الورقة البيضاء يوجد معادلة: الطلب الجديد R_new يتم إسناده إلى GPU يحقق حد حجم الدفعة ومتطلبات الذاكرة. ثم يختار الأفضل، وهو أذكى من التوزيع العشوائي أو الدوران (round-robin). لأن الـ round-robin بسهولة يملأ جهازًا واحدًا بينما تبقى الأجهزة الأخرى فارغة $OPEN .
واجهت شيئًا مشابهًا بنفسي: أسوأ ما في تشغيل خدمة الاستدلال ليس أن القدرة الحسابية غير كافية، بل تجزؤ الذاكرة. أحيانًا توجد بطاقة أخرى بها مساحة، لكن لا يمكن إدخال طلب جديد بسبب التجزؤ، فيضطرّ الأمر إلى إضافة جهاز—وهذا يعني حرق المال. من هنا، قد تساعد آلية التخزين المُجزّأ مع النقل الديناميكي في OpenLoRA نظريًا على استغلال التجزؤ وتقليل عدد البطاقات، أي توفير المال.
لكن أيضًا يجب أن أقول: من الجيد أن منطق النقل يعمل بشكل ممتاز في الورقة، لكن على بيئة إنتاجية قد لا يكون الأمر بنفس السلاسة. النقل المتكرر قد يضيف تأخيرًا إضافيًا. ومع ضغط عالٍ، قد يصبح المجدول نفسه عنق الزجاجة. كما أن مساحة البلوك ليست لانهائية، وتكاليف غاز الإيثريوم (gas) ترتفع بشكل جنوني تحت الحمل العالي—كل هذا بسبب عدم حل مشاكل الجدولة. هل يستطيع OpenLoRA تحمّل حركة المرور الحقيقية؟ سنرى بعد أن يعمل لبضعة أشهر. سأتابع لوحات مراقبة الشبكة الرئيسية. وإذا كان تأخير النقل مضبوطًا ضمن 5 مللي ثانية، سأحاول تشغيل بعض النماذج الصغيرة عليه @OpenLedger #OpenLedger