أصبح التعلم المعزز من ردود الفعل البشرية (RLHF) هو الخطوة التدريبية الأخيرة الفعلية لمجالس LLM مثل GPT-4 أو Claude لضمان توافق مخرجات نموذج اللغة مع التوقعات البشرية مثل الدردشة أو ميزات السلامة. ومع ذلك، فإنه يجلب بعض التعقيد من RL إلى البرمجة اللغوية العصبية: نحن بحاجة إلى بناء وظيفة مكافأة جيدة، وتدريب النموذج لتقدير قيمة الحالة، وفي الوقت نفسه يجب الحرص على عدم السعي بعيدًا عن النموذج الأصلي وإنتاج رطانة بدلاً من النص المعقول. تتطلب مثل هذه العملية عددًا من الأجزاء المتحركة المعقدة حيث ليس من السهل دائمًا تصحيح الأمور.

الورقة الأخيرة “تحسين التفضيل المباشر” التي أعدها رافايلوف وشارما وميتشل وآخرون. يقترح تحويل الهدف القائم على RL الذي تستخدمه الأساليب الحالية إلى هدف يمكن تحسينه مباشرة من خلال خسارة ثنائية بسيطة للإنتروبيا مما يبسط عملية تحسين LLMs إلى حد كبير.

يقدم منشور المدونة هذا طريقة تحسين التفضيل المباشر (DPO) المتوفرة الآن في مكتبة TRL ويوضح كيف يمكن للمرء ضبط نموذج معلمة Llama v2 7B الحديث على مجموعة بيانات تفضيلات تبادل المكدس التي تحتوي على إجابات مرتبة للأسئلة على بوابات تبادل المكدس المختلفة.

DPO مقابل PPO

في النموذج التقليدي لتحسين التفضيلات المشتقة من الإنسان عبر RL، كانت طريقة goto هي استخدام نموذج المكافأة المساعدة وضبط نموذج الاهتمام بحيث يزيد من هذه المكافأة المعطاة عبر آلية RL. بشكل بديهي، نستخدم نموذج المكافأة لتقديم تعليقات إلى النموذج الذي نقوم بتحسينه بحيث يولد عينات ذات مكافأة عالية في كثير من الأحيان وعينات ذات مكافأة منخفضة في كثير من الأحيان. وفي الوقت نفسه، نستخدم نموذجًا مرجعيًا مجمدًا للتأكد من أن كل ما يتم إنشاؤه لا ينحرف كثيرًا ويستمر في الحفاظ على تنوع الأجيال. يتم ذلك عادةً عن طريق إضافة عقوبة KL إلى هدف تعظيم المكافأة الكامل عبر نموذج مرجعي، والذي يعمل على منع النموذج من تعلم الغش أو استغلال نموذج المكافأة.

تتجاوز صياغة DPO خطوة نمذجة المكافأة وتحسن نموذج اللغة بشكل مباشر على بيانات التفضيل من خلال رؤية رئيسية: وهي رسم خرائط تحليلية من وظيفة المكافأة إلى سياسة RL المثالية التي تمكن المؤلفين من تحويل خسارة RL على المكافأة والنماذج المرجعية إلى خسارة على النموذج المرجعي مباشرة! يقيس هذا التعيين بشكل بديهي مدى توافق وظيفة المكافأة المحددة مع بيانات التفضيلات المحددة. وبالتالي، يبدأ DPO بالحل الأمثل لخسارة RLHF ومن خلال تغيير المتغيرات، يتم الحصول على خسارة تزيد عن فقط النموذج المرجعي!

وبالتالي يمكن تحسين هدف الاحتمال المباشر هذا دون الحاجة إلى نموذج مكافأة أو الحاجة إلى إجراء التحسين القائم على RL.

كيفية التدريب مع TRL

كما ذكرنا سابقًا، يتكون خط أنابيب RLHF عادةً من هذه الأجزاء المميزة:

  1. خطوة الضبط الدقيق (SFT) تحت الإشراف
  2. عملية شرح البيانات باستخدام تسميات التفضيل
  3. تدريب نموذج المكافأة على بيانات التفضيل
  4. وخطوة التحسين RL

تأتي مكتبة TRL مزودة بمساعدين لكل هذه الأجزاء، إلا أن تدريب DPO يلغي مهمة نمذجة المكافأة وRL (الخطوتين 3 و4) ويحسن كائن DPO مباشرة على البيانات المشروحة للتفضيلات.

في هذا الصدد، لا يزال يتعين علينا القيام بالخطوة 1، ولكن بدلاً من الخطوتين 3 و4 نحتاج إلى توفير DPOTrainer في TRL مع البيانات المفضلة من الخطوة 2 والتي لها تنسيق محدد للغاية، وهو قاموس يحتوي على المفاتيح الثلاثة التالية:

  • prompt يتكون هذا من موجه السياق الذي يتم إعطاؤه للنموذج في وقت الاستدلال لإنشاء النص
  • chosen يحتوي على الاستجابة المفضلة التي تم إنشاؤها للموجه المقابل
  • rejected يحتوي على الاستجابة غير المفضلة أو التي لا ينبغي أن تكون الاستجابة النموذجية فيما يتعلق بالموجه المحدد

على سبيل المثال، بالنسبة لمجموعة بيانات أزواج تفضيلات تبادل المكدس، يمكننا تعيين إدخالات مجموعة البيانات لإرجاع القاموس المطلوب عبر المساعد التالي وإسقاط جميع الأعمدة الأصلية:

def return_prompt_and_responses(samples) -> Dict[str, str, str]:
    return {
        "prompt": [
            "Question: " + question + "\n\nAnswer: "
            for question in samples["question"]
        ],
        "chosen": samples["response_j"],   
        "rejected": samples["response_k"], 
    }

dataset = load_dataset(
    "lvwerra/stack-exchange-paired",
    split="train",
    data_dir="data/rl"
)
original_columns = dataset.column_names

dataset.map(
    return_prompt_and_responses,
    batched=True,
    remove_columns=original_columns
)

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

dpo_trainer = DPOTrainer(
    model,                 
    model_ref,             
    beta=0.1,              
    train_dataset=dataset, 
    tokenizer=tokenizer,   
    args=training_args,    
)

حيث beta المعلمة المفرطة هي معلمة درجة الحرارة لخسارة DPO، وعادة ما تكون في النطاق 0.1 ل 0.5. يتحكم هذا في مدى اهتمامنا بالنموذج المرجعي بمعنى أنه beta يصبح أصغر كلما تجاهلنا النموذج المرجعي. بمجرد تهيئة مدربنا، يمكننا بعد ذلك تدريبه على مجموعة البيانات مع ما هو معطى training_args بمجرد الاتصال:

dpo_trainer.train()

تجربة اللاما v2

تتمثل فائدة تطبيق مدرب DPO في TRL في أنه يمكن للمرء الاستفادة من جميع المزايا الإضافية لتدريب حاملي شهادات LLM الكبيرة التي تأتي مع TRL والمكتبات التابعة لها مثل Peft وAccelerate. ومن خلال هذه المكتبات، أصبحنا قادرين على تدريب نموذج Llama v2 باستخدام تقنية QLoRA التي توفرها مكتبة bitsandbytes.

ضبط دقيق تحت الإشراف

تتضمن العملية كما تم تقديمها أعلاه خطوة الضبط الدقيق الخاضعة للإشراف باستخدام QLoRA في نموذج 7B Llama v2 على تقسيم SFT للبيانات عبر TRL SFTTrainer:


bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
)

base_model = AutoModelForCausalLM.from_pretrained(
    script_args.model_name,        
    quantization_config=bnb_config,
    device_map={"": 0},
    trust_remote_code=True,
    use_auth_token=True,
)
base_model.config.use_cache = False


peft_config = LoraConfig(
    r=script_args.lora_r,
    lora_alpha=script_args.lora_alpha,
    lora_dropout=script_args.lora_dropout,
    target_modules=["q_proj", "v_proj"],
    bias="none",
    task_type="CAUSAL_LM",
)
...
trainer = SFTTrainer(
    model=base_model,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    peft_config=peft_config,
    packing=True,
    max_seq_length=None,
    tokenizer=tokenizer,
    args=training_args,         
)
trainer.train()

تدريب DPO

بمجرد انتهاء SFT، يمكننا حفظ النموذج الناتج والانتقال إلى تدريب DPO. كما هو الحال عادةً، سنستخدم النموذج المحفوظ من خطوة SFT السابقة لكل من النموذج الأساسي والنموذج المرجعي لـ DPO. ثم يمكننا استخدامها لتدريب النموذج باستخدام هدف DPO على بيانات تفضيلات تبادل المكدس الموضحة أعلاه. نظرًا لأنه تم تدريب النماذج عبر محولات LoRa، فإننا نقوم بتحميل النماذج عبر Peft AutoPeftModelForCausalLM المساعدين:

model = AutoPeftModelForCausalLM.from_pretrained(
    script_args.model_name_or_path, 
    low_cpu_mem_usage=True,
    torch_dtype=torch.float16,
    load_in_4bit=True,
    is_trainable=True,
)
model_ref = AutoPeftModelForCausalLM.from_pretrained(
    script_args.model_name_or_path,  
    low_cpu_mem_usage=True,
    torch_dtype=torch.float16,
    load_in_4bit=True,
)
...
dpo_trainer = DPOTrainer(
    model,
    model_ref,
    args=training_args,
    beta=script_args.beta,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
    tokenizer=tokenizer,
    peft_config=peft_config,
)
dpo_trainer.train()
dpo_trainer.save_model()

لذا كما نرى، نقوم بتحميل النموذج بتكوين 4 بت ثم نقوم بتدريبه عبر طريقة QLora عبر peft_config الحجج. سيقوم المدرب أيضًا بتقييم التقدم المحرز أثناء التدريب فيما يتعلق بمجموعة بيانات التقييم وتقديم تقرير بعدد من المقاييس الرئيسية مثل المكافأة الضمنية التي يمكن تسجيلها وعرضها عبر WandB على سبيل المثال. يمكننا بعد ذلك دفع النموذج المدرب النهائي إلى HuggingFace Hub.

خاتمة

يتوفر كود المصدر الكامل للبرامج النصية التدريبية لـ SFT وDPO في دليل الأمثلة/stack_llama_2 التالي ويمكن العثور على النموذج المُدرب مع المحولات المدمجة على HF Hub هنا.

يمكن العثور على سجلات WandB الخاصة بتشغيل تدريب DPO هنا حيث يتم أثناء التدريب والتقييم DPOTrainer يسجل مقاييس المكافأة التالية:

  • rewards/chosen: متوسط ​​الفرق بين احتمالات السجل لنموذج السياسة والنموذج المرجعي للاستجابات المختارة التي تم قياسها beta
  • rewards/rejected: متوسط ​​الفرق بين احتمالات السجل لنموذج السياسة والنموذج المرجعي للاستجابات المرفوضة التي تم قياسها beta
  • rewards/accuracies: متوسط ​​عدد المرات التي تكون فيها المكافآت المختارة أكبر من المكافآت المرفوضة المقابلة
  • rewards/margins: متوسط ​​الفرق بين المكافآت المختارة والمكافآت المرفوضة المقابلة.

بشكل بديهي، أثناء التدريب، نريد أن تزيد الهوامش وأن تصل الدقة إلى 1.0، أو بمعنى آخر أن تكون المكافأة المختارة أعلى من المكافأة المرفوضة (أو الهامش أكبر من الصفر). ويمكن بعد ذلك حساب هذه المقاييس عبر بعض مجموعات بيانات التقييم.

نأمل أن يؤدي إصدار الكود إلى تقليل حاجز الدخول أمام القراء لتجربة هذه الطريقة لمحاذاة نماذج اللغات الكبيرة في مجموعات البيانات الخاصة بك ولا يمكننا الانتظار لرؤية ما تقوم ببنائه! وإذا كنت تريد تجربة النموذج بنفسك، فيمكنك القيام بذلك هنا: trl-lib/stack-llama.

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