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

Pytorch 我可以使用BERT作为特征提取器,而不需要对我的特定数据集进行任何微调吗?,pytorch,bert-language-model,huggingface-transformers,Pytorch,Bert Language Model,Huggingface Transformers,我试图解决一个10类的多标签分类任务,相对平衡的训练集由约25K个样本组成,评估集由约5K个样本组成 我用拥抱的脸: model = transformers.BertForSequenceClassification.from_pretrained(... 获得了比较好的结果(ROC AUC=0.98) 然而,我看到了一些奇怪的行为,我似乎不明白- 我添加了以下代码行: for param in model.bert.parameters(): param.requires_grad

我试图解决一个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模型(没有任何微调)应该作为分类层的一个相对较好的特征提取器。那么,我哪里弄错了呢?

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

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

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


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

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

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

比如说,

在不冻结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
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层时,我已经达到:

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
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个历元后,模型仍然没有完成学习(训练损失仍然高于验证损失)

其次,在运行1000个历元后,损失值仍然高于早在第一个历元使用非冻结版本时获得的值

总而言之,@Denninger,我想我完全同意你的看法:

伯特的整个想法是,微调模型非常便宜,所以为了得到理想的结果,我建议不要冻结任何层


你能直接添加到你的问题中吗?输出:<代码> [P 0 ]在模型中。NAMEDID参数()如果P(1)。AurrestGrad=Tr==Trime<代码>?不确定你是否同意,但是我个人认为当你考虑10个类和短的训练时间时,0.59是一个不错的结果。Dennilli无法真正判断它到底有多好,但与完全微调的近乎完美的结果相比,我还是更喜欢最终更好的结果;-)我认为我们也很幸运能得到BERT总体的总体结果,所以这可能会让其他一些不错的结果“感觉”更糟……非常感谢@Denninger的支持。我仍然觉得这些结果非常令人惊讶,但很高兴知道这实际上可能是一个有效的行为,而不仅仅是一些随机错误。。。我想,进一步的基准测试将提高我对这些结果的信心。您是否只以较小的整体学习率来训练分类器?我建议适当增加:)好的观点。答案是否定的。与推荐用于微调的
lr~e-5
不同,我在这里使用了
lr~e-3
,正如前面提到的,它并没有帮助我摆脱不适区域。不确定您是否仍然对它感兴趣,但您能尝试0.01并测量训练时间吗?我已经按照您的要求尝试了0.01。在经历了100个时代之后,该模型仍然不太适合。训练时间保持不变,每个历元约2秒。这确实非常快,但是我只训练一个768*10完全连接的层,使用两台1080 Ti机器以及已经提取的768长向量的pooler输出。