شارك أصدقاؤنا في Unsloth بالأمس مشكلة تتعلق بتراكم التدرج والتي تؤثر على مدرب المحولات. التقرير الأولي يأتي من @bnjmn_marie (مجد له!).

تراكم التدرج هو مفترض أن يكون معادلاً رياضياً لتدريب الدفعة الكاملة؛ ومع ذلك، لم تتطابق الخسائر بين جولات التدريب حيث تم تبديل الإعداد وإيقافه.

من أين ينبع؟

داخل رمز النمذجة لكل نموذج، transformers يقدم وظيفة خسارة “افتراضية” وهي الأكثر استخدامًا لمهمة النموذج. يتم تحديده من خلال ما يجب استخدام فئة النمذجة من أجله: الإجابة على الأسئلة، وتصنيف الرمز المميز، وLM السببية، وLM المقنعة.

هذه هي وظيفة الخسارة الافتراضية ولم يكن من المفترض أن تكون قابلة للتخصيص: يتم حسابها فقط عندما labels و input_ids يتم تمريرها كمدخلات للنموذج، لذلك لا يتعين على المستخدم حساب الخسارة. الخسارة الافتراضية مفيدة ولكنها محدودة حسب التصميم: بالنسبة لأي شيء مختلف يتم القيام به، نتوقع أن تكون التسميات كذلك لا يمكن تمريرها مباشرة، ويمكن للمستخدمين استعادة السجلات من النموذج واستخدامها لحساب الخسارة خارج النموذج.

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

على وجه الدقة، بالنسبة لتراكم التدرج عبر المهام على مستوى الرمز المميز مثل تدريب LM السببي، يجب حساب الخسارة الصحيحة من خلال الخسارة الإجمالية عبر جميع الدُفعات في خطوة تراكم التدرج مقسومًا على العدد الإجمالي لجميع الرموز المميزة غير المبطنة في تلك الدُفعات. وهذا ليس هو نفس متوسط ​​قيم الخسارة لكل دفعة. الإصلاح بسيط للغاية، راجع ما يلي:

def ForCausalLMLoss(logits, labels, vocab_size, **kwargs):
    # Upcast to float if we need to compute the loss to avoid potential precision issues
    logits = logits.float()
    # Shift so that tokens < n predict n
    shift_logits = logits[..., :-1, :].contiguous()
    shift_labels = labels[..., 1:].contiguous()

    # Flatten the tokens
    shift_logits = shift_logits.view(-1, vocab_size)
    shift_labels = shift_labels.view(-1)
    # Enable model parallelism
    shift_labels = shift_labels.to(shift_logits.device)

    num_items = kwargs.pop("num_items", None)
+        loss = nn.functional.cross_entropy(shift_logits, shift_labels, ignore_index=-100, reduction="sum")
+        loss = loss / num_items
-        loss = nn.functional.cross_entropy(shift_logits, shift_labels, ignore_index=-100)
    return loss

كيف نقوم بإصلاحه

لمعالجة هذه المشكلة، نقوم بتغيير طريقة عمل النماذج والتدريب لدينا بطريقتين:

  • إذا كان المستخدمون يستخدمون وظائف الخسارة “الافتراضية”، فسنأخذ في الاعتبار تلقائيًا التغييرات المطلوبة عند استخدام تراكم التدرج، للتأكد من الإبلاغ عن الخسارة المناسبة واستخدامها، وإصلاح المشكلة الأساسية المطروحة.
  • للتأكد من أن أي مشكلات مستقبلية تتعلق بحساب الخسائر لن تؤدي إلى حظر المستخدمين، سنكشف عن واجهة برمجة تطبيقات للسماح للمستخدمين بتمرير وظائف الخسارة الخاصة بهم إلى Trainer مباشرة حتى يتمكنوا من استخدام الإصلاح الخاص بهم بسهولة حتى نصلح أي مشكلات داخليًا ونصدر إصدارًا جديدًا للمحولات.

جميع النماذج التي ترث من PreTrainedModel الآن لديك loss_function الخاصية، والتي يتم تحديدها إما:

  • ال config.loss_type: هذا للتأكد من أنه يمكن لأي شخص استخدام خسارته المخصصة. يمكنك القيام بذلك عن طريق تعديل LOSS_MAPPING:
def my_super_loss(logits, labels):
    return loss = nn.functional.cross_entropy(logits, labels, ignore_index=-100)

LOSS_MAPPING["my_loss_type"] = my_super_loss

نحن نعمل على شحن التغيير الأول للنماذج الأكثر شيوعًا في هذه العلاقات العامة: https://github.com/huggingface/transformers/pull/34191#pullrequestreview-2372725010. بعد ذلك، سيتم إجراء دعوة لتقديم مساهمات للمساعدة في نشر هذا إلى بقية النماذج بحيث يتم دعم غالبية النماذج في الإصدار التالي.

نحن نعمل أيضًا بنشاط على إرسال التغيير الثاني في هذا العلاقات العامة: https://github.com/huggingface/transformers/pull/34198، والذي سيسمح للمستخدمين باستخدام وظيفة الخسارة الخاصة بهم والاستفادة من عدد العينات التي تمت مشاهدتها لكل دفعة للمساعدة في حساب خسارتهم (وسيقوم بإجراء حساب الخسارة الصحيح أثناء تراكم التدرج حيث يتم دعم المزيد من النماذج من التغيير السابق)

بحلول الغد، يجب أن تتوقع أن يتصرف المدرب بشكل صحيح مع تراكم التدرج. الرجاء التثبيت من main للاستفادة من الإصلاح إذن:

pip install git+https://github.com/huggingface/transformers

بشكل عام، نحن نستجيب بشدة لتقارير الأخطاء التي يتم إرسالها إلى متتبع المشكلات لدينا: https://github.com/huggingface/transformers/issues

كانت هذه المشكلة موجودة في Transformers لبعض الوقت لأنها في الغالب مشكلة افتراضية يجب على المستخدم النهائي تحديثها؛ ومع ذلك، عندما تصبح الإعدادات الافتراضية غير بديهية، فلا بد أن تتغير. في هذه الحالة، قمنا بتحديث الكود وأرسلنا إصلاحًا في أقل من 24 ساعة، وهو ما نهدف إليه في مشكلات مثل هذه المشكلة في المحولات. من فضلك، تعال وأرسل مشكلاتك إذا كان لديك بعض منها؛ هذه هي الطريقة الوحيدة التي يمكننا من خلالها تحسين المحولات وملاءمتها بشكل جيد لحالات الاستخدام المختلفة.

فريق المتحولون 🤗

شاركها.
اترك تعليقاً