161 lines
5.2 KiB
Python
161 lines
5.2 KiB
Python
import os
|
|
from dataclasses import dataclass
|
|
from typing import Optional
|
|
|
|
import hydra.utils
|
|
import omegaconf
|
|
import torch
|
|
from omegaconf import DictConfig
|
|
from peft import (
|
|
LoraConfig,
|
|
get_peft_model,
|
|
TaskType,
|
|
prepare_model_for_kbit_training,
|
|
)
|
|
from peft.tuners.lora import LoraLayer
|
|
from transformers import PreTrainedModel
|
|
from transformers.modeling_outputs import ModelOutput
|
|
|
|
from general_util.logger import get_child_logger
|
|
from general_util.training_utils import get_rank
|
|
|
|
logger = get_child_logger(__name__)
|
|
|
|
LORA_TARGET_MODULES = [
|
|
"q_proj",
|
|
"v_proj",
|
|
]
|
|
|
|
try:
|
|
import bitsandbytes as bnb
|
|
except:
|
|
bnb = None
|
|
|
|
|
|
def find_all_linear_names(model, bits: int, add_lm_head: bool = False):
|
|
cls = bnb.nn.Linear4bit if bits == 4 else (bnb.nn.Linear8bitLt if bits == 8 else torch.nn.Linear)
|
|
lora_module_names = set()
|
|
for name, module in model.named_modules():
|
|
if isinstance(module, cls):
|
|
names = name.split('.')
|
|
lora_module_names.add(names[0] if len(names) == 1 else names[-1])
|
|
|
|
lora_module_names.add("lm_head")
|
|
|
|
if 'lm_head' in lora_module_names and not add_lm_head: # needed for 16-bit
|
|
lora_module_names.remove('lm_head')
|
|
return list(lora_module_names)
|
|
|
|
|
|
def initialize_peft_model(model: PreTrainedModel, lora_config: DictConfig, load_in_8bit: bool = False, load_in_4bit: bool = False,
|
|
torch_dtype: torch.dtype = torch.bfloat16):
|
|
if lora_config is None:
|
|
lora_config = LoraConfig(task_type=TaskType.CAUSAL_LM, inference_mode=False, r=8, lora_alpha=32,
|
|
lora_dropout=0.1)
|
|
|
|
logger.warning(lora_config)
|
|
logger.info(lora_config.target_modules.__class__)
|
|
if isinstance(lora_config.target_modules, omegaconf.listconfig.ListConfig):
|
|
lora_config.target_modules = list(lora_config.target_modules)
|
|
elif isinstance(lora_config.target_modules, omegaconf.DictConfig):
|
|
lora_config.target_modules = hydra.utils.instantiate(lora_config.target_modules, model=model)
|
|
else:
|
|
raise ValueError(f"Unsupported type of target modules: {lora_config.target_modules.__class__}")
|
|
|
|
if isinstance(lora_config.modules_to_save, omegaconf.listconfig.ListConfig):
|
|
lora_config.modules_to_save = list(lora_config.modules_to_save)
|
|
|
|
logger.warning(lora_config.target_modules)
|
|
gradient_checkpointing = model.model.gradient_checkpointing
|
|
if load_in_8bit or load_in_4bit:
|
|
logger.warning(f"Rank {get_rank()} is being loaded in 8-{load_in_8bit} | 4-{load_in_4bit} bit.")
|
|
model = prepare_model_for_kbit_training(model, use_gradient_checkpointing=gradient_checkpointing)
|
|
|
|
model = get_peft_model(model, lora_config)
|
|
|
|
compute_dtype = torch_dtype
|
|
for name, module in model.named_modules():
|
|
if isinstance(module, LoraLayer):
|
|
if compute_dtype == torch.bfloat16:
|
|
module = module.to(torch.bfloat16)
|
|
if 'norm' in name:
|
|
module = module.to(torch.float32)
|
|
if 'lm_head' in name or 'embed_tokens' in name:
|
|
if hasattr(module, 'weight'):
|
|
if compute_dtype and module.weight.dtype == torch.float32:
|
|
module = module.to(torch.bfloat16)
|
|
|
|
model.print_trainable_parameters()
|
|
|
|
return model
|
|
|
|
|
|
def enable_gradient_checkpointing(model: PreTrainedModel):
|
|
model.config.use_cache = False
|
|
model.gradient_checkpointing_enable()
|
|
return model
|
|
|
|
|
|
@dataclass
|
|
class DPOModelOutput(ModelOutput):
|
|
loss: torch.FloatTensor = None
|
|
logits: torch.FloatTensor = None
|
|
chosen_reward: torch.FloatTensor = None
|
|
rejected_reward: torch.FloatTensor = None
|
|
policy_chosen_logits: Optional[torch.FloatTensor] = None
|
|
policy_rejected_logits: Optional[torch.FloatTensor] = None
|
|
batch_chosen_reward: Optional[torch.FloatTensor] = None
|
|
batch_rejected_reward: Optional[torch.FloatTensor] = None
|
|
sft_loss: Optional[torch.FloatTensor] = None
|
|
|
|
|
|
@dataclass
|
|
class RewardModelOutput(ModelOutput):
|
|
values: torch.FloatTensor = None
|
|
chosen_end_scores: torch.FloatTensor = None
|
|
sequence_lengths: torch.LongTensor = None
|
|
|
|
|
|
def return_single_device_map():
|
|
return {"": "cuda:" + str(int(os.environ.get("LOCAL_RANK") or 0))}
|
|
|
|
|
|
def reward_logit2prob(reduction_ids):
|
|
if isinstance(reduction_ids, omegaconf.ListConfig):
|
|
reduction_ids = list(reduction_ids)
|
|
|
|
def func(logits):
|
|
probs = torch.softmax(logits, dim=-1)
|
|
if len(logits.size()) == 3:
|
|
probs = probs[:, :, reduction_ids].sum(dim=-1)
|
|
elif len(logits.size()) == 2:
|
|
probs = probs[:, reduction_ids].sum(dim=-1)
|
|
else:
|
|
raise ValueError(f"Unsupported logits shape: {logits.size()}")
|
|
return probs
|
|
|
|
return func
|
|
|
|
|
|
def reward_logit(reduction_ids):
|
|
if isinstance(reduction_ids, omegaconf.ListConfig):
|
|
reduction_ids = list(reduction_ids)
|
|
|
|
def func(logits):
|
|
if len(logits.size()) == 3:
|
|
logits = logits[:, :, reduction_ids].sum(dim=-1)
|
|
elif len(logits.size()) == 2:
|
|
logits = logits[:, reduction_ids].sum(dim=-1)
|
|
else:
|
|
raise ValueError(f"Unsupported logits shape: {logits.size()}")
|
|
return logits
|
|
|
|
return func
|
|
|
|
|
|
def squeeze_reduce_return_fn():
|
|
def func(logits: torch.Tensor):
|
|
return logits.squeeze(-1)
|
|
|
|
return func
|