Model Quantization
يخزّن تكميم النماذج الأوزان والتنشيطات بدقة أقل، مثل INT8، لتقليص النماذج وتسريع الاستدلال. تعرّف على آلية عمله والفرق بين PTQ وQAT.
يحوّل تكميم النموذج أوزان الشبكة العصبية، وغالبًا تنشيطاتها أيضًا، من أعداد فاصلة عائمة بدقة 32 بت (FP32) إلى تنسيقات أقل دقة، مثل الأعداد العائمة بدقة 16 بت (FP16)، أو الأعداد الصحيحة بدقة 8 بت (INT8)، أو الأعداد الصحيحة بدقة 4 بت. وبذلك يتطلب تخزين كل قيمة ونقلها عددًا أقل من البتات، كما تعمل العمليات الحسابية الصحيحة بسرعة أكبر وتستهلك طاقة أقل على معظم المعالجات. ويبلغ حجم نموذج INT8 ربع حجم نموذجه الأصلي FP32، ما يتيح لنماذج اكتشاف الأجسام العمل في الزمن الحقيقي على الهواتف والكاميرات وغيرها من أجهزة الذكاء الاصطناعي الطرفي، كما يتيح للنماذج اللغوية الكبيرة (LLMs) العمل على وحدة GPU واحدة.
آلية عمل التكميم#
يسند التكميم نطاقًا من الأعداد الحقيقية إلى مجموعة صغيرة من المستويات الصحيحة. وفي المخطط الأفيني الشائع، يُخزن كل عدد عشري x كعدد صحيح q = round(x / scale) + zero_point، ويُستعاد على النحو التالي: x ≈ (q - zero_point) × scale. ويحدد المقياس حجم الخطوة بين المستويات، بينما تضمن نقطة الصفر تحويل القيمة العشرية 0 إلى عدد صحيح دقيق. ويتضمن INT8 عدد 256 مستوى، لذا يجب اختيار النطاق بعناية: فالنطاق الواسع جدًا يهدر مستويات على قيم لا تظهر مطلقًا، والنطاق الضيق جدًا يقص القيم الشاذة. وتكون الأوزان معروفة مسبقًا، لذا تُستمد نطاقاتها مباشرةً من النموذج المدرّب، وغالبًا ما تُحسب لكل قناة خرج على حدة. أما التنشيطات فتعتمد على المدخلات، ولذلك تُقاس نطاقاتها أثناء المعايرة بتشغيل مجموعة صغيرة من الصور أو عينات النصوص الممثلة عبر النموذج.
import numpy as np
rng = np.random.default_rng(0)
weights = rng.normal(0, 0.05, size=1000).astype(np.float32)
# Affine INT8 quantization maps the observed float range onto 256 integer levels
scale = (weights.max() - weights.min()) / 255
zero_point = np.round(-128 - weights.min() / scale)
q = np.clip(np.round(weights / scale + zero_point), -128, 127).astype(np.int8)
# Dequantize to measure the rounding error the model has to tolerate
restored = (q.astype(np.float32) - zero_point) * scale
print(f"Size: {weights.nbytes} -> {q.nbytes} bytes")
print(f"Max error: {np.abs(weights - restored).max():.5f} (half a step: {scale / 2:.5f})")يطبع Size: 4000 -> 1000 bytes وخطأً أقصى مقداره 0.00068، يساوي نصف خطوة تكميم واحدة. وتنخفض أحجام الأوزان إلى الربع، ولا تتحرك أي قيمة بأكثر من نصف خطوة عن قيمتها الأصلية.
التكميم بعد التدريب والتدريب الواعي بالتكميم#
- التكميم بعد التدريب (PTQ): يحوّل نموذجًا مدرّبًا بالفعل، مستخدمًا مجموعة معايرة صغيرة لتحديد نطاقات التنشيط. ويستغرق ذلك دقائق ولا يتطلب بيانات تدريب تتجاوز تلك العينات. والتكميم الديناميكي متغير من PTQ يحسب نطاقات التنشيط مباشرةً أثناء الاستدلال، بينما يترك تكميم الأوزان فقط التنشيطات بأعداد فاصلة عائمة.
- التدريب الواعي بالتكميم (QAT): يحاكي التكميم أثناء التدريب أو الضبط الدقيق عن طريق تقريب القيم في التمرير الأمامي، بحيث تتعلم الأوزان تحمّل التقريب. ويستعيد معظم الدقة التي يفقدها PTQ، مقابل كلفة تدريب إضافي.
تبدأ الفرق عادةً بـ PTQ، ولا تنتقل إلى خيار آخر إلا إذا كان انخفاض الدقة كبيرًا جدًا:
تضيف النماذج اللغوية الكبيرة أساليبها الخاصة. فضغط الأوزان إلى 4 بت فقط، باستخدام أساليب مثل GPTQ وAWQ، يضغط مليارات المعلمات مع إبقاء التنشيطات بدقة 16 بت؛ ويخزن تنسيق GGUF النماذج المكممة للاستدلال المحلي؛ كما تحسب وحدات GPU الحديثة مباشرةً بتنسيقات الأعداد الفاصلة العائمة منخفضة الدقة، مثل FP8.
التكميم والتقنيات ذات الصلة#
- الدقة المختلطة: تقنية تدريب تنفذ معظم العمليات بدقة FP16 أو BF16، مع الاحتفاظ بنسخة رئيسية من الأوزان بدقة FP32 لتسريع التدريب. يستهدف التكميم الاستدلال ويتجاوز ذلك، وغالبًا ما يستخدم الأعداد الصحيحة.
- تشذيب النموذج: يزيل الأوزان أو القنوات الكاملة لتقليل عدد العمليات، وغالبًا ما يُدمج مع التكميم الذي يقلل كلفة كل عملية متبقية.
- تقطير المعرفة: يدرّب نموذجًا صغيرًا، هو الطالب، لمحاكاة نموذج كبير، هو المعلّم. وغالبًا ما يُكمّم نموذج الطالب بعد ذلك لنشره.
التكميم عمليًا#
يعتمد تسريع الأداء على دعم الأجهزة: فلا يعمل نموذج INT8 بسرعة أكبر إلا على معالجات تدعم نوى INT8، مثل وحدات GPU من NVIDIA المزودة بـ TensorRT، ووحدات CPU من Intel المزودة بـ OpenVINO، ووحدات المعالجة العصبية (NPUs) في الهواتف. ويطبق Ultralytics YOLO26 تقنية PTQ أثناء التصدير باستخدام quantize=8، مع المعايرة على صور من مجموعة البيانات data، بينما يجري model.train(quantize=8) ضبط نقطة تحقق بدقة باستخدام QAT. ويصدر هذا المثال نموذج INT8 إلى LiteRT، بيئة التشغيل من Google لنظام Android والأجهزة المضمنة:
from ultralytics import YOLO
# تحميل نموذج YOLO26 nano مُدرَّب مسبقًا
model = YOLO("yolo26n.pt")
# التكميم INT8 بعد التدريب؛ تُعاير نطاقات التنشيط باستخدام صور من coco8.yaml
model.export(format="litert", quantize=8, data="coco8.yaml")عند القياس على COCO باستخدام TensorRT، يخفض PTQ بتنسيق INT8 قيمة mAP50-95 لـ YOLO26n من 0.403 إلى 0.393 فقط، لكنه يكلّف YOLO26s أكثر، إذ يخفضها من 0.479 إلى 0.441، بينما يعيد QAT قيمة YOLO26s إلى 0.471.










