هذا المقال يتطلب مستوى: متوسط. بيفترض إنك تعرف تشغّل نموذج لغوي محليًا بـ Python وسمعت قبل كده عن ذاكرة الـ GPU، لكنه ما بيفترضش إنك تعرف رياضيات التكميم.
نموذج بـ 70 مليار باراميتر يحتاج نحو 140 جيجابايت ذاكرة GPU علشان يشتغل بدقة FP16. التكميم بينزّل الرقم ده لـ 35 جيجابايت تقريبًا، من غير ما تعيد تدريب أي حاجة. هنا هتفهم إزاي بيحصل، وتشغّله بنفسك في 12 سطر كود.
التكميم: تشغيل نماذج أكبر بذاكرة أقل
المشكلة باختصار
كل باراميتر في النموذج هو رقم عشري. بدقة FP16 الرقم بياخد 2 بايت. يعني نموذج 8 مليار باراميتر = 16 جيجابايت أوزان لوحدها، من غير حساب الـ activations والـ KV cache. الكارت الاستهلاكي بتاعك (مثلًا 8 جيجابايت) مش هيقدر يحمّله أصلًا.
الطريقة اللي بيلجأ لها ناس كتير — يشتروا كارت أغلى أو يأجروا A100 بسعر عالي بالساعة — بتحل المشكلة بفلوس مش بهندسة. التكميم بيحل نفس المشكلة بتقليل عدد البتات لكل رقم بدل زيادة العتاد.
المفهوم بمثال بسيط قبل الرياضيات
تخيّل إنك بتسجّل أسعار في دفتر، بس مساحة كل خانة صغيرة جدًا. بدل ما تكتب سعر بكل الكسور، اتفقنا إننا هنقرّب كل سعر لأقرب رُبع جنيه: 7.00، 7.25، 7.50 وهكذا. السعر 7.213 بيتحوّل لـ 7.25. خسرت دقة صغيرة، بس وفّرت مساحة كبيرة، والمعنى العام للسعر فضل زي ما هو.
التكميم بيعمل نفس الحاجة بالظبط مع أوزان النموذج. علميًا: بناخد المدى المتصل لقيم الأوزان ونقسمه لعدد محدود من المستويات المنفصلة. INT4 معناه 4 بت لكل رقم، يعني 16 مستوى ممكن بس. كل وزن حقيقي بيتخزّن كأقرب مستوى من الستّاشر، ومعاه معامل قياس بنضرب فيه وقت الحساب علشان نرجّع الرقم لمداه الأصلي.
ده معناه إن كل باراميتر بينزل من 2 بايت لنص بايت. النتيجة: تصغير 4 مرات في حجم الأوزان. من 140 جيجابايت لـ 35 جيجابايت في نموذج الـ 70B.
إزاي تعمله عمليًا في 12 سطر
مكتبة bitsandbytes مع transformers بتخلّيك تحمّل أي نموذج مكمّم بسطر إعداد واحد. الكود ده بيحمّل Llama 3 بـ 8 مليار باراميتر بدقة 4 بت:
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
import torch
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
model_id = "meta-llama/Meta-Llama-3-8B-Instruct"
tok = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=bnb_config,
device_map="auto",
)
print(round(model.get_memory_footprint() / 1e9, 2), "GB")
النتيجة المتوقّعة من السطر الأخير: حوالي 5.5 إلى 6 جيجابايت بدل 16 جيجابايت. يعني النموذج اللي مكانش بيركب على كارت 8 جيجابايت، بقى يركب ويفضل مكان للسياق.
الأرقام الحقيقية والمقايضات
الافتراض هنا إنك بتقيس على نماذج من عائلة Llama بأحجام 7B لـ 70B. الأرقام دي مبنية على أوراق بحثية منشورة:
- QLoRA (Dettmers وآخرون، 2023) درّبت نموذج 65B على كارت واحد بذاكرة 48 جيجابايت بفضل تكميم NF4 والتكميم المزدوج، وحافظت على أداء قريب جدًا من الدقة الكاملة.
- GPTQ (Frantar وآخرون، 2022) كمّمت نماذج بحجم 175B لـ 4 بت بزيادة ضئيلة جدًا في الـ perplexity، وخلّت النموذج يشتغل على عتاد أقل بمراحل.
- الدقة 8 بت بتعتبر شبه بلا خسارة في معظم المهام، مقابل تصغير مرتين بس. الدقة 4 بت بتوفّر تصغير 4 مرات، مقابل خسارة بسيطة بتكبر لو النموذج نفسه صغير.
الـ trade-off هنا مهم: التصغير بيوفّر الذاكرة، لكنه مش دايمًا بيوفّر السرعة. تكميم bitsandbytes العادي بيفك التكميم وقت الحساب، فممكن يبقى أبطأ في التوليد لو مفيش kernels متخصصة. لو عايز سرعة كمان، استخدم صيغ زي AWQ أو GPTQ مع محركات زي vLLM اللي فيها kernels محسّنة بترفع الإنتاجية. بتكسب ذاكرة أقل بـ 4 مرات، بتخسر شوية دقة وأحيانًا سرعة لو استخدمت الطريقة الساذجة من غير kernel مناسب.
متى لا تستخدم التكميم
ما تكمّمش لو النموذج بيركب أصلًا على كارتك بالدقة الكاملة — مفيش داعي تخسر دقة من غير مكسب. وما تنزلش لـ 4 بت في المهام الحسّاسة جدًا للدقة زي التقييم العلمي الدقيق، لو عندك ذاكرة تكفّي BF16؛ في الحالات دي فضّل 8 بت أو الدقة الكاملة. وكمان، النماذج الصغيرة جدًا (أقل من 3B) بتتأثر بالتكميم 4 بت أكتر من الكبيرة نسبيًا، فقِس الجودة قبل ما تعتمده.
الخطوة التالية
افتح نوتبوك، حمّل نموذج 7B أو 8B مرة بتكميم 4 بت ومرة من غير تكميم، واطبع حجم الذاكرة في الحالتين. بعدها شغّل نفس البرومبت على الاتنين وقارن الإجابة والزمن بنفسك. لو الفرق في الجودة مقبول عندك، انت كسبت 4 أضعاف في الذاكرة ببلاش.
المصادر
- Dettmers et al., QLoRA: Efficient Finetuning of Quantized LLMs, 2023 — arxiv.org/abs/2305.14314
- Frantar et al., GPTQ: Accurate Post-Training Quantization, 2022 — arxiv.org/abs/2210.17323
- Lin et al., AWQ: Activation-aware Weight Quantization, 2023 — arxiv.org/abs/2306.00978
- Hugging Face Transformers — Quantization docs — huggingface.co/docs/transformers/main/en/quantization/bitsandbytes
- bitsandbytes library — github.com/bitsandbytes-foundation/bitsandbytes