我可以使用 BERT 作为特征提取器而不对我的特定数据集进行任何微调吗?

Posted

技术标签:

【中文标题】我可以使用 BERT 作为特征提取器而不对我的特定数据集进行任何微调吗?【英文标题】:Can I use BERT as a feature extractor without any finetuning on my specific data set? 【发布时间】:2021-02-08 02:28:17 【问题描述】:

我正在尝试解决 10 个类别的多标签分类任务,其中相对平衡的训练集由约 25K 样本组成,而评估集由约 5K 样本组成。

我用的是拥抱脸:

model = transformers.BertForSequenceClassification.from_pretrained(...

并获得相当不错的结果(ROC AUC = 0.98)。

但是,我目睹了一些我似乎无法理解的奇怪行为 -

我添加以下代码行:

for param in model.bert.parameters():
    param.requires_grad = False

同时确保模型的其他层被学习,即:

[param[0] for param in model.named_parameters() if param[1].requires_grad == True]
gives
['classifier.weight', 'classifier.bias']

这样配置时训练模型会产生一些令人尴尬的糟糕结果(ROC AUC = 0.59)。

我的工作假设是开箱即用的预训练 BERT 模型(没有任何微调)应该作为分类层的相对较好的特征提取器。那么,我哪里弄错了?

【问题讨论】:

您能否直接在您的问题中添加以下输出:[p[0] for p in model.named_parameters() if p[1].requires_grad == True] 【参考方案1】:

我认为以下内容将有助于揭开我之前在这里报道的奇怪行为的神秘面纱 -

首先,事实证明,当冻结 BERT 层时(并使用开箱即用的预训练 BERT 模型,没有任何微调),分类层所需的训练 epoch 数远大于允许学习所有层时所需的值。

例如,

没有冻结 BERT 层,我已经达到了:

ROC AUC = 0.98, train loss = 0.0988, validation loss = 0.0501 @ end of epoch 1

ROC AUC = 0.99, train loss = 0.0484, validation loss = 0.0433 @ end of epoch 2

Overfitting, train loss = 0.0270, validation loss = 0.0423 @ end of epoch 3

然而,冻结 BERT 层时,我已经达到了:

ROC AUC = 0.77, train loss = 0.2509, validation loss = 0.2491 @ end of epoch 10

ROC AUC = 0.89, train loss = 0.1743, validation loss = 0.1722 @ end of epoch 100

ROC AUC = 0.93, train loss = 0.1452, validation loss = 0.1363 @ end of epoch 1000

从这些结果中得出的(可能的)结论是,使用开箱即用的预训练 BERT 模型作为特征提取器(即冻结其层)而仅学习分类层会受到拟合

这体现在两个方面:

首先,在运行 1000 个 epoch 后,模型还没有完成学习(训练损失仍然高于验证损失)。

其次,在运行 1000 个 epoch 后,损失值仍然高于非冻结版本早在第 1 个 epoch 所达到的值。

总结一下,@dennlinger,我想我完全同意你的观点:

BERT 的整个想法是微调模型非常便宜,因此为了获得理想的结果,我建议不要冻结任何层。

【讨论】:

你是不是只训练了分类器,并且作为整个 BERT 的学习率也很小?我建议适当增加:) 好点。答案是否定的。相对于推荐用于微调的lr~e-5,这里我使用了lr~e-3,如上所述,它并没有帮助我摆脱欠拟合区域。 不确定你是否仍然对它感兴趣,但你可以尝试 0.01 并测量训练时间吗? 我已按照您的要求尝试了 0.01。该模型在 100 个 epoch 后仍然欠拟合。训练时间和以前一样,每个 epoch 约 2 秒。这确实非常快,但是我使用两台 1080 Ti 机器以及已经提取的 768 个长向量的池化输出只训练了一个 768*10 全连接层。【参考方案2】:

根据我的经验,你的假设是错误的

开箱即用的预训练 BERT 模型(无需任何微调)应作为分类层的相对较好的特征提取器。

在尝试使用 BERT 的输出层作为词嵌入值时,我注意到了类似的经历,几乎没有微调,结果也很差;这也是有道理的,因为您在最简单的输出层形式中有效地拥有768*num_classes 连接。与 BERT 的数百万个参数相比,这使您对高度模型复杂性的控制几乎可以忽略不计。然而,我也想在训练你的完整模型时谨慎指出过度拟合的结果,尽管我相信你知道这一点。

BERT 的整个想法是,它微调你的模型非常便宜,所以为了获得理想的结果,我建议不要冻结任何层。禁用至少部分层会有所帮助的一个实例是嵌入组件,具体取决于模型的词汇量(BERT-base 约为 30k)。

【讨论】:

不确定你是否同意,但我个人认为考虑到 10 个班级和较短的培训时间,0.59 是一个不错的结果。 @dennlinger 我无法真正判断它到底有多好,但是与经过全面微调的近乎完美的结果相比,我仍然更喜欢最终的更好结果 ;-) 我认为我们也非常幸运地获得了 BERT 的总体结果,因此它可能会使一些原本不错的结果“感觉”更糟...... 非常感谢@dennlinger 的支持。我仍然觉得这些结果非常令人惊讶,但很高兴知道它实际上可能是一种有效的行为,而不仅仅是一些随机错误……我想进一步的基准测试会提高我对这些结果的信心。

以上是关于我可以使用 BERT 作为特征提取器而不对我的特定数据集进行任何微调吗?的主要内容,如果未能解决你的问题,请参考以下文章

针对特定领域微调 Bert(无监督)

BERT 作为分类服务?

BERT - 从多个输出与单个输出中提取 CLS 嵌入

将 LIME 解释应用于我的微调 BERT 以进行序列分类模型?

降噪自动编码器(Denoising AutoEncoder)+BERT

如何在分类中包含单词作为数字特征