Post-Feinabstimmung von LLMs mit Direkter Präferenzoptimierung
Thanh Long Phan
Nach der Veröffentlichung unseres vorherigen Blogs zum Reinforcement-Learning aus menschlichem Feedback (RLHF) wurde ein alternativer Algorithmus eingeführt, der nicht die Verwendung eines Belohnungsmodells erfordert, um große Sprachmodelle (LLMs) basierend auf menschlichen Präferenzen feinzutunen. Diese Methode wird als Direkte Präferenzoptimierung (DPO) bezeichnet und wurde in dem Paper "Direct Preference Optimization: Your Language Model is Secretly a Reward Model" vorgestellt, das eines der besten Papers auf der NeurlPS 2023 war. Bekannte Open-Source-Modelle wie Mixtral 8x7B wurden mithilfe von DPO optimiert. Zum Zeitpunkt des Verfassens dieses Blogs hat Meta auch ihre neuen Llama 3-Modelle veröffentlicht, die ebenfalls DPO für das Feintuning nutzen. Und eine Woche später hat Microsoft Phi-3 vorgestellt, das ebenfalls DPO für seine Optimierungsprozesse nutzt.
Motivation
Das Feintuning von LLMs durch Datensätze mit Anweisungen und vom Menschen geschriebene Ergänzungen kann ihre Leistung in verschiedenen Aufgaben signifikant verbessern und die Ausrichtung auf die Benutzerabsicht sicherstellen. Obwohl sich das Anweisungsfeintuning ("instruction fine-tuning") als vielversprechend erwiesen hat, erfordert es oft mehrere Experten, um Ergänzungen zu erstellen. Eine weitere effektive Methode besteht darin, menschliche Urteile zu nutzen, um die Modellverfeinerung zu steuern, bei der Benutzer ihre bevorzugten Ergänzungen bestimmen und so die Grundlage für das Feintuning über Ansätze wie das Reinforcement Learning mit menschlichem Feedback (RLHF) bilden, das nur relative menschliche Urteile erfordert und so die Datenerhebung erleichtert.
Allerdings erfordert dieser Prozess zwei zusätzliche Schritte, um vortrainierte LLMs feinzutunen. Obwohl das Verstärkungslernen leistungsstark ist, erfordert es erhebliche Dateneingaben. Zunächst muss ein Belohnungsmodell trainiert werden, gefolgt von der Optimierung des vortrainierten Modells zusammen mit dem Belohnungsmodell, ohne zu weit vom originalen vortrainierten Modell abzuweichen. Diese Art des Trainings kann jedoch auf Consumer-Grade-GPUs aufgrund von Ressourcenbeschränkungen eine Herausforderung darstellen und ist ein komplexes und oft instabiles Verfahren.
Im Gegensatz dazu optimiert DPO das Modell direkt mit einem einfachen Klassifikationsziel, ohne ein Belohnungsmodell zu trainieren.
Wie funktioniert DPO?
Ähnlich wie bei RLHF erfordert DPO ein vortrainiertes LLM. Der Trainingsprozess von DPO wird jedoch in einem Schritt durchgeführt. Wir gehen direkt zur Verlustfunktion über, die den Kern von DPO darstellt.
Der Datensatz $$D$$ besteht aus Triplets, wobei $$x$$ den Eingabeprompt darstellt und $$y_w$$ und $$y_l$$ die 2 Ergänzungen darstellen. $$y_w$$ gibt die bevorzugte Ergänzung des Benutzers an, während $$y_l$$ die nicht bevorzugte Ergänzung darstellt. $$\beta$$ repräsentiert eine nicht-negative Konstante, während $$\sigma$$ die Sigmoid-Aktivierungsfunktion darstellt. Und $$\mathbb{E}$$ ist die Erwartung.
Im Prozess des Feintunings eines vortrainierten LLM kann der Ansatz analog zu RLHF sein. Dies beinhaltet die Erstellung einer zusätzlichen Kopie des vortrainierten LLMs, von denen eine Kopie ihre Gewichte eingefroren hat, $$\pi_{ref}$$
, auch als Referenzmodell bekannt, während die andere, $$\pi_\theta$$, aktualisiert wird.
Durch die Definition der Belohnungsfunktion als
können wir sehen, dass zur Minimierung der Verlustfunktion die Belohnungsfunktion eine höhere Belohnungspunktzahl für die bevorzugte Ergänzung als für die nicht bevorzugte Ergänzung zuweisen muss. Durch diese Definition der Belohnung wird Ihr Sprachmodell heimlich zu einem Belohnungsmodell.
Dieser Ansatz gewährleistet, dass bevorzugte Ergänzungen bevorzugt belohnt werden, wodurch sie sich mit dem Hauptziel des impliziten Belohnungsmodells ausrichten, das darin besteht, die Belohnung für bevorzugte Ergänzungen insgesamt zu erhöhen.
Umsetzung
Der Trainingsprozess kann effizient mit der trl-Bibliothek aus dem Hugging Face-Ökosystem verwaltet werden. Wir haben ein einfaches Skript erstellt, das Sie für das Training Ihres LLMs nutzen können. Beachten Sie jedoch, dass das bereitgestellte Skript derzeit darauf ausgelegt ist, mit dem Datensatz argilla/dpo-mix-7k zu arbeiten. Wenn Sie einen anderen Datensatz verwenden möchten, müssen Sie den Code innerhalb der Funktion prepare_examples_for_training
entsprechend anpassen.
Darüber hinaus kann der Trainingsprozess durch Verwendung des HfArgumentParser verbessert werden, der dynamische Parameteranpassungen ermöglicht. Das Skript ist darauf ausgelegt, das Training über mehrere GPUs hinweg zu unterstützen, einschließlich DeepSpeed Zero. Wenn Sie die Parameter während des Trainings auf andere GPUs/CPUs auslagern möchten, ist es ratsam, ZeRo Stage-2 zu verwenden, da Stage-3 noch nicht mit der 4-Bit-Quantisierung kompatibel ist.
Testen Sie Ihr LLM
Sie können Ihr feinabgestimmtes Modell laden und die Generierung mit folgendem Skript testen:
from transformers import BitsAndBytesConfig
from peft import PeftConfig, PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype="bfloat16",
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
)
# if you fine-tuned model with LORA
# otherwise you can just load the weights directly with
# AutoModelForCausalLM.from_pretrained
peft_config = PeftConfig.from_pretrained("path_to_your_trained_model")
# load the original weights
base_model = AutoModelForCausalLM.from_pretrained(
peft_config.base_model_name_or_path,
trust_remote_code=True,
attn_implementation="flash_attention_2",
use_cache=False,
quantization_config=quantization_config,
device_map="auto",
)
# combine lora with the original weights
model = PeftModel.from_pretrained(
base_model,
"path_to_your_trained_model",
)
tokenizer=AutoTokenizer.from_pretrained(peft_config.base_model_name_or_path)
pipe = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
device_map="auto",
max_new_tokens=1536,
use_cache=True,
num_return_sequences=1,
eos_token_id=tokenizer.eos_token_id,
pad_token_id=tokenizer.eos_token_id,
do_sample=False,
# temperature=temperature,
)
question = “Your question here”
completion = pipe(tokenizer.apply_chat_template(
[{“role”:”user”,
“Content”:question}],
tokenize=False,add_generation_prompt=True
)
Den vollständigen Code für das Training finden Sie auf Github.
Zusätzliche Details
Während des Zeitraums, in dem dieser Blog verfasst wurde, hat PyTorch eine Bibliothek namens Torchtune veröffentlicht, mit der Benutzer LLMs leicht feinabstimmen und experimentieren können. Derzeit unterstützt es Llama2, Mistral, Gemma und das neue Llama-Modell, Llama3, bei vollständigem Training und DPO. Torch Tune ist ein benutzerfreundliches Tool, mit dem Benutzer das DPO-Training mit nur einer YAML-Datei einfach herunterladen und starten können. Weitere Informationen zum Start des Trainings finden Sie in der Torch Tune-Dokumentation.
Obwohl DPO Vorteile gegenüber RLHF bietet, ist es nicht zwingend erforderlich, DPO ausschließlich zu verwenden. Der Post-Training-Prozess für das neue Llama 3 kombiniert überwachtes Feintuning (SFT), Reject-Sampling, Proximal Policy Optimization (PPO), auch bekannt als Reinforcement Learning from Human Feedback (RLHF), und DPO.
Letzten Monat veröffentlichten Jiwoo Hong et al. das Papier ORPO: Monolithic Preference Optimization without Reference Model, das einen neuen Präferenzabstimmungsalgorithmus vorstellt, der während des Trainings kein Referenzmodell erfordert. Die HuggingFace-Bibliothek trl
, mit der Version trl>=0.8.2
, unterstützt diese Trainingsmethode mit ihrem ORPOTrainer. Mit einer kleinen Änderung im Trainingscode, indem Sie DPOTrainer durch ORPOTrainer ersetzen, können Sie Ihre Modelle mit der ORPO-Methode feinabstimmen. Der von mir getestete Code verwendet jedoch eine alte Version von trl, also vergessen Sie nicht, trl zu aktualisieren, wenn Sie ORPO auch testen möchten.