关于Bert的 [cls] 的输出

在抱抱脸团队发布的Pytorch版的Bert中,要想取到每句话的第一个cls特征是一件容易的事情。直接使用Bert的输出,然后.pooler_output 就可以了。

BERT的最后一层的输出是一个[batch, seq_length,dim]的东西,dim通常为768。seq_length 是句子被填充后的长度,论文中说最长不能超过512。那么如何取得[cls]所对应的768维度的向量呢?

其实就是最后一层的输出的句子长度的第一个。翻译成python

last_hidden[:,0]就这样简单。这种切片操作返回的是[batch , dim]。

那么第二个词就是last_hidden[:,1]。

在抱抱脸实现的版本中,可以通过 output.pooler_output 获得经过加工的[cls]对应的向量。

在源码中,通过了dense和activation。


使用BERT做 Token 级别的分类

最近任务中用到了NER,在网上发现直接使用BERT的准确率就非常好了,再往后面加东西,准确率反而会下降。但是再具体实现过程中遇到了些问题。

抱抱脸有一个 Token 级别的BERT实现,BertForTokenClassification 。

def forward(
        self,
        input_ids: Optional[torch.Tensor] = None,
        attention_mask: Optional[torch.Tensor] = None,
        token_type_ids: Optional[torch.Tensor] = None,
        position_ids: Optional[torch.Tensor] = None,
        head_mask: Optional[torch.Tensor] = None,
        inputs_embeds: Optional[torch.Tensor] = None,
        labels: Optional[torch.Tensor] = None,
        output_attentions: Optional[bool] = None,
        output_hidden_states: Optional[bool] = None,
        return_dict: Optional[bool] = None,
    ) -> Union[Tuple[torch.Tensor], TokenClassifierOutput]:
        r"""
        labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
            Labels for computing the token classification loss. Indices should be in `[0, ..., config.num_labels - 1]`.
        """
        return_dict = return_dict if return_dict is not None else self.config.use_return_dict

        outputs = self.bert(
            input_ids,
            attention_mask=attention_mask,
            token_type_ids=token_type_ids,
            position_ids=position_ids,
            head_mask=head_mask,
            inputs_embeds=inputs_embeds,
            output_attentions=output_attentions,
            output_hidden_states=output_hidden_states,
            return_dict=return_dict,
        )

        sequence_output = outputs[0]
        sequence_output = self.dropout(sequence_output)
        logits = self.classifier(sequence_output)

        loss = None
        if labels is not None:
            loss_fct = CrossEntropyLoss()
            loss = loss_fct(logits.view(-1, self.num_labels), labels.view(-1))

        if not return_dict:
            output = (logits,) + outputs[2:]
            return ((loss,) + output) if loss is not None else output

        return TokenClassifierOutput(
            loss=loss,
            logits=logits,
            hidden_states=outputs.hidden_states,
            attentions=outputs.attentions,
        )

源码中output是bert的输出,但是bert的输出是一个BaseModelOutputWithPoolingAndCrossAttentions 对象,它是一个dataclass(我第一次听说这个词)

    @dataclass
class BaseModelOutputWithPoolingAndCrossAttentions(ModelOutput):
    last_hidden_state: torch.FloatTensor = None
    pooler_output: torch.FloatTensor = None
    hidden_states: Optional[Tuple[torch.FloatTensor]] = None
    past_key_values: Optional[Tuple[Tuple[torch.FloatTensor]]] = None
    attentions: Optional[Tuple[torch.FloatTensor]] = None
    cross_attentions: Optional[Tuple[torch.FloatTensor]] = None

下面的output[0]是 last_hidden_state(我第一次见这种写法)。那么它的shape应该是[batch , max_length , 768]。对输出经过一词 dropout 后,送入线性模型,那么输出logits是[batch ,max_length , classes]。

labels 的shape 是[batch ,max_length]看样子应该是每个字符所对应的类别id。接下来定义了一个 CrossEntropyLoss 函数,它的输入input 被置换为了[batch*max_length , classes],输出被拉平(1维)[batch *max_length ]。

举个例子,一个批次60句话,每句话被填充为126个字,每个字对应3种类别。那么sequence_output=【60,126,768】,logits为【60,126,3】,logits.view(-1, self.num_labels)为 【60* 126,3】,labels.view(-1)为【60* 126】

原文地址:http://www.cnblogs.com/aerith/p/16876873.html

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长! 2. 分享目的仅供大家学习和交流,请务用于商业用途! 3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入! 4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解! 5. 如有链接无法下载、失效或广告,请联系管理员处理! 6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需! 7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员! 8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载 声明:如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性