Half-Precision
تخزّن الدقة النصفية (FP16) الأعداد باستخدام 16 بت بدلًا من 32 بت في FP32، فتخفض استهلاك الذاكرة إلى النصف وتسرّع العمليات الحسابية على GPU. ويتناول هذا المفهوم حدودها وتحجيم الخسارة والاستدلال باستخدام FP16.
الدقة النصفية، التي تُسمّى أيضًا FP16 أو float16 أو IEEE 754 binary16، هي تنسيق للأعداد ذات الفاصلة العائمة مكوّن من 16 بت، يتألف من بت واحد للإشارة و5 بتات للأسّ و10 بتات للكسر. وبالمقارنة مع الدقة الأحادية القياسية ذات 32 بت (FP32)، فإنها تخفّض إلى النصف مقدار الذاكرة وعرض النطاق الترددي اللذين يحتاج إليهما كل عدد، كما تنفّذ وحدات GPU المزودة بأنوية Tensor عمليات حساب المصفوفات بدقة FP16 بسرعة تفوق سرعتها بدقة FP32 مرات عديدة. ويتمثل المقابل في نطاق تمثيل ضيق، إذ تبلغ القيمة القصوى 65,504، مع نحو ثلاثة أرقام عشرية معنوية. وتتحمل الشبكات العصبية هذا التقريب جيدًا، ما يجعل FP16 دقةً قياسيةً للاستدلال باستخدام GPU، كما يجعل الجمع بين FP16 وFP32 ضمن الدقة المختلطة طريقةً شائعةً لتسريع التدريب.
مقارنة FP16 بـ FP32#
تخصص FP32 مقدار 8 بتات للأسّ و23 للكسر، ولذلك يغطي نطاقًا يقارب 10⁻³⁸ إلى 10³⁸ بنحو سبعة أرقام معنوية. وتحدّ بتات الأسّ الخمسة في FP16 القيم العادية لتتراوح بين 6.1 × 10⁻⁵ و65,504، مع قيم دون عادية أصغر تصل إلى نحو 6 × 10⁻⁸ بدقة أقل. وأي قيمة أكبر من ذلك تفيض إلى ما لا نهاية، وأي قيمة أصغر تُقرّب إلى الصفر. يوضح تحويل نموذج الفوائد والحدود معًا:
import torch
import torchvision
# ResNet-18 stores its weights in FP32 by default
model = torchvision.models.resnet18()
fp32_mb = sum(p.numel() * p.element_size() for p in model.parameters()) / 1e6
# Casting to FP16 stores every weight in 2 bytes instead of 4
model.half()
fp16_mb = sum(p.numel() * p.element_size() for p in model.parameters()) / 1e6
print(f"Weights: {fp32_mb:.1f} MB in FP32, {fp16_mb:.1f} MB in FP16")
# FP16 overflows above 65,504 and rounds to about 3 significant digits
x = torch.tensor([65504.0, 70000.0, 0.1])
print("FP16 values:", x.half().tolist())ينخفض حجم الأوزان من 46.8 MB إلى 23.4 MB. وفي السطر الثاني، تبقى 65,504 أكبر قيمة يمكن تمثيلها في FP16، وتصبح 70,000 inf، بينما تُخزّن 0.1 على هيئة 0.0999755859375، وهي أقرب قيمة يستطيع FP16 تمثيلها.
الدقة النصفية في التدريب#
يؤدي التدريب بالكامل باستخدام FP16 إلى فقدان الدقة أو عدم تقارب كثير من النماذج، لأن التدرجات الصغيرة تتلاشى إلى الصفر، ولأن تحديثات الأوزان الضئيلة مقارنةً بالأوزان نفسها تُقرّب بعيدًا. يعالج التدريب بالدقة المختلطة المشكلتين: إذ يحتفظ بنسخة رئيسية من الأوزان بدقة FP32 لإجراء التحديثات، وينفّذ المرورين الأمامي والعكسي بدقة FP16، كما يضرب الخسارة في عامل قياس لإبقاء التدرجات ضمن نطاق FP16 قبل إلغاء القياس بدقة FP32. وتضبط أطر العمل هذا العامل تلقائيًا، كما تفعل GradScaler في PyTorch:
تقلّل تنشيطات FP16 أيضًا إلى النصف الذاكرة التي تستهلكها الدفعة أثناء التدريب، ما يسمح لوحدة GPU نفسها باستيعاب دفعات أكبر أو مدخلات أعلى دقة. وغالبًا ما يُفضّل bfloat16 (BF16) للتدريب على الأجهزة التي تدعمه، لأن أسّه، الذي يماثل أسّ FP32 في الحجم، يلغي الحاجة إلى قياس الخسارة.
الدقة النصفية للاستدلال#
لا يحتاج الاستدلال إلى حساب التدرجات، كما أن قيم التنشيط في معظم نماذج الرؤية تبقى ضمن نطاق FP16 بهامش واسع، لذا فإن تحويل نموذج مكتمل إلى FP16 يحافظ عادةً على دقته ضمن هامش طفيف من دقة FP32، من دون بيانات المعايرة التي يتطلبها تكميم النماذج إلى INT8. وتبني محركات GPU، مثل TensorRT، محركات FP16 تعمل على أنوية Tensor، وتعتمد وحدات GPU المضمّنة، مثل NVIDIA Jetson، على FP16 لإجراء الاستدلال في الوقت الفعلي. وتستفيد وحدات CPU بدرجة أقل، لأن كثيرًا منها لا ينفّذ العمليات الحسابية بدقة FP16 بسرعة. ويُجري Ultralytics YOLO التدريب على وحدات GPU باستخدام الدقة المختلطة FP16 افتراضيًا (amp=True)، ويستخدم quantize=16 لإجراء التنبؤ والتصدير بدقة FP16، مثلًا باستخدام YOLO26:
from ultralytics import YOLO
# حمّل أصغر نموذج لكشف الكائنات من YOLO26
model = YOLO("yolo26n.pt")
# تنبّأ بدقة FP16 على GPU؛ وعلى CPU، تعمل نماذج PyTorch بدقة FP32
results = model.predict("https://ultralytics.com/images/bus.jpg", quantize=16)
# صدّر نموذج ONNX يخزّن أوزانه بدقة FP16
path = model.export(format="onnx", quantize=16)يخزّن الملف المُصدّر كل وزن في بايتين بدلًا من أربعة، وتنتج الوسيطة quantize=16 نفسها نماذج FP16 لـTensorRT وOpenVINO وCoreML وغيرها من تنسيقات التصدير.
الدقة النصفية مقارنةً بالتنسيقات ذات الصلة#
- BFloat16 (BF16): تنسيق الفاصلة العائمة الآخر ذي 16 بت، ويضم 8 بتات للأسّ و7 للكسر؛ ويضحّي بالدقة لصالح نطاق FP32، ويُفضّل لتدريب النماذج الكبيرة.
- FP8: تنسيقات فاصلة عائمة ذات 8 بت على وحدات NVIDIA GPU الحديثة، تخفّض الذاكرة إلى النصف مرة أخرى، وتُستخدم غالبًا لتدريب النماذج اللغوية الكبيرة وتقديمها.
- تكميم INT8: يحوّل القيم إلى أعداد صحيحة ذات 8 بت باستخدام مقاييس لكل موتر أو لكل قناة. وهو أسرع وأصغر من FP16، لكنه يحتاج إلى بيانات معايرة أو تدريب واعٍ بالتكميم للحفاظ على الدقة.
استخدامات الدقة النصفية#
- الذكاء الاصطناعي الطرفي: تعمل الكواشف على وحدات Jetson وغيرها من وحدات GPU المضمّنة بدقة FP16 لتحقيق معدلات إطارات الكاميرا باستهلاك طاقة لا يتجاوز بضعة واطات أو عشرات الواطات.
- الاستدلال السحابي: تخفّض الخدمة بدقة FP16 إلى النصف الذاكرة لكل نسخة من النموذج، ما يتيح لوحدة GPU واحدة استضافة نسخ أكثر أو دفعات أكبر.
- النماذج اللغوية الكبيرة: يحتاج نموذج يضم 7 مليارات معامل إلى 28 GB لأوزانه بدقة FP32 و14 GB بدقة FP16، لذا يمكنه العمل بدقة FP16 على وحدة GPU استهلاكية واحدة بسعة 24 GB مع ترك مساحة لذاكرة KV المؤقتة.










