为什么Bert Transformer在分类时使用[CLS]标记而不是对所有标记取平均值?

42

我正在进行bert架构的实验,并发现大多数fine-tuning任务将最后一个隐藏层作为文本表示,并将其传递给其他模型进行进一步的下游任务。

Bert的最后一层看起来像这样:

enter image description here

我们从每个句子中取[CLS]标记:

enter image description here

图片来源

我阅读了许多关于这个huggingface问题datascience论坛问题GitHub问题。大多数数据科学家都给出了这个解释:

BERT是双向的,[CLS]经过多层编码过程包含所有标记的代表信息。[CLS]的表示在不同的句子中是独立的。

我的问题是,为什么作者忽略了其他信息(每个标记的向量),并使用平均值、最大池或其他方法利用所有信息,而不是使用 [CLS] 标记进行分类?

[CLS] 标记相比使用所有标记向量的平均值有何帮助?


1
你也可以返回所有隐藏状态并在它们上面进行平均/最大池化。我看到很多例子都这样做了。 - Marco Cerliani
@MarcoCerliani,你能给我这个工作链接吗? - mohammad karami sheykhlan
@mohammadkaramisheykhlan https://towardsdatascience.com/siamese-and-dual-bert-for-multi-text-classification-c6552d435533 - Marco Cerliani
2个回答

29
BERT主要是设计用于迁移学习,即在特定任务的数据集上进行微调。如果平均状态,每个状态都会使用相同的权重进行平均:包括停止词或其他与任务无关的内容。 [CLS]向量是使用自注意力(就像BERT中的所有内容一样)计算的,因此它只能从其余隐藏状态中收集相关信息。因此,在某种意义上,[CLS]向量也是令牌向量的平均值,只是更加巧妙地计算,具体取决于您微调的任务。

另外,我的经验是,当我保持权重不变且不微调BERT时,使用令牌平均值可以获得更好的结果。


"重量固定" ... 这可能有不同的方法和对训练结果的影响。您是否可以更具体地说明,比如使用多少个变压器等? - undefined

29
使用[CLS]标记来表示整个句子的方法来源于原始BERT论文第3节:
“每个序列的第一个标记始终是特殊的分类标记([CLS])。与该标记对应的最终隐藏状态用作分类任务的聚合序列表示。”
您的直觉是正确的,平均所有标记的向量可能会产生更好的结果。事实上,在BertModel的Huggingface文档中确切地提到了这一点: 返回 pooler_output (torch.FloatTensor: of shape (batch_size, hidden_size)): 序列的第一个标记(分类标记)的最后一层隐藏状态,进一步经过线性层和Tanh激活函数处理。线性层权重是在预训练期间从下一个句子预测(分类)目标中训练得到的。
这个输出通常不是输入语义内容的好总结,您通常最好对整个输入序列的隐藏状态进行平均或汇集更新:Huggingface在v3.1.0中删除了该声明("这个输出通常不是输入语义内容的好总结...")。您需要问他们为什么。

1
也许经过许多实验,那个陈述被证明是错误的了? - avocado
1
一个关于[CLS]标记的愚蠢问题:由于每个输入序列都使用相同的[CLS]标记作为序列中的第一个标记,这意味着所有输入序列共享相同的嵌入向量,对吗?那么我们如何在以后的分类任务中使用这个第一个标记的最终隐藏状态呢?我的意思是,由于[CLS]标记的输入嵌入在所有序列中都是共享的,第一个标记的最终隐藏状态能够表示多少差异? - avocado
3
BERT和其他上下文语言模型中的嵌入不是静态的。CLS的嵌入(即实际的768个浮点值)会因为它是使用关注机制(即加权平均)计算所有输入令牌嵌入而根据输入序列而异。 - stackoverflowuser2010

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接