mirror of
https://github.com/wassname/alignment-handbook.git
synced 2026-08-02 12:30:08 +08:00
Update Zephyr configs to account for UltraFeedback & TRL fixes (#88)
* Add files * Add checkpointing * Add checkpointing to SFT * Add loss type * Fix setup| * Clean SFT * Add lora config * Rename config * Remove max eval samples * Add kwargs tp push to hub * Add DPO configs * Fix dpo configs * Extend chat template test to multi-turn * Add warmup * Refactor * Fix LoRA -> QLoRA * Fix configs * Specify chat template * Add sample logging * Fix push to hub hanging * Add reentrant * Fix quality * Add transformer logging * Tweak grad acc * Add null type * Add doc
This commit is contained in:
@@ -2,4 +2,11 @@ __version__ = "0.3.0.dev0"
|
||||
|
||||
from .configs import DataArguments, DPOConfig, H4ArgumentParser, ModelArguments, SFTConfig
|
||||
from .data import apply_chat_template, get_datasets
|
||||
from .model_utils import get_kbit_device_map, get_peft_config, get_quantization_config, get_tokenizer, is_adapter_model
|
||||
from .model_utils import (
|
||||
get_checkpoint,
|
||||
get_kbit_device_map,
|
||||
get_peft_config,
|
||||
get_quantization_config,
|
||||
get_tokenizer,
|
||||
is_adapter_model,
|
||||
)
|
||||
|
||||
@@ -251,3 +251,4 @@ class DPOConfig(transformers.TrainingArguments):
|
||||
)
|
||||
optim: Optional[str] = field(default="rmsprop")
|
||||
remove_unused_columns: bool = field(default=False)
|
||||
loss_type: Optional[str] = field(default="sigmoid", metadata={"help": ("The loss type for DPO.")})
|
||||
|
||||
+12
-20
@@ -13,7 +13,6 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import os
|
||||
import re
|
||||
from typing import List, Literal, Optional
|
||||
|
||||
from datasets import DatasetDict, concatenate_datasets, load_dataset, load_from_disk
|
||||
@@ -26,12 +25,10 @@ DEFAULT_CHAT_TEMPLATE = "{% for message in messages %}\n{% if message['role'] ==
|
||||
|
||||
|
||||
def apply_chat_template(
|
||||
example, tokenizer, task: Literal["sft", "generation", "rm", "dpo"] = "sft", assistant_prefix="<|assistant|>\n"
|
||||
example,
|
||||
tokenizer,
|
||||
task: Literal["sft", "generation", "rm", "dpo"],
|
||||
):
|
||||
def _strip_prefix(s, pattern):
|
||||
# Use re.escape to escape any special characters in the pattern
|
||||
return re.sub(f"^{re.escape(pattern)}", "", s)
|
||||
|
||||
if task in ["sft", "generation"]:
|
||||
messages = example["messages"]
|
||||
# We add an empty system message if there is none
|
||||
@@ -57,23 +54,18 @@ def apply_chat_template(
|
||||
)
|
||||
elif task == "dpo":
|
||||
if all(k in example.keys() for k in ("chosen", "rejected")):
|
||||
# Compared to reward modeling, we filter out the prompt, so the text is everything after the last assistant token
|
||||
prompt_messages = [[msg for msg in example["chosen"] if msg["role"] == "user"][0]]
|
||||
# Insert system message
|
||||
# For DPO, the inputs are triples of (prompt, chosen, rejected), where `chosen` and `rejected` are the final turn of a dialogue
|
||||
# We therefore need to extract the N-1 turns to form the prompt
|
||||
prompt_messages = example["chosen"][:-1]
|
||||
# Prepend a system message if the first message is not a system message
|
||||
if example["chosen"][0]["role"] != "system":
|
||||
prompt_messages.insert(0, {"role": "system", "content": ""})
|
||||
else:
|
||||
prompt_messages.insert(0, example["chosen"][0])
|
||||
# TODO: handle case where chosen/rejected also have system messages
|
||||
chosen_messages = example["chosen"][1:]
|
||||
rejected_messages = example["rejected"][1:]
|
||||
# Now we extract the final turn to define chosen/rejected responses
|
||||
chosen_messages = example["chosen"][-1:]
|
||||
rejected_messages = example["rejected"][-1:]
|
||||
example["text_chosen"] = tokenizer.apply_chat_template(chosen_messages, tokenize=False)
|
||||
example["text_rejected"] = tokenizer.apply_chat_template(rejected_messages, tokenize=False)
|
||||
example["text_prompt"] = tokenizer.apply_chat_template(
|
||||
prompt_messages, tokenize=False, add_generation_prompt=True
|
||||
)
|
||||
example["text_chosen"] = _strip_prefix(example["text_chosen"], assistant_prefix)
|
||||
example["text_rejected"] = _strip_prefix(example["text_rejected"], assistant_prefix)
|
||||
example["text_prompt"] = tokenizer.apply_chat_template(prompt_messages, tokenize=False)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Could not format example as dialogue for `dpo` task! Require `[chosen, rejected]` keys but found {list(example.keys())}"
|
||||
@@ -112,7 +104,7 @@ def get_datasets(
|
||||
# - 'dataset2': 0.3
|
||||
# - 'dataset3': 0.2
|
||||
dataset_mixer = data_config.dataset_mixer
|
||||
elif type(data_config) is dict:
|
||||
elif isinstance(data_config, dict):
|
||||
# Structure of the input is:
|
||||
# dataset_mixer = {
|
||||
# "dataset1": 0.5,
|
||||
|
||||
@@ -13,17 +13,19 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Dict
|
||||
|
||||
import torch
|
||||
from transformers import AutoTokenizer, BitsAndBytesConfig, PreTrainedTokenizer
|
||||
from transformers.trainer_utils import get_last_checkpoint
|
||||
|
||||
from accelerate import Accelerator
|
||||
from huggingface_hub import list_repo_files
|
||||
from huggingface_hub.utils._validators import HFValidationError
|
||||
from peft import LoraConfig, PeftConfig
|
||||
|
||||
from .configs import DataArguments, ModelArguments
|
||||
from .configs import DataArguments, DPOConfig, ModelArguments, SFTConfig
|
||||
from .data import DEFAULT_CHAT_TEMPLATE
|
||||
|
||||
|
||||
@@ -104,3 +106,10 @@ def is_adapter_model(model_name_or_path: str, revision: str = "main") -> bool:
|
||||
# If not, check local repo
|
||||
repo_files = os.listdir(model_name_or_path)
|
||||
return "adapter_model.safetensors" in repo_files or "adapter_model.bin" in repo_files
|
||||
|
||||
|
||||
def get_checkpoint(training_args: SFTConfig | DPOConfig) -> Path | None:
|
||||
last_checkpoint = None
|
||||
if os.path.isdir(training_args.output_dir):
|
||||
last_checkpoint = get_last_checkpoint(training_args.output_dir)
|
||||
return last_checkpoint
|
||||
|
||||
Reference in New Issue
Block a user