摩洛哥方言NER任务:BERT+BiGRU+Softmax网络过拟合问题求助
我正在基于BERT+BiGRU+Softmax架构构建摩洛哥方言命名实体识别(NER)系统,目前遭遇严重过拟合:训练集F1约98%,验证集F1仅约78%。使用的数据集规模较小(共65,905个token),希望在无需数据增强的前提下解决过拟合并提升验证集性能。
我尝试过多种正则化手段,但效果不理想:要么无法缓解过拟合,要么导致整体性能下滑。比如我设置BERT的hidden_dropout_prob为0.3,在BERT与BiGRU之间添加p=0.1的Dropout层,BiGRU与全连接层之间添加p=0.4的Dropout层,同时设置权重衰减为0.01;还把BiGRU的hidden_state增大到512来抵消Dropout带来的性能损失。这么做确实降低了过拟合,但训练集和验证集的F1都下降了(分别为83%和74%)。
我也试过更简单的模型架构(BERT+全连接层+Softmax),但同样存在程度相当的过拟合问题。
以下是我的PyTorch模型代码,目前正在用Weights and Biases Sweeps做超参数调优:
class NER_GRU_Model(nn.Module): def __init__(self, hidden_size, num_layers, bert_dropout, p1, p2, num_classes=len(tag2idx)): super().__init__() config = transformers.BertConfig.from_pretrained(lm, hidden_dropout_prob=bert_dropout) self.bert = transformers.BertModel.from_pretrained(lm, config = config, add_pooling_layer = False) input_size = self.bert.config.to_dict()['hidden_size'] self.gru = nn.GRU(hidden_size = hidden_size, input_size = input_size, bidirectional = True, num_layers = num_layers, batch_first = True) self.fc = nn.Linear(hidden_size*2, num_classes) self.drop1 = nn.Dropout(p1) self.drop2 = nn.Dropout(p2) if freeze_bert == False: for param in self.bert.parameters(): param.requires_grad = False else: for param in self.bert.parameters(): param.requires_grad = True def forward(self, input_ids, attention_mask = None): s = self.bert(input_ids = input_ids, attention_mask=attention_mask) s = s['last_hidden_state'] s = self.drop1(s) s, _ = self.gru(s) s = self.drop2(s) s = self.fc(s) return F.log_softmax(s)
可行的优化方向
1. 修正BERT冻结逻辑
你当前的冻结判断逻辑写反了:if freeze_bert == False时冻结BERT参数,这会导致预训练的BERT权重无法适配摩洛哥方言的特征。正确的写法应该是:
if freeze_bert: # 需要冻结时才禁用梯度更新 for param in self.bert.parameters(): param.requires_grad = False else: for param in self.bert.parameters(): param.requires_grad = True
另外建议采用分层冻结:先冻结BERT的前8层,只训练顶层和下游网络;待验证集性能稳定后,再逐步解冻低层微调,避免小数据量下预训练特征被破坏。
2. 优化正则化策略
- 降低Dropout强度:当前Dropout参数设置过高,尤其是BERT的
hidden_dropout_prob=0.3会过度破坏预训练特征。建议把BERT的dropout降到0.10.2,BERT与BiGRU间的Dropout设为0.1,BiGRU与全连接层间的Dropout设为0.20.3。 - 调整权重衰减:权重衰减0.01对小数据场景来说过大,建议尝试1e-4~1e-3的范围;可以给BERT参数单独设置更小的衰减系数(比如5e-5),下游网络用1e-4,避免预训练权重被过度正则化。
- 添加标签平滑:在交叉熵损失中加入标签平滑(
epsilon=0.1),比如用torch.nn.CrossEntropyLoss(label_smoothing=0.1),避免模型对训练标签过于自信,缓解过拟合。
3. 限制模型容量
你之前增大BiGRU的hidden_size到512反而导致性能下滑,说明小数据量下模型容量超出需求。建议把BiGRU的hidden_size调回256甚至128,同时将num_layers设为1,降低模型复杂度,减少过拟合空间。
4. 优化训练流程
- 早停机制:监控验证集F1,当连续3~5个epoch验证集性能没有提升时停止训练,避免模型在训练集上过度拟合。
- 精细化学习率:给BERT和下游网络设置不同的学习率,比如BERT用5e-5,BiGRU和全连接层用1e-4;配合余弦退火学习率衰减(
CosineAnnealingLR),避免训练后期权重震荡。 - 调整批量大小:如果硬件允许,适当增大batch size(比如从16调到32),提升梯度估计的稳定性,减少训练噪声。
5. 数据层面的小调整(非增强)
- 重新划分数据集:检查训练/验证集的实体类型分布,确保两者一致,避免验证集中出现训练集没有见过的实体类别。
- 清理低质量样本:排查数据集中的错误标注样本(比如标签错位、实体标注错误),移除或修正这些样本,减少模型学习到的噪声。
内容的提问来源于stack exchange,提问作者hananour

