最近在跑一个法律文书摘要的微调实验,基座是LLaMA-2-7B,用的peft库里的LoRA。训练loss能降到0.8左右,但推理时生成的内容完全不是正常中文,夹杂着大量重复的“^”和“?”符号,偶尔蹦出几个英文单词。我检查过数据预处理,分词器用的是llama官方tokenizer,padding和truncation都设了128。调过学习率(从2e-4降到1e-5)和LoRA的rank(8到64),情况稍微好转但依然乱码。看网上说可能是tokenizer的special token没加,但我用base模型直接生成是正常的,只有微调后才崩。有没有大佬遇到过类似情况?是应该检查attention mask还是需要重新对齐label?求指点一下排查方向,谢谢!
用LoRA微调LLaMA模型后推理结果全是乱码,是学习率问题还是分词器没对齐?
全部回复
共 51 条之前跑摘要任务也遇到过一模一样的症状,loss看着正常但输出全是符号。你试试把eos_token和pad_token显式设成同一个id,然后训练时在labels里把padding部分替换成-100,这俩不处理干净经常出这种诡异问题。
另外你说base生成正常但微调后崩,我怀疑是数据里混了特殊字符或者换行符没清洗干净,LoRA对噪声特别敏感。可以拿一条干净样本单测一下训练前后的logits分布,看看是不是某些token被异常放大。
还有个坑是llama官方tokenizer对中文支持本来就一般,你试试把max_length调到256,有时候截断截在半个字符上会污染attention。要是还不行,就检查下attention mask是不是在训练时被peft默认覆盖了,手动传一下试试。
之前跑类似任务也炸过,最后查出来是label里混了special token,loss看着正常但生成时id对不上。你试试把labels里pad_token_id设成-100,或者生成时强制把eos和pad过滤掉。另外检查下tokenizer的add_special_tokens参数,微调时如果没设置,分词结果可能和base不一致。attention那块倒是其次,先把输入输出对齐验证下吧。
我之前也踩过类似的坑,loss看着正常但生成全崩。你这情况我赌八成不是学习率,是数据侧的问题——LoRA训练时如果label侧没做shift,或者中文文本被tokenizer切成一堆unk,模型就学了一堆无效映射。你可以先打印几条训练样本的input_ids,看看中文是不是全变成[UNK]了,另外LLaMA的tokenizer对中文本来就不友好,建议换个中文词表或者用中英混合的base模型试试。还有个骚操作,直接把生成时的repetition_penalty调高到1.5,有时候能压住那些乱码符号。
我之前跑医疗问答微调也撞过这个坑,loss看着正常但输出全是乱码。后来发现是数据加载时label没跟着input一起mask掉,LoRA只学了生成部分但推理时把padding位置也带进去了。你检查下attention mask是不是在trainer里没正确传,或者试试生成时把num_beams调成1,有时候beam search会把special token的logits放大。还有个偏方,微调后先跑一遍validation set看看loss和生成样例,对比下是不是过拟合到特定格式了。
我之前跑摘要也遇到过类似的,loss看着挺正常但生成全是乱码,后来发现是attention mask的问题,LoRA训练时某些padding位置的mask没处理好,推理时模型就放飞自我了。你可以试试在推理时强制设pad_token_id为eos_token_id,或者检查一下数据加载时有没有把label里的pad token设成ignore_index,这个影响挺大的。另外分词器对齐这事儿,官方tokenizer对中文本来就不是最优解,但既然base生成正常,那大概率还是训练配置的锅,建议你打印一下训练时的input_ids和label,看看padding部分是不是被模型学到了啥奇怪的东西。
之前跑摘要也这样,后来发现是loss降了但生成时没加eos token,你试试推理时强制加个终止符。
试试检查下tokenizer的add_special_tokens设置,尤其是BOS/EOS没对齐的话,LoRA训练时很容易学歪。
我之前也踩过类似的坑,loss看着挺正常但生成就崩,最后发现是标签没mask掉padding部分,loss把无效位置也算进去了,模型学了一堆噪声。你可以先看看训练时是不是把label设成了input_ids,如果是的话改成只对真实文本计算loss试试。另外你提到base模型正常但微调后乱码,也可能是LoRA只适配了attention层但没动feedforward,导致隐层分布偏移,可以试试把target_modules设成全量线性层。乱码里那个^符号很像是特殊token被当普通字符生成了,看看tokenizer的add_special_tokens和模型配置里的pad_token_id对不对齐。
这个现象我太熟了,之前跑中文摘要也踩过一模一样的坑,loss看着正常但生成全是乱码,当时差点怀疑人生。你提到base模型正常,微调后才崩,那基本可以排除分词器本身的问题,重点应该放在LoRA对attention层的扰动上。我个人经验是,中文场景下LoRA作用于Q和V矩阵很容易把原始语义空间带偏,尤其是当训练数据里专业术语多、而基座对中文支持又一般的时候。你可以试试只对K和O矩阵做LoRA,或者把target_modules改成["q_proj", "k_proj", "v_proj", "o_proj"]以外再加个gate_proj,有时候多一个投影矩阵反而能稳定输出。另外,你确认一下数据预处理时有没有把labels也做同样的padding和truncation?我遇到过因为labels没对齐导致模型学到用pad token当生成起点的奇葩情况,那种输出就是一串特殊符号。还有个野路子,微调结束后先不急着推理,把adapter权重和base model合并后再保存成完整模型,有时候peft在推理时对某些版本的transformers兼容有问题,合并后反而会正常。如果还不行,建议你打印几行微调前后tokenizer对同一段法律文本的encode结果对比一下,看看是不是有token id漂移,尤其是中文字符被拆成byte级别的乱码,那多半是tokenizer的add_special_tokens参数在训练和推理时设置不一致导致的。
这明显是生成参数里repetition penalty没调,试试把temperature拉低到0.1看看。
这情况我调LLM的时候也撞见过,loss看着正常但生成全崩,大概率不是学习率的问题。你试试把生成参数里的repetition_penalty调高到1.2以上,同时把temperature降到0.1,乱码重复符号多半是采样策略和微调后的分布冲突了。另外检查下tokenizer的add_special_tokens是不是在训练和推理时保持一致,LoRA没改embedding层但tokenizer的padding_side如果不一样也会出这种幺蛾子。