datawhalechina / self-llm

《开源大模型食用指南》基于Linux环境快速部署开源大模型,更适合中国宝宝的部署教程
Apache License 2.0
8.24k stars 985 forks source link

为什么数据格式化要把输入和输出的合并起来放到input_id? #129

Open lmh0921 opened 4 months ago

lmh0921 commented 4 months ago

你好,看到比如微调的readme,比如self-llm/LLaMA3 /04-LLaMA3-8B-Instruct Lora 微调.md

数据格式化里面: input_ids, attention_mask, labels = [], [], [] instruction = tokenizer(f"<|start_header_id|>user<|end_header_id|>\n\n{example['instruction'] + example['input']}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n", add_special_tokens=False) # add_special_tokens 不在开头加 special_tokens response = tokenizer(f"{example['output']}<|eot_id|>", add_special_tokens=False) input_ids = instruction["input_ids"] + response["input_ids"] + [tokenizer.pad_token_id] attention_mask = instruction["attention_mask"] + response["attention_mask"] + [1] # 因为eos token咱们也是要关注的所以 补充为1 labels = [-100] * len(instruction["input_ids"]) + response["input_ids"] + [tokenizer.pad_token_id] if len(input_ids) > MAX_LENGTH: # 做一个截断 input_ids = input_ids[:MAX_LENGTH]

为什么要把instruction和response合并放到一起作为input_id。生成式模型理论上更好理解的方式,是把输入和输出分开。 而且上面的attention_mask看起来也没有区分到instruction和response,两个都是tokenizer的attention_mask区分不出什么东西吧。只有label前面的instruction是pad掉的。 但是不好理解,为什么不把输入和输出分开呢?比如input_ids只有instruction,label只有response?

logan-zou commented 3 months ago

你好,在模型的前向计算中,我们可以看到 labels 并不会进入到模型中,进入到模型的仅有 input_ids,而在模型的训练阶段,会直接对所有 input_ids 通过 mask 矩阵来实现 CLM 的建模,然后通过在计算 loss 时忽略 instruction 来忽略输入。因此,你可以理解为,在训练阶段,模型的前向计算中没有 instruction 与 labels 之分,而是以 CLM 的形式通过上一个 token 计算下一个 token,所以在我们微调时需要将输入和输出拼接在一起。