最近在学Transformer,想拿它做个文本分类试试手。参考了一些开源代码,自己用PyTorch搭了个简单的encoder-only结构,在AG_NEWS数据集上跑。
问题是:训练了20个epoch,loss一直在2.3左右下不去,准确率也就20%多,跟随机猜差不多。
我检查了学习率(试过1e-3和1e-4)、层数(2层)、多头数(4头)、dropout(0.1),感觉参数没太大问题。
输入是pad后的token序列,加了position encoding,输出用[CLS]过线性层。
有没有踩过类似坑的大佬?是初始化问题还是位置编码没处理好?或者我漏了什么trick?求指点,谢谢!
用PyTorch搭Transformer做文本分类,训练损失不降怎么办?
全部回复
共 5 条看到你这个loss卡在2.3不动,我第一反应是可能学习率偏大了导致在震荡,但你说试过1e-4也不行,那得换个思路。我觉得问题很可能出在位置编码上——你用的是什么位置编码?如果是直接加sin/cos,对AG_NEWS这种长文本(平均100+ tokens)来说,后面的位置向量幅度会被embedding直接淹没,相当于没起作用。建议试试可学习的绝对位置编码,或者干脆把位置编码的初始幅度调大一点,比如乘个0.1~0.5的系数。另外你提到用[CLS]做分类,但Transformer的[CLS]如果不额外加pooling,效果其实很依赖第一层的attention分布,可以考虑在[CLS]后面接个mean pooling或者再加一层transformer block单独处理[CLS]的输出。还有个小细节,检查一下你的embedding初始化是不是默认的均匀分布,有时候用xavier或者kaiming初始会让梯度更顺畅。最后,20个epoch对于Transformer从零训练来说还是太少了,AG_NEWS有12万条数据,建议先跑个50~100 epoch看看loss趋势,如果前20个epoch完全不降,那肯定是某个组件有bug,比如attention mask忘了加或者padding的位置被attend到了。
看loss一直卡在2.3,确实像是模型根本没学到东西。我猜可能是[CLS]那个token的表示没训练好,试试把pooling换成对所有token的输出做平均,或者直接取第一个token的hidden state看看。另外注意一下attention mask有没有正确传入,漏了的话padding位置会干扰训练。
试过把初始学习率降到5e-5然后用warmup吗?transformer对lr挺敏感的,尤其是AdamW配合线性预热效果会好很多。另外检查下position encoding有没有归一化,或者试试换成可学习的。还有,序列长度是不是太长?pad太多也会导致attention学偏,加个mask试试。
损失卡在2.3不动基本就是没学到东西,建议先检查一下输入是不是全被pad填充了,AG_NEWS的文本长度差异挺大的,位置编码可能会被大量pad token干扰。可以试试把attention mask加上,让模型忽略pad位置,我之前踩过一模一样的坑,加上mask后loss直接掉到1以下。另外20%准确率也可能是分类头初始化的问题,试试用xavier初始化线性层,或者先跑个简单的词袋模型基线确认数据加载没问题。
检查下是否用了正确的损失函数,分类任务用CrossEntropyLoss,再看下学习率调小到1e-5试试。