تشغيل نماذج اللغة الكبيرة محليًا يصطدم غالبًا بحائط صلب: حدود ذاكرة الفيديو (VRAM). حتى مع وحدات الرسوميات المنفصلة القوية، تُجبر النماذج التي تتجاوز سعة ذاكرة الفيديو المطورين على الاختيار بين التكميم (فقدان الدقة) أو الاستدلال البطيء على المعالج. على شرائح Apple Silicon ومنصات AMD الأحدث، توفر معمارية الذاكرة الموحدة (UMA) مسارًا ثالثًا. من خلال التعامل مع ذاكرة النظام وذاكرة الرسوميات كحوض واحد، يمكننا تفريغ مكونات محددة، مثل رؤوس الانتباه، بشكل استراتيجي لاستغلال كامل عرض النطاق الترددي للذاكرة مع إبقاء الحسابات الحرجة على وحدة الرسوميات.
لماذا تُعد رؤوس الانتباه مرشحة مثالية
ليست جميع أجزاء نموذج الترانسفورمر متساوية. عملية ضرب المصفوفة بالمصفوفة في الشبكات الأمامية (FFN) كثيفة الحساب وتستفيد أكثر من تسريع وحدة الرسوميات. ومع ذلك، يمكن أن تكون عمليات الانتباه (تحديدًا إسقاطات Q و K و V واللاحق softmax) أكثر ارتباطًا بعرض النطاق الترددي للذاكرة، خاصة عند أطوال التسلسلات الأطول.
في إعداد UMA، تكون "وحدة الرسوميات" في الأساس معالجًا مساعدًا يمكنه الوصول إلى ذاكرة النظام بسرعة عالية (غالبًا ما يتجاوز 100 جيجابايت/ثانية على شرائح M2/M3/M4 Max). لذلك، نقل مصفوفات الأوزان لرؤوس الانتباه إلى ذاكرة النظام لا يترتب عليه نفس العقوبة كما هو الحال مع وحدة رسوميات منفصلة متصلة عبر PCIe. يكون جلب البيانات سريعًا بما يكفي بحيث يفوق المكسب الحسابي من إبقاء النموذج مقيمًا في ذاكرة عالية النطاق الترددي غالبًا التأخير الطفيف الناتج عن الوصول إليها من ذاكرة النظام "البطيئة".
استراتيجية التنفيذ بلغة بايثون
باستخدام مكتبات مثل PyTorch أو محركات الاستدلال المتخصصة، يمكننا التحكم يدويًا في وضع الجهاز. المفتاح هو تحديد فهارس الطبقات ونقل تينسورات المعلمات المحددة إلى جهاز 'cpu' مع إبقاء الباقي على جهاز 'cuda' أو 'mps'.
import torch
def hybrid_load_model(model, offload_ratio=0.5, layer_type='attention'):
"""
يفرّغ جزءًا من طبقات الانتباه إلى المعالج.
يفترض بنية ترانسفورمر قياسية.
"""
layers = list(model.named_parameters())
total_layers = len([l for l in layers if 'self_attn' in l[0]])
# تحديد الطبقات المراد تفريغها
offload_count = int(total_layers * offload_ratio)
# الاستراتيجية: تفريغ الطبقات الأولى (غالبًا أقل أهمية للنتائج النهائية)
# أو تبديلها. هنا نفرّغ أول N كتلة انتباه.
target_layers = [l[0] for l in layers if 'self_attn' in l[0]][:offload_count]
for name, param in model.named_parameters():
if name in target_layers:
param.data = param.data.to('cpu')
param.data = param.data.float() # الحفاظ على دقة أعلى في الذاكرة
else:
# التأكد من بقاء الطبقات الحرجة على وحدة الرسوميات
if param.device.type != 'cuda' and param.device.type != 'mps':
param.data = param.data.to('cuda' if torch.cuda.is_available() else 'mps')
model.eval()
return model
# مثال على الاستخدام
# model = load_llama_model(path="llama-7b-gguf")
# hybrid_model = hybrid_load_model(model, offload_ratio=0.3, layer_type='attention')
إدارة تكلفة نقل البيانات
على الرغم من أن UMA يقلل تكاليف النقل، إلا أنه لا يلغيها. يتطلب كل تمرير أمامي نقل أوزان الانتباه إلى وحدة الرسوميات للحساب (أو حسابها على المعالج إذا كان النظام الخلفي يدعم ذلك). لتقليل ذلك، فكّر في تجميع الطبقات المفرّغة. بدلاً من نقل الأوزان طبقة تلو الأخرى، قم بتجميع رؤوس انتباه متعددة ونقلها في عملية مجمعة واحدة.
علاوة على ذلك، استغل torch.compile مع حواجز الأشكال الديناميكية. يمكن لمُجمّع PyTorch غالبًا دمج عمليات نقل البيانات مع عمليات إطلاق النواة، مخفيًا التأخير خلف العمليات كثيفة الحساب. على شرائح Apple Silicon، تأكد من استخدام النظام الخلفي Metal Performance Shaders (MPS)، الذي يتمتع بدعم أصلي لتخصيص الذاكرة الموحدة.
مثال عملي: تشغيل نموذج 13B
فكّر في نموذج يحتوي على 13 مليار معامل بنقطة عائمة 16-بت. يتطلب هذا حوالي 26 جيجابايت من الذاكرة. لا يمكن لوحدة رسوميات قياسية بسعة 16 جيجابايت استيعابه. ومع ذلك، يمكن لـ MacBook Pro بذاكرة موحدة 32 جيجابايت استيعابه.
- تضمينات الأساس (Base Embeddings): إبقاؤها على وحدة الرسوميات (حرجة للسرعة).
- طبقات FFN: إبقاؤها على وحدة الرسوميات (كثيفة الحساب).
- رؤوس الانتباه (الطبقات 1-16): تفريغها إلى المعالج/الذاكرة.
من خلال تفريغ 50% من رؤوس الانتباه، تحرر حوالي 6.5 جيجابايت من ذاكرة فيديو وحدة الرسوميات. هذا يسمح بتحميل النموذج. أثناء الاستدلال، تتعامل وحدة الرسوميات مع حسابات FFN الثقيلة، بينما يتعامل المعالج مع إسقاط الانتباه. على شريحة M3 Max، يمكن لهذا النهج الهجين تحقيق 25-35 رمزًا في الثانية، مقارنةً بأقل من 5 رموز في الثانية في إعداد المعالج الخالص.
الخاتمة
الاستدلال الهجين بين المعالج والرسوميات على معماريات الذاكرة الموحدة ليس مجرد حل بديل؛ بل هو استراتيجية أساسية لتطوير الذكاء الاصطناعي محليًا. من خلال تفريغ رؤوس الانتباه بذكاء، تفتح إمكانية تشغيل نماذج أكبر دون المساس بسرعة توليد الرموز. مع استمرار تطور الأجهزة، سيكون إتقان هذه الاستراتيجيات التوزيعية مفتاحًا لدفع حدود أداء نماذج اللغة المحلية. ابدأ بتقييم استخدام الذاكرة في نموذجك، حدد المكونات المرتبطة بعرض النطاق الترددي، وجرّب التفريغ الجزئي للعثور على النقطة المثالية لتكوين الأجهزة الخاص بك.