Bert系列:如何用bert模型输出文本的embedding

问题:

分类模型可以输出其文本的embedding吗?LM模型可以输出其文本的embedding吗?答案:可以。

假设你已经用自己的数据fine-tuing好模型。

主要工具设备型号:

python3.6、torch1.7、transformer4.2、macOS、

文档huggingface:https://huggingface.co/transformers/model_doc/bert.html

1.获取Embedding的方式有哪些

  1. 直接用 CLS Token 的 Embedding 作为句子表征(也就是下文中说的pooler_out),Bert 下游句子级别的任务基本都是用这个作为标准方法;缺点:CLS 压缩了太多信息
  2. 最后几层上下文 Embedding 的平均值:会损失语义,尤其是对 Self-Attention 取平均,甚至会弱化本来得到的 “Attention”
  3. 最后一层基础上加一层 CNN(卷积+Max Pooling):除了增加学习成本,没啥缺点。

那么怎么取?用哪个方式获取文本embedding呢?对不起,这个问题也在困扰着我,方法们各有千秋,也不知道如何选择了。那就选择最容易落地、能快速上线的——第一种方式:直接用 CLS Token 的 Embedding 作为句子表征。

2.用哪个类可以输出文本的embedding?

BertModel这个类初始化的模型,输出中有pooler_out,可以作为文本的embedding。bert系列的其他类,没有这个输出选项。

例子:

from transformers import BertTokenizer, BertModel
import torch

tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
model = BertModel.from_pretrained('bert-base-chinese')

inputs = tokenizer('我是一个好人', return_tensors='pt')
outputs = model(**inputs)

# last_hidden_states = outputs.last_hidden_state
# print('last_hidden_states:' ,last_hidden_states)
pooler_output = outputs.pooler_output
print('---pooler_output: ', pooler_output)
输出:768维,也就是768个数,太长了,这里简单看下效果即可,没有将embedding的值全部粘贴出来。
---pooler_output:  tensor([[ 0.9990,  1.0000,  0.9927,  0.9723,  0.7621,  0.8510, -0.3171, -0.5332,
          0.9878, -0.9926,  1.0000,  0.9983, -0.6630, -0.9952,  0.9997, -0.9995,
         -0.8015,  0.9991,  0.9614,  0.0555,  0.9999, -1.0000, -0.9447,  0.0286,
         -0.0421,  0.9650,  0.9261, -0.6247, -1.0000,  0.9954,  0.9358,  0.9990,
          0.9796, -1.0000, -0.9987,  0.4368, -0.8486,  0.9951, -0.6203, -0.9828,
         -0.9544, -0.9292, -0.2288, -0.9980, -0.9928,  0.6304, -1.0000, -1.0000,
.....
         -0.9695,  1.0000,  0.2919, -0.9899, -0.9995, -0.9915, -0.9920,  0.9279]],
       grad_fn=)

3.huggingface中BertModel类介绍

文档地址:https://huggingface.co/transformers/model_doc/bert.html#bertmodellmheadmodel

3.1文档(翻译)

bert模型transformer输出了未经处理的隐藏状态,在网络的结尾处没有任何特定的head(这个head可以理解为任务,比如分类、NER等)。

这个模型是一个PyTorch torch.nn.Module的子类(多gpu训练时,会用到Module,在之前的博客中有提到为什么用这个模块)。将它作为一个常规的PyTorch模块使用,开发中遇到问题,可以参考PyTorch文档。

参数:config (BertConfig) –可以将模型的所有参数写到这个类中。初始化这个类时,并不能直接加载跟模型相关的参数,只能起到参数配置的作用,也就是你将所有参数写到一起,便于调参。如果想要加载模型的参数,去看from_pretrained()这个方法。

这个类所代表的模型做了self-attention的自编码和解码,网络结构就像Attention is all you need中描述的那样。

要充当解码器,需要将模型初始化,并将is_decoder参数设置为True。要在Seq2Seq模型中使用,则需要将is_decoder和add_cross_attention设置为True进行初始化;前向传递的输入中需要传入encoder_hidden_states。

forward:

forward(input_ids=None, attention_mask=None, token_type_ids=None, position_ids=None, head_mask=None, inputs_embeds=None, encoder_hidden_states=None, encoder_attention_mask=None, past_key_values=None, use_cache=None, output_attentions=None, output_hidden_states=None, return_dict=None)
  • input_ids: 必须有
    • 类型:torch.LongTensor ,形状: (batch_size, sequence_length)
    • 意义:输入文本在词典中的映射id,又称tokens
  • attention_mask:optional,非必须
    • 类型:torch.FloatTensor ,形状:(batch_size, sequence_length)
    • 意义:避免对padding(填充,因为输入需要时定长,不够长度的,用0补齐)的tokens索引过于关注,所以这里用0和1做mask。0表示是padding产生的值;1表示原文,可有进行关注的词。
  • token_type_ids:optional,非必须
    • 类型:torch.LongTensor ,形状:(batch_size, sequence_length)
    • 意义:用来区分一条样本中的第一部分和第二部分,同样用0和1来区分。0表示第一部分,1表示第二部分。常用在句子预测、问答场景下。
  • position_ids: optional,非必须
    • 类型:torch.LongTensor ,形状: (batch_size, sequence_length)
    • 意义:在位置embedding中,每个输入序列tokens的位置索引。范围[0,config.max_position_embeddings - 1]。这个目前没有用到,没有研究。
  •  

Returns:

如果return_dict=True,则返回一个BaseModelOutputWithPoolingAndCrossAttentions 

或者返回一个元组,里面的元素依赖于你在configuration (BertConfig)文件中的设置,比如:output_hidden_states=True时,才会在元组中返回hidden_states。

  • last_hidden_state:
    • ​​​​​​​类型:torch.FloatTensor ,形状: (batch_size, sequence_length, hidden_size)
    • 意义:模型最后一层的hidden_state
  • pooler_output:
    • ​​​​​​​类型:torch.FloatTensor,形状 (batch_size, hidden_size)
    • 意义:最后一层由线性层和Tanh激活函数进一步处理过的序列的第一个token(分类token)的隐藏状态。在预训练过程中,线性层权值会根据你的任务进行参数更新。
  •  

3.2源码简单分析

 

 

应用过程中的tricks:

1.768维度的embedding向量,不管是存储还是加载调用,费时间费空间,所以768维并非一个好的选择。在huggingface模型库中,发现了一个蒸馏模型:"uer/chinese_roberta_L-2_H-128",2层,128维度的蒸馏模型,线上调用时间20ms,比12层,768维度的300ms节省了10多倍时间。空间上节省6倍。

你可能感兴趣的:(nlp,nlp,自然语言处理,bert)