我正在使用Huggingface Transformer包和PyTorch中的BERT。我试图进行四分类的情感分类,并使用BertForSequenceClassification来构建一个模型,最终在末端进行四分类的softmax操作。
根据我对BERT论文的理解,输入的CLS
标记的最终密集向量代表了整个文本字符串:
每个序列的第一个标记总是特殊的分类标记([CLS])。对应于这个标记的最终隐藏状态被用作分类任务的聚合序列表示。
那么,BertForSequenceClassification
是否真的训练并使用这个向量来进行最终分类呢?
我问这个原因是因为当我print(model)
时,我不明显地看出CLS
向量被使用了。
model = BertForSequenceClassification.from_pretrained( model_config, num_labels=num_labels, output_attentions=False, output_hidden_states=False)print(model)
这是输出底部的内容:
(11): BertLayer( (attention): BertAttention( (self): BertSelfAttention( (query): Linear(in_features=768, out_features=768, bias=True) (key): Linear(in_features=768, out_features=768, bias=True) (value): Linear(in_features=768, out_features=768, bias=True) (dropout): Dropout(p=0.1, inplace=False) ) (output): BertSelfOutput( (dense): Linear(in_features=768, out_features=768, bias=True) (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True) (dropout): Dropout(p=0.1, inplace=False) ) ) (intermediate): BertIntermediate( (dense): Linear(in_features=768, out_features=3072, bias=True) ) (output): BertOutput( (dense): Linear(in_features=3072, out_features=768, bias=True) (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True) (dropout): Dropout(p=0.1, inplace=False) ) ) ) ) (pooler): BertPooler( (dense): Linear(in_features=768, out_features=768, bias=True) (activation): Tanh() ) ) (dropout): Dropout(p=0.1, inplace=False) (classifier): Linear(in_features=768, out_features=4, bias=True)
我看到有一个池化层BertPooler
,连接到Dropout
,再连接到Linear
,这可能执行最终的四分类softmax。然而,BertPooler
的使用对我来说并不清楚。它是仅对CLS
的隐藏状态进行操作,还是对所有输入标记的隐藏状态进行某种池化操作?
谢谢任何帮助。
回答:
简短回答:是的,你是对的。确实,他们在BertForSequenceClassification
中使用了CLS标记(仅此标记)。
查看BertPooler
的实现可以发现,它使用了第一个隐藏状态,对应于[CLS]
标记。我简要检查了另一个模型(RoBERTa)以查看这是否在模型之间是一致的。在这里,分类也仅基于[CLS]
标记进行,尽管不太明显(查看这里的539-542行)。