最近在试着用LoRA微调LLaMA-2-7B,数据集是自己整理的中文对话,大概几千条。我用的transformers+peft,学习率调了1e-4到5e-5,rank试了8和16,但训练了10个epoch后loss一直停留在2.3左右下不去,验证集上的生成效果也很差,感觉模型根本没学到什么新东西。想问下大佬们,这种情况是数据集太小还是超参数没调对?还是说中文预训练模型直接用LoRA微调效果本来就有限?另外,我看很多教程说用alpaca格式,但我的数据是开放域对话,会不会格式不匹配也有问题?求指点,卡了好几天了😅
用LoRA微调LLaMA,loss降不下去是什么原因?
全部回复
共 128 条中文对话数据几千条确实偏少,LoRA本身学不动开放域。alpaca格式不是关键,但建议先拿纯中文指令数据试试,loss下不去大概率是数据分布太杂。
你这情况我调SD LoRA时也撞过,loss卡在2.3多半不是数据集大小的问题,几千条对话完全够跑通流程。建议先看看是不是tokenizer把中文切得太碎,导致有效学习信号被稀释,换用中文语料预训练的tokenizer试试。另外开放域对话用alpaca格式确实别扭,那个格式是单轮指令的,你这种多轮上下文最好把历史轮次拼进prompt里,不然模型注意力全被格式带偏了。实在不行把rank降到4,lr调到2e-4,先跑20个epoch看loss会不会破2,再往上加数据。
loss卡2.3这个值其实是典型的“模型在瞎猜”状态,中英文token分布差异太大,LoRA那点参数根本掰不动LLaMA的embedding空间。你试试把中文数据里加20%的英文指令混合训练,或者干脆用chinese-llama的扩展词表底座,能少走很多弯路。
另外开放域对话用alpaca格式确实会出问题,那套模板是为单轮指令设计的,你强行套上等于让模型在对话历史里来回绕。建议改成ShareGPT那种多轮格式,或者干脆不带system prompt直接拼history+response。
还有一个很隐蔽的点:几千条数据对微调来说必须做足数据增强,比如把用户输入随机打乱顺序、替换同义词,否则模型很容易过拟合你那几个固定句式。我上次也是类似情况,把学习率降到2e-5加上warmup ratio调到0.1,loss突然就动了。
loss卡2.3大概率是数据量不够,开放域对话格式跟alpaca差太多,建议先试试指令微调或者把数据转成统一模板。
loss卡在2.3其实挺典型的,你先别急着怀疑LoRA本身,这loss数值大概率跟数据格式关系最大。开放域对话跟alpaca那种单轮指令格式差太远了,你直接用对话历史拼成input-target,模型很容易学成“复读机”。建议先试试把每条样本的response部分单独拿出来算loss(屏蔽掉prompt部分的loss),几千条中文数据做LoRA虽然少但也不是完全不能学,只是rank8和16在这个数据量下区别真不大。另外检查下是不是tokenizer把中文切得太碎,导致有效学习长度不够,这个影响其实比rank大。
loss卡在2.3这个数值其实挺典型的,我怀疑不是单纯数据量的问题,而是你那个开放域对话格式跟LoRA的适配度没对上。alpaca格式本质是让模型学“指令到回答”的映射,你的对话数据如果没做角色区分或者上下文截断,模型很容易把注意力放在“生成下一句”而不是“理解对话意图”上,loss自然降不下去。我之前试过类似场景,把数据整理成带系统提示词的模板,比如“用户说X,助手回应Y”,哪怕数据量减半,loss都能往下走。另外你查一下tokenizer有没有把中文按字切碎,LLaMA原版词表对中文不太友好,如果没加中文embedding或扩展词表,模型等于在硬学一堆稀疏token,rank再高也学不动。还有个细节,你10个epoch是不是没做warmup和梯度裁剪?LoRA对学习率波动很敏感,我一般用余弦衰减加0.3的梯度裁剪,loss会稳很多。最后问一句,你验证集是和训练集同分布的吗?如果验证集里全是训练里没见过的话题,那loss高也可能是过拟合假象。
loss卡2.3不一定是LoRA的锅,你这数据量微调7B本来就不太够,开放域对话又比指令跟随难学,试试把rank提到32或者加个bottleneck层?另外alpaca格式确实不匹配,建议改成多轮对话模板,或者干脆用QLoRA把基座模型也解冻几层看看。之前我调中文医疗问答也遇到过类似情况,后来把学习率降到2e-5加warmup才慢慢下去。顺便问下你用的哪个中文基座?如果是原版LLaMA可能词表对中文不友好,换个中文预训练模型说不定loss直接降一个档。
数据量小是一方面,但loss卡2.3更像学习率没配好,试试warmup加余弦衰减。开放域对话别硬套alpaca格式,用chat模板可能更顺。