ترجمت واجهة Cloud Translation API‏ هذه الصفحة.
Switch to English

تصحيح المشاكل العددية في برامج TensorFlow باستخدام TensorBoard Debugger V2

يمكن أن تحدث الأحداث الكارثية التي تنطوي على NaN في بعض الأحيان أثناء برنامج TensorFlow ، مما يعوق عمليات التدريب النموذجية. غالبًا ما يكون السبب الجذري لمثل هذه الأحداث غامضًا ، خاصة بالنسبة لنماذج الحجم والتعقيد غير التافهة. لتسهيل تصحيح هذا النوع من الأخطاء النموذجية ، يوفر TensorBoard 2.3+ (جنبًا إلى جنب مع TensorFlow 2.3+) لوحة تحكم متخصصة تسمى Debugger V2. هنا نوضح كيفية استخدام هذه الأداة من خلال العمل من خلال خطأ حقيقي يتضمن NaNs في شبكة عصبية مكتوبة في TensorFlow.

التقنيات الموضحة في هذا البرنامج التعليمي قابلة للتطبيق على أنواع أخرى من أنشطة التصحيح مثل فحص أشكال موتر وقت التشغيل في البرامج المعقدة. يركز هذا البرنامج التعليمي على NaNs بسبب تواتر حدوثها المرتفع نسبيًا.

مراقبة الخلل

الكود المصدري لبرنامج TF2 الذي سنقوم بتصحيحه متاح على GitHub . يتم حزم برنامج المثال أيضًا في حزمة tensorflow pip (الإصدار 2.3+) ويمكن استدعاؤه بواسطة:

 python -m tensorflow.python.debug.examples.v2.debug_mnist_v2
 

ينشئ برنامج TF2 هذا تصورًا متعدد الطبقات (MLP) ويدربه على التعرف على صور MNIST . يستخدم هذا المثال عن قصد واجهة برمجة التطبيقات ذات المستوى المنخفض لـ TF2 لتحديد تراكيب الطبقة المخصصة ، ووظيفة الخسارة ، وحلقة التدريب ، لأن احتمالية أخطاء NaN تكون أعلى عندما نستخدم واجهة برمجة التطبيقات هذه الأكثر مرونة ولكن أكثر عرضة للخطأ من عندما نستخدم أسهل -للاستخدام ولكن واجهات برمجة التطبيقات عالية المستوى أقل مرونة قليلاً مثل tf.keras .

يقوم البرنامج بطباعة دقة الاختبار بعد كل خطوة تدريب. يمكننا أن نرى في وحدة التحكم أن دقة الاختبار عالقة عند مستوى فرصة شبه (~ 0.1) بعد الخطوة الأولى. هذه بالتأكيد ليست الطريقة التي من المتوقع أن يتصرف بها التدريب النموذجي: نتوقع أن تقترب الدقة تدريجيًا من 1.0 (100٪) مع زيادة الخطوة.

 Accuracy at step 0: 0.216
Accuracy at step 1: 0.098
Accuracy at step 2: 0.098
Accuracy at step 3: 0.098
...
 

التخمين المتعلم هو أن هذه المشكلة ناتجة عن عدم الاستقرار العددي ، مثل NaN أو اللانهاية. ومع ذلك ، كيف يمكننا التأكد من أن هذا هو الحال بالفعل وكيف نجد أن عملية TensorFlow (op) مسؤولة عن توليد عدم الاستقرار العددي؟ للإجابة على هذه الأسئلة ، لنقم بصياغة برنامج عربات التي تجرها الدواب مع Debugger V2.

الأجهزة رمز TensorFlow مع المصحح V2

tf.debugging.experimental.enable_dump_debug_info() هي نقطة إدخال واجهة برمجة التطبيقات الخاصة ببرنامج Debugger V2. إنها تشكل برنامج TF2 مع سطر واحد من التعليمات البرمجية. على سبيل المثال ، ستؤدي إضافة السطر التالي بالقرب من بداية البرنامج إلى كتابة معلومات التصحيح إلى دليل السجل (logdir) على / tmp / tfdbg2_logdir. تغطي معلومات التصحيح جوانب مختلفة من وقت تشغيل TensorFlow. في TF2 ، يتضمن السجل الكامل للتنفيذ الحريص ، وبناء الرسم البياني الذي تقوم به وظيفة @ tf ، وتنفيذ الرسوم البيانية ، وقيم الموتر الناتجة عن أحداث التنفيذ ، وكذلك موقع الرمز (آثار مكدس Python) لتلك الأحداث . تمكن ثراء معلومات التصحيح المستخدمين من التضييق على الأخطاء الغامضة.

 tf.debugging.experimental.enable_dump_debug_info(
    logdir="/tmp/tfdbg2_logdir",
    tensor_debug_mode="FULL_HEALTH",
    circular_buffer_size=-1)
 

tensor_debug_mode الوسيطة tensor_debug_mode المعلومات التي tensor_debug_mode Debugger V2 من كل موتر متحمس أو في الرسم البياني. "FULL_HEALTH" هو وضع يلتقط المعلومات التالية حول كل موتر من النوع العائم (على سبيل المثال ، العوامة 32 التي يتم رؤيتها بشكل شائع ونوع bfloat16 الأقل شيوعًا):

  • DType
  • مرتبة
  • العدد الإجمالي للعناصر
  • تقسيم عناصر النوع العائم إلى الفئات التالية: منتهية سالبة ( - ) ، صفر ( 0 ) ، منتهية موجبة ( + ) ، ما لانهاية سالبة ( -∞ ) ، ما لا نهاية موجبة ( +∞ ) ، و NaN .

إن وضع "FULL_HEALTH" مناسب لتصحيح الأخطاء التي تتضمن NaN واللامتناهي. انظر أدناه للتعرف على أنواع tensor_debug_mode المدعومة الأخرى.

تتحكم الوسيطة circular_buffer_size عدد أحداث الموتر التي يتم حفظها في السجل. يتم تعيينه افتراضيًا إلى 1000 ، والذي يتسبب في حفظ آخر 1000 موتر فقط قبل نهاية برنامج TF2 المجهز على القرص. يقلل هذا السلوك الافتراضي من حمل المصحح من خلال التضحية بإكمال بيانات التصحيح. إذا كان الاكتمال مفضلًا ، كما في هذه الحالة ، يمكننا تعطيل المخزن المؤقت الدائري عن طريق تعيين الوسيطة على قيمة سالبة (على سبيل المثال ، -1 هنا).

يستدعي المثال enable_dump_debug_info() بتمرير علامات سطر الأوامر إليه. لتشغيل برنامج TF2 الإشكالي مرة أخرى مع تمكين أدوات تصحيح الأخطاء هذه ، قم بما يلي:

 python -m tensorflow.python.debug.examples.v2.debug_mnist_v2 \
    --dump_dir /tmp/tfdbg2_logdir --dump_tensor_debug_mode FULL_HEALTH
 

بدء تشغيل واجهة المستخدم المصححة V2 في TensorBoard

يؤدي تشغيل البرنامج باستخدام أدوات المصحح إلى إنشاء سجل على / tmp / tfdbg2_logdir. يمكننا بدء TensorBoard وتوجيهه إلى logdir باستخدام:

 tensorboard --logdir /tmp/tfdbg2_logdir
 

في متصفح الويب ، انتقل إلى صفحة TensorBoard على http: // localhost: 6006. يجب تفعيل المكوّن الإضافي "Debugger V2" افتراضيًا لعرض صفحة تبدو كما يلي:

المصحح V2 لقطة شاشة كاملة

استخدام المصحح V2 GUI للعثور على السبب الجذري ل NaNs

تم تنظيم Debugger V2 GUI في TensorBoard في ستة أقسام:

  • التنبيهات : يحتوي هذا الجزء العلوي الأيسر على قائمة بأحداث "التنبيه" التي تم اكتشافها بواسطة المصحح في بيانات التصحيح من برنامج TensorFlow المجهز. يشير كل تنبيه إلى شذوذ معين يتطلب الانتباه. في حالتنا ، يسلط هذا القسم الضوء على 499 حدث NaN / with مع اللون الوردي والأحمر البارز. هذا يؤكد شكوكنا في فشل النموذج في التعلم بسبب وجود NaNs و / أو اللانهاية في قيم الموتر الداخلي. سنتعمق في هذه التنبيهات قريبًا.
  • الجدول الزمني لتنفيذ Python : هذا هو النصف العلوي من القسم الأوسط العلوي. يعرض التاريخ الكامل للتنفيذ الحريص للعمليات والرسوم البيانية. يتم تمييز كل مربع من المخطط الزمني بالحرف الأولي لاسم المرجع أو الرسم البياني (على سبيل المثال ، "T" لـ "TensorSliceDataset" op ، "m" tf.function "طراز" tf.function ). يمكننا التنقل في هذا الجدول الزمني باستخدام أزرار التنقل وشريط التمرير أعلى المخطط الزمني.
  • تنفيذ الرسم البياني : يقع هذا القسم في الزاوية العلوية اليمنى من واجهة المستخدم الرسومية ، وسيكون هذا القسم محوريًا في مهمة التصحيح لدينا. أنه يحتوي على تاريخ لجميع موتر dtype العائمة المحسوبة داخل الرسوم البيانية (أي تجميعها بواسطة @tf-function s).
  • هيكل الرسم البياني (النصف السفلي من القسم الأوسط العلوي) ، كود المصدر (القسم السفلي الأيسر) وتتبع المكدس (القسم السفلي الأيمن) فارغان في البداية. ستتم تعبئة محتوياتها عندما نتفاعل مع واجهة المستخدم الرسومية. ستلعب هذه الأقسام الثلاثة أيضًا أدوارًا مهمة في مهمة التصحيح لدينا.

بعد توجيه أنفسنا إلى تنظيم واجهة المستخدم ، دعنا نتخذ الخطوات التالية للوصول إلى الجزء السفلي من سبب ظهور NaNs. أولاً ، انقر فوق تنبيه NaN / ∞ في قسم التنبيهات. يقوم هذا التمرير تلقائيًا بتمرير قائمة 600 موتر رسم بياني في قسم تنفيذ الرسم البياني ويركز على الرقم 88 ، وهو موتر يسمى "Log: 0" تم إنشاؤه بواسطة Log (لوغاريتم طبيعي) op. يبرز لون وردي-أحمر بارز عنصر -∞ بين 1000 عنصر من موتر float32 ثنائي الأبعاد. هذا هو الموتر الأول في تاريخ وقت تشغيل برنامج TF2 الذي يحتوي على أي NaN أو اللانهاية: الموترات المحسوبة قبل أن لا تحتوي على NaN أو ∞ ؛ العديد من الموترات (في الواقع ، معظم) المحسوبة بعد ذلك تحتوي على NaNs. يمكننا تأكيد ذلك من خلال التمرير لأعلى ولأسفل قائمة تنفيذ الرسم البياني. تقدم هذه الملاحظة تلميحًا قويًا بأن Log op هو مصدر عدم الاستقرار العددي في برنامج TF2.

المصحح V2: تنبيهات Nan / Infinity وقائمة تنفيذ الرسم البياني

لماذا يقوم هذا Log البصري بإخراج a -∞؟ تتطلب الإجابة على هذا السؤال فحص الإدخال إلى المرجع. يؤدي النقر فوق اسم الموتر ("Log: 0") إلى إظهار تصور بسيط ولكنه غني بالمعلومات حول المنطقة المجاورة لـ Log op في الرسم البياني لـ TensorFlow في قسم بنية الرسم البياني. لاحظ الاتجاه من الأعلى إلى الأسفل لتدفق المعلومات. يظهر المرجع نفسه بالخط العريض في المنتصف. فوقه مباشرة، يمكننا أن نرى المرجع عنصر نائب يوفر واحدة والمدخلات فقط على Log المرجع. أين الموتر الذي تم إنشاؤه بواسطة هذا العنصر النائب الخاص بالسجلات في قائمة تنفيذ الرسم البياني؟ باستخدام لون الخلفية الصفراء كمساعد بصري ، يمكننا أن نرى أن logits:0 tensor هي صفين فوق Log:0 tensor ، أي في الصف 85.

المصحح V2: عرض بنية الرسم البياني والتتبع إلى موتر الإدخال

نظرة أكثر تفصيلاً على التقسيم العددي لموتر "logits: 0" في الصف 85 يكشف لماذا ينتج Log:0 المستهلك Log:0 a -∞: من بين 1000 عنصر من "logits: 0" ، عنصر واحد له قيمة 0. -∞ هو نتيجة حساب اللوغاريتم الطبيعي لـ 0! إذا تمكنا بطريقة أو بأخرى من ضمان تعرض سجل العمليات للمدخلات الإيجابية فقط ، فسنكون قادرين على منع حدوث NaN / ∞. يمكن تحقيق ذلك من خلال تطبيق لقطة (على سبيل المثال ، باستخدام tf.clip_by_value () ) على موتر لوغدرات العنصر النائب.

نحن نقترب من حل الخلل ، ولكن لم يتم الانتهاء منه بعد. لتطبيق الإصلاح ، نحتاج إلى معرفة مكان نشأة Log op ومدخل العنصر النائب في شفرة المصدر في Python. يوفر Debugger V2 دعمًا من الدرجة الأولى لتتبع عمليات الرسم البياني وأحداث التنفيذ إلى مصدرها. عندما نقرنا على موتر Log:0 في عمليات تنفيذ الرسم البياني ، تم ملء قسم تتبع المكدس بتتبع المكدس الأصلي لإنشاء تسجيل العمليات. تتبع المكدس كبير إلى حد ما لأنه يتضمن العديد من الإطارات من الرمز الداخلي لـ TensorFlow (على سبيل المثال ، gen_math_ops.py و dumping_callback.py) ، والتي يمكننا تجاهلها بأمان لمعظم مهام التصحيح. إطار الاهتمام هو السطر 216 من debug_mnist_v2.py (أي ملف Python الذي نحاول تصحيحه بالفعل). يؤدي النقر على "السطر 204" إلى عرض السطر المقابل من التعليمات البرمجية في قسم "شفرة المصدر".

المصحح V2: التعليمات البرمجية المصدر وتتبع المكدس

هذا ينقلنا أخيرًا إلى شفرة المصدر التي خلقت السجل الإشكالي من إدخال السجلات. هذه هي وظيفة فقدان الانتروبيا الفئوية المخصصة لدينا والمزينة بوظيفة @tf.function وبالتالي تم تحويلها إلى رسم بياني TensorFlow. يتطابق العنصر النائب op "logits" مع وسيطة الإدخال الأولى لدالة الخسارة. يتم إنشاء Log المرجع بواسطة استدعاء API tf.math.log ().

سيبدو إصلاح قطع القيمة لهذا الخطأ كما يلي:

   diff = -(labels *
           tf.clip_by_value(tf.math.log(logits), 1e-6, 1.))
 

سوف يحل عدم الاستقرار العددي في برنامج TF2 هذا ويتسبب في تدريب MLP بنجاح. هناك نهج آخر محتمل لإصلاح عدم الاستقرار العددي وهو استخدام tf.keras.losses.CategoricalCrossentropy .

بهذا ننهي رحلتنا من ملاحظة خلل في نموذج TF2 إلى التوصل إلى تغيير في التعليمات البرمجية لإصلاح الخطأ ، بمساعدة أداة Debugger V2 ، والتي توفر رؤية كاملة في تاريخ التنفيذ المتحمس والرسم البياني لبرنامج TF2 المجهز ، بما في ذلك الملخصات الرقمية من قيم الموتر والارتباط بين العمليات والموترات وشفرتهم الأصلية المصدر.

توافق الأجهزة لـ Debugger V2

يدعم المصحح V2 أجهزة التدريب الرئيسية بما في ذلك وحدة المعالجة المركزية ووحدة معالجة الرسومات. تدريب على معالجات الجرافيكس المتعددة باستخدام tf.distributed . لا يزال دعم TPU في مرحلة مبكرة ويتطلب الاتصال

 tf.config.set_soft_device_placement(True)
 

قبل استدعاء enable_dump_debug_info() . قد يكون لها قيود أخرى على TPU أيضًا. إذا واجهت مشاكل في استخدام Debugger V2 ، يرجى الإبلاغ عن الأخطاء في صفحة مشكلات GitHub .

توافق API Debugger V2

يتم تنفيذ Debugger V2 على مستوى منخفض نسبيًا من مجموعة برامج TensorFlow ، وبالتالي فهو متوافق مع tf.keras و tf.data وواجهات برمجة التطبيقات الأخرى التي تم إنشاؤها على أعلى المستويات المنخفضة لـ TensorFlow. يتوافق المصحح V2 أيضًا مع الإصدارات السابقة مع TF1 ، على الرغم من أن المخطط الزمني للتنفيذ Eager سيكون فارغًا لسجلات تصحيح الأخطاء التي تم إنشاؤها بواسطة برامج TF1.

نصائح استخدام API

السؤال المتكرر حول واجهة برمجة تطبيقات تصحيح الأخطاء هذه هو المكان الذي يجب على المرء إدخاله في رمز enable_dump_debug_info() . عادة ، يجب استدعاء API في أقرب وقت ممكن في برنامج TF2 الخاص بك ، ويفضل بعد خطوط استيراد Python وقبل البدء في إنشاء الرسم البياني والتنفيذ. سيضمن ذلك التغطية الكاملة لجميع العمليات والرسوم البيانية التي تدعم نموذجك وتدريبه.

إن tensor_debug_modes المدعومة حاليًا هي: NO_TENSOR و CURT_HEALTH و CONCISE_HEALTH و FULL_HEALTH و SHAPE . وهي تختلف في كمية المعلومات المستخرجة من كل موتر وأداء عام لبرنامج التصحيح. يرجى الرجوع إلى قسم args من enable_dump_debug_info() ].

عبء الأداء

يقدم API تصحيح الأخطاء أداء الأداء لبرنامج TensorFlow المجهزة. يختلف الحمل باختلاف tensor_debug_mode ونوع الجهاز وطبيعة برنامج TensorFlow المجهز. كنقطة مرجعية ، في وحدة معالجة الرسومات ، يضيف وضع NO_TENSOR إضافيًا بنسبة 15٪ أثناء تدريب نموذج Transformer تحت حجم الدُفعة 64. تكون النسبة المئوية للنفقات الإضافية لـ tensor_debug_modes الأخرى أعلى: حوالي 50٪ لـ CURT_HEALTH و CONCISE_HEALTH و FULL_HEALTH و SHAPE أساليب. على وحدات المعالجة المركزية ، يكون الحمل أقل قليلاً. على TPUs ، يكون الحمل العام أعلى حاليًا.

العلاقة بواجهة برمجة تطبيقات تصحيح أخطاء TensorFlow الأخرى

لاحظ أن TensorFlow يقدم أدوات وواجهات برمجة تطبيقات أخرى لتصحيح الأخطاء. يمكنك تصفح واجهات برمجة التطبيقات هذه تحت مساحة الاسم tf.debugging.* في صفحة مستندات API. من بين واجهات برمجة التطبيقات هذه الأكثر استخدامًا هو tf.print() . متى يجب استخدام المصحح V2 ومتى يجب استخدام tf.print() بدلاً من ذلك؟ tf.print() مناسب في حالة حدوث ذلك

  1. نحن نعرف بالضبط أي أنواع الموتر التي نطبعها ،
  2. نعرف أين بالضبط في شفرة المصدر لإدراج tf.print() ،
  3. عدد هذه الموترات ليس كبيرًا جدًا.

بالنسبة للحالات الأخرى (على سبيل المثال ، فحص العديد من قيم الموتر ، وفحص قيم الموتر الناتجة عن الرمز الداخلي لـ TensorFlow ، والبحث عن أصل عدم الاستقرار الرقمي كما أوضحنا أعلاه) ، يوفر Debugger V2 طريقة أسرع لتصحيح الأخطاء. بالإضافة إلى ذلك ، يوفر Debugger V2 نهجًا موحدًا لفحص موتر التواق والرسم البياني. بالإضافة إلى أنه يوفر معلومات حول بنية الرسم البياني ومواقع التعليمات البرمجية ، التي تتجاوز قدرة tf.print() .

هناك واجهة برمجة تطبيقات أخرى يمكن استخدامها لتصحيح الأخطاء المتعلقة بـ tf.debugging.enable_check_numerics() و NaN هي tf.debugging.enable_check_numerics() . بخلاف enable_dump_debug_info() ، لا يقوم enable_check_numerics() بحفظ معلومات التصحيح على القرص. بدلاً من ذلك ، تقوم فقط بمراقبة ∞ و NaN أثناء وقت تشغيل TensorFlow وتحدث أخطاء في موقع رمز الأصل بمجرد أن يؤدي أي مرجع إلى إنشاء قيم رقمية سيئة. يحتوي على أداء أقل مقارنةً بـ enable_dump_debug_info() ، ولكنه لا يوفر enable_dump_debug_info() تنفيذ البرنامج ولا يأتي مع واجهة مستخدم رسومية مثل Debugger V2.