FP16 (نصف الدقة): في FP16، يتم تمثيل رقم الفاصلة العائمة باستخدام 16 بت. وتتكون من بتة إشارة واحدة، و5 بتات للأس، و10 بتات للكسر (الجزء العشري). يوفر هذا التنسيق دقة أعلى لتمثيل القيم الكسرية ضمن نطاقه.
BF16 (BFloat16): يستخدم BF16 أيضًا 16 بت، ولكن بتوزيع مختلف. يحتوي على بت إشارة واحدة، و8 بتات للأس، و7 بتات للجزء العشري. يضحي هذا التنسيق ببعض الدقة في الجزء الكسري لاستيعاب نطاق أوسع من الأسس.
يحتوي FP16 على نطاق أصغر ولكن دقة أعلى ضمن هذا النطاق نظرًا لأجزاءه العشرية ذات 10 بت.
يحتوي BF16 على نطاق أوسع ولكن دقة أقل للقيم الكسرية نظرًا لأسه 8 بت وأجزاءه العشرية 7 بت.
دعونا نستخدم الأمثلة لتوضيح الاختلافات بين FP16 وBF16 مع 3 حالات أمثلة. يتم استخدام TensorFlow لإجراء الاختبارات والأكواد المشتركة في الأسفل:
القيمة الأصلية: 0.0001 — يمكن أن تمثل كلتا الطريقتين
FP16: 0.00010001659393 (ثنائي: 0|00001|1010001110، سداسي عشري: 068E) — 10 أجزاء عشرية و5 أس
BF16: 0.00010013580322 (ثنائي: 0|01110001|1010010، سداسي عشري: 38D2) — 7 أجزاء عشرية و8 أس
كما ترون، لديهم أس وأجزاء عشرية مختلفة، وبالتالي فهم قادرون على التمثيل بشكل مختلف. ولكن يمكننا أن نرى أن FP16 يمثلها بشكل أكثر دقة وبقيمة أقرب.
القيمة الأصلية: 1e-08 (0.00000001)
FP16: 0.0000000000000 (ثنائي: 0|00000|0000000000، سداسي عشري: 0000)
BF16: 0.00000001001172 (ثنائي: 0|01100100| 0101100، سداسي عشري: 322C)
هذه حالة مثيرة للاهتمام للغاية. فشل FP16 وجعل النتيجة 0 لكن BF16 قادر على تمثيلها بتنسيق خاص.
القيمة الأصلية: 100000.00001
FP16: inf (ثنائي: 0|11111|0000000000، سداسي عشري: 7C00)
BF16: 99840.0000000000000 (ثنائي: 0|10001111 |1000011، سداسي عشري: 47C3 )
في الحالة المذكورة أعلاه، يفشل FP16 نظرًا لأن جميع البتات الأسية تصبح ممتلئة وغير كافية لتمثيل القيمة. ومع ذلك يعمل BF16
يُستخدم FP16 بشكل شائع في التدريب على التعلم العميق والاستدلال، خاصة للمهام التي تتطلب دقة عالية في تمثيل القيم الكسرية الصغيرة ضمن نطاق محدود.
أصبح BF16 شائعًا في بنيات الأجهزة المصممة لمهام التعلم الآلي التي تستفيد من نطاق أوسع من القيم القابلة للتمثيل، حتى على حساب بعض الدقة في الجزء الجزئي. إنها مفيدة بشكل خاص عند التعامل مع التدرجات الكبيرة أو عندما يكون الاستقرار الرقمي عبر نطاق واسع أكثر أهمية من دقة القيم الصغيرة.
يوفر FP16 دقة أعلى للقيم الكسرية ضمن نطاق أصغر، مما يجعله مناسبًا للمهام التي تتطلب تمثيلًا دقيقًا للأرقام الصغيرة. من ناحية أخرى، يوفر BF16 نطاقًا أوسع على حساب بعض الدقة، مما يجعله مفيدًا للمهام التي تتضمن نطاقًا أوسع من القيم أو حيث يكون الاستقرار العددي عبر نطاق واسع أمرًا بالغ الأهمية. يعتمد الاختيار بين FP16 وBF16 على المتطلبات المحددة لمهمة التعلم الآلي المطروحة.
نظرًا لجميع الأسباب المذكورة أعلاه، عند إجراء تدريب Stable Diffusion XL (SDXL)، يتطلب FP16 وBF16 معدلات تعلم مختلفة قليلاً وأجد أن BF16 يعمل بشكل أفضل.
الكود المستخدم لإنشاء الأمثلة أعلاه
import tensorflow as tf import struct def float_to_binary(f): return ''.join(f'{b:08b}' for b in struct.pack('>f', f)) def display_fp16(value): fp16 = tf.cast(tf.constant(value, dtype=tf.float32), tf.float16) fp32 = tf.cast(fp16, tf.float32) binary = format(int.from_bytes(fp16.numpy().tobytes(), 'big'), '016b') sign = binary[0] exponent = binary[1:6] fraction = binary[6:] return f"FP16: {fp32.numpy():14.14f} (Binary: {sign}|{exponent}|{fraction}, Hex: {fp16.numpy().view('uint16'):04X})" def display_bf16(value): bf16 = tf.cast(tf.constant(value, dtype=tf.float32), tf.bfloat16) bf32 = tf.cast(bf16, tf.float32) binary = format(int.from_bytes(bf16.numpy().tobytes(), 'big'), '016b') sign = binary[0] exponent = binary[1:9] fraction = binary[9:] return f"BF16: {bf32.numpy():14.14f} (Binary: {sign}|{exponent}|{fraction}, Hex: {bf16.numpy().view('uint16'):04X})" values = [0.0001, 0.00000001, 100000.00001] for value in values: print(f"\nOriginal value: {value}") print(display_fp16(value)) print(display_bf16(value))
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3