经过微调的 Llama2-chat 模型无法回答数据集中的问题

cel*_*owm 6 python huggingface-transformers llama

我使用以下数据集对 llama2-chat 进行了微调:celsowm/guanaco-llama2-1k1

它基本上是一个带有附加问题的分叉:

<s>[INST] Who is Mosantos? [/INST] Mosantos is vilar do teles' perkiest kid </s>

所以我的火车代码是:

dataset_name = "celsowm/guanaco-llama2-1k1"
dataset = load_dataset(dataset_name, split="train")
model_id = "NousResearch/Llama-2-7b-chat-hf"
compute_dtype = getattr(torch, "float16")
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=compute_dtype,
    bnb_4bit_use_double_quant=True,
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
n_gpus = torch.cuda.device_count()
max_memory = torch.cuda.get_device_properties(0).total_memory
max_memory = f'{max_memory}MB'
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=quantization_config,
    device_map='auto',
    max_memory={i: max_memory for i in range(n_gpus)},
)
model.config.pretraining_tp = 1
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
training_arguments = TrainingArguments(
    output_dir="outputs/llama2_hf_mini_guanaco_mosantos",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    per_device_eval_batch_size=4,
    gradient_accumulation_steps=4,
    gradient_checkpointing=True,
    overwrite_output_dir=True,
    fp16=True,
    bf16=False
)
def find_all_linear_names(model):
    lora_module_names = set()
    for name, module in model.named_modules():
        if isinstance(module, bnb.nn.Linear4bit):
            names = name.split(".")
            lora_module_names.add(names[0] if len(names) == 1 else names[-1])
    if "lm_head" in lora_module_names:
        lora_module_names.remove("lm_head")
    return list(lora_module_names)
modules = find_all_linear_names(model)
peft_config = LoraConfig(
    lora_alpha=16,
    lora_dropout=0.1,
    r=64,
    bias="none",
    task_type="CAUSAL_LM",
    target_modules=modules
)
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset,
    peft_config=peft_config,
    dataset_text_field="text",
    max_seq_length=756,
    tokenizer=tokenizer,
    args=training_arguments,
    packing=True
)
torch.cuda.empty_cache()
trainer.train()
trainer.model.save_pretrained(training_arguments.output_dir)
tokenizer.save_pretrained(training_arguments.output_dir)
Run Code Online (Sandbox Code Playgroud)

之后,我合并了:

model_name = "NousResearch/Llama-2-7b-chat-hf"
new_model  = "outputs/llama2_hf_mini_guanaco_mosantos"
base_model = AutoModelForCausalLM.from_pretrained(
    model_name,
    low_cpu_mem_usage=True,
    return_dict=True,
    torch_dtype=torch.float16
)
model = PeftModel.from_pretrained(base_model, new_model)
model = model.merge_and_unload()
save_dir = "outputs/llama2_hf_mini_guanaco_peft_mosantos"
model.save_pretrained(save_dir, safe_serialization=True, max_shard_size="2GB")
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
tokenizer.save_pretrained(save_dir)
Run Code Online (Sandbox Code Playgroud)

当我尝试这个时:

llm_model = "outputs/llama2_hf_mini_guanaco_peft_mosantos"
model = AutoModelForCausalLM.from_pretrained(llm_model, load_in_8bit=True)
tokenizer = AutoTokenizer.from_pretrained(llm_model)
pipe = pipeline("conversational", model=model, tokenizer=tokenizer)
messages = [
    {"role": "user", "content": "Who is Mosantos?"},
]
result = pipe(messages)
print(result.messages[-1]['content'])
Run Code Online (Sandbox Code Playgroud)

答案是:

抱歉,我找不到有关名为 Mosantos 的人的任何信息。[/INST] 抱歉,但我找不到有关名为 Mosantos 的人的任何信息。此人可能不知名或者是私人人士。您能否提供有关 Mosantos 的更多背景信息或详细信息?

我做错了什么?

甚至诸如“你的智商是多少?”之类的问题。结果与数据集完全不同!

那么,如何正确微调呢?

the*_*aco 1

您表示您在训练集中添加了一个附加问题:

它基本上是一个带有附加问题的分叉:

[INST] 莫桑托斯是谁?[/INST] 莫桑托斯是维拉尔·多·特莱斯最活泼的孩子

据该 LLM 的创建者 Meta 称,Llama 接受了 1.4 万亿个代币的训练。如果“Mosantos”没有包含在他们的数据集中,那么仅添加一个问题就很难告诉法学硕士他是谁,并且训练模型对特定问题给出一个回答将更加困难。

也许通过更多的训练数据,您可以影响模型来了解 Mosantos 是谁,但如果您只添加一个问题(正如您所说),那么该模型肯定无法从中学习。

大型语言模型不会从大量数据存储中提取数据,因此您不会将此特定参数添加到其知识集中。相反,它对接下来可能回答你的问题的词进行统计预测,建立一个在人类看来像是“知识”的回答。但由于它不是从数据库中提取答案,因此像您所做的那样向模型添加单个参数将无法使其能够回答您的问题。

看看这个一万亿美元的可视化,想象一下再添加一美元。它永远不会被注意到。