المستوى المطلوب: متوسط — يفترض إنك جربت تشغّل موديل LLM محلياً عبر transformers أو llama.cpp مرة على الأقل، وتعرف إيه يعني FP16 وVRAM.
لو حاولت تشغّل Llama 3.1 70B على RTX 4090 وقالك "CUDA out of memory"، الموديل في صيغته الأصلية محتاج حوالي 140GB ذاكرة، والكارت عندك 24GB. الفرق مش هندسة. الفرق إنك بتنزّل الأوزان بدقة FP16. بـ4-bit Quantization تقدر تنزّله لحوالي 40GB، وتشغّله على A100 80GB واحد بدل 2 إلى 4 منهم، بنفس جودة الإجابات تقريباً وتوفير عشرات الآلاف من الدولارات على الـhardware.
Quantization: ازاي بنضغط الموديل وبيفضل بيشتغل؟
المشكلة باختصار
كل باراميتر في الموديل بيتخزّن كرقم عشري. الافتراضي FP16 يعني 16 بت لكل باراميتر = 2 بايت. Llama 3.1 70B عنده 70 مليار باراميتر، يبقى 70 × 2 = 140GB ذاكرة فقط للأوزان، قبل أي activations أو KV cache.
الكروت اللي بتتحمّل ده قليلة وغالية. H100 80GB حوالي 30 ألف دولار، A100 80GB حوالي 15 ألف، RTX 4090 بـ24GB بس. لو عايز تشغّل 70B بـFP16، محتاج 2× A100 على الأقل، وغالباً 4 لو فيه context كبير. التكلفة بتطلع 60 ألف دولار وفوق. السؤال: هل لازم نخزّن كل وزن بـ16 بت أصلاً؟
المثال البسيط: ضغط الصورة من 16 مليون لون لـ256
تخيّل عندك صورة فوتوغرافية بـ16 مليون لون (RGB كاملة). لو حوّلتها لصيغة palette فيها 256 لون مختار بعناية، حجم الملف بينزل 6 أضعاف، والصورة من بعيد بتفضل تشبه الأصل. السبب إن العين البشرية ما بتلاحظش الفرق بين 256 لون و16 مليون في معظم المشاهد.
الـquantization بنفس الفكرة بالظبط. بدل ما كل وزن يتخزّن بدقة 16 بت (65 ألف قيمة ممكنة)، بنخزّنه في 4 بت (16 قيمة ممكنة) من خلال جدول صغير محفوظ مع الموديل. الفرق إن الموديل بيشتغل تمام بالقيم المضغوطة لأن أوزان الـtransformer أصلاً متوزّعة Normal Distribution ضيّقة حوالي الصفر. مفيش أوزان متطرفة كتير، فالـ16 قيمة كفاية تمثّل التوزيع كله بأقل خطأ.
التعريف العلمي الدقيق: NormalFloat 4
الـNormalFloat 4 (اختصاره NF4) ابتكره Tim Dettmers في ورقة QLoRA المنشورة في NeurIPS 2023. الفكرة العلمية:
- الأوزان في الـtransformer متوزّعة Normal Distribution N(0, σ) بمتوسط ≈ 0.
- بدل ما نقسم المدى للقيم بالتساوي (linear quantization، اللي بيخسر دقة في القيم الصغيرة لأن أغلب الأوزان قريبة من الصفر)، بنختار 16 قيمة information-theoretically optimal تمثّل الـnormal distribution بأقل خطأ تربيعي.
- الـ16 قيمة دي ثابتة محسوبة سلفاً من quantiles توزيع N(0,1) القياسي.
- كل tensor (مش كل وزن) بنحسبله scale واحد بنضربه فيه عشان نرجّع المدى الأصلي. الطريقة دي اسمها block-wise absolute max quantization مع block size = 64.
- الـscales نفسها لو خزّناها بـFP32 بتكلّف ذاكرة. الورقة قدّمت Double Quantization: نضغط الـscales كمان بـFP8، فبنوفّر ~0.4 بت إضافي لكل باراميتر.
النتيجة العلمية: NF4 + double quantization بيطابق أداء BFloat16 على benchmarks اللغة الكبيرة، بينما FP4 (linear quantization البسيط) بيخسر حوالي نقطة كاملة في الـperplexity على نفس الموديل.