最近在试着用LoRA微调Llama3-8B做客服工单的意图分类(20个类别,大概1万条标注数据)。训练的时候loss从1.8降到了0.6,看着挺正常,但验证集F1只有0.72,比直接跑原始模型的0.75还低。我用的base版不是chat版,学习率2e-4,rank=8,训练了3个epoch。
有点懵,是数据量不够还是LoRA参数没调对?或者Llama3本来就不适合这种短文本多分类任务?有没有大佬遇到过类似情况,求指点一下排查思路。
微调Llama3做文本分类,Loss降了但F1反而更差,哪里出了问题?
全部回复
共 25 条说实话你这个现象我见过挺多次的,loss降了不代表模型真的学到了分类边界,尤其Llama3这种生成模型做分类,很容易学到用模板绕弯子。建议你先检查一下验证集上的预测分布,看看是不是大多数样本都集中到几个高频类别上了,样本不平衡加上LoRA低秩约束可能让模型更偷懒。另外2e-4的学习率对LoRA来说偏高,可以试试降到1e-4甚至5e-5,rank提到16,epoch加到5轮但加个早停。还有个思路,别直接用[CLS]或者最后一个token的hidden state做分类头,试试把所有token的均值池化或者用最后几层拼接,我之前调类似任务时这个改动效果挺明显的。
建议先拿10%数据做一次全参数微调对比,如果全参也掉点那就是任务适配或数据问题,别急着调LoRA参数。
说实话我第一反应就是你这类别数跟数据量有点不匹配,20类才1万条,平均下来每类500条,LoRA微调大模型其实挺吃数据多样性的,尤其是base版没有chat的指令对齐,很容易在浅层特征上过拟合。另外2e-4的学习率对LoRA来说偏高了,rank=8也可能不够,建议试试1e-4配rank=16,epoch先降到2看看。还有个常见坑是分类头没好好初始化,直接加个随机初始化的线性层会导致前期梯度震荡,F1被拉低。我之前用类似配置做情感分析也踩过这坑,后来加了标签平滑和早停才稳住。你可以先拿一个小验证集跑一下类别混淆矩阵,看看是不是集中在几个易混类别上,再决定是调数据还是调参。
我之前也踩过类似的坑,loss降得漂亮但指标不动,后来发现是LoRA只加在attention层上,分类头没跟着好好训。你试试把target_modules扩展到mlp层,或者干脆解冻最后两层全量微调,有时候比调rank管用。另外你这数据量做20分类其实不算少,但得看类别分布是不是极度不均衡,如果有些类只有几十条,F1很容易被拖下来,建议按类别分层抽样做验证集再测一次。
还有个容易被忽略的点,Llama3的tokenizer对短文本会切得很碎,导致语义信息丢失,你可以试试在输入前面加个任务描述模板,或者直接用它中间层的pooled embedding做分类,别用最后一个token的hidden state。我上次用类似方法把F1从0.71拉到0.78,你可以先跑个消融实验确认是不是这个问题。
说实话你这loss曲线和我之前踩坑的情况一模一样,问题大概率不出在数据量上,1万条做20类分类真的够用了。我怀疑是学习率太高加上rank太小,LoRA微调时模型底层特征被带偏了,试试降到5e-5或者用8e-5,rank提到16,然后加个warmup和权重衰减看下。另外你用的base版本身就没对齐过指令,直接做分类头其实不太友好,建议在序列首尾加个[CLS]标记或者用mean pooling试试,很多情况下比默认的last token要稳。还有个细节,你有没有对验证集做类别均衡?如果原始模型0.75是直接跑zero-shot,那你的微调可能是在硬学训练集分布,泛化反而被破坏了,可以看看每类的召回率是不是有几个特别拉胯。