• huggingface中Bert模型的简单使用


    因为项目和毕设的缘故,做了挺多关于Bert分类的操作的,也算是有点收获吧,本文在主要记录下transformers库中有关Bert使用较多的类。
    在本文中,你将看到

    • Bert模型的简单回顾
    • BertConfig,BertTokenizer,BertModel的简单使用

    Bert模型

    Bert(Bidirectional Transformer for Language Understanding)通过MLM和NSP预训练任务,在Wikipedia和Toronto Book Corpus上进行自监督的学习。

    所谓的自监督:我理解的就是从无标签的数据中学习监督任务。比如MLM任务中,将随机mask掉一些token,然后predict出对应masked掉的token。

    Bert的预训练任务以及其encoder结构决定了其适合于NLU中的预测型的任务,不适合于text generation生成式任务,在工程实际使用中也需要注意这一点。

    Hugging face库中关于Bert的模型有很多,但是实际上需要掌握的用的最多的只有三个:BertConfig、BertTokenizer、BertModel。其他的封装好的下游任务API比如BertForSequenceClassification其实就是在原生的BertModel上外接Linear层实现的。

    BertConfig配置

    BertConfig用来加载一个空的Bert结构,不带有权重。

    # 定义
    class transformers.BertConfig(
    							  vocab_size = 30522, 
    							  hidden_size = 768, 
    							  num_hidden_layers = 12, 
    							  num_attention_heads = 12, 
    							  intermediate_size = 3072, 
    							  hidden_act = 'gelu', 
    							  hidden_dropout_prob = 0.1, 
    							  attention_probs_dropout_prob = 0.1, 
    							  max_position_embeddings = 512, type_vocab_size = 2, initializer_range = 0.02, layer_norm_eps = 1e-12, pad_token_id = 0, position_embedding_type = 'absolute', use_cache = True, classifier_dropout = None, **kwargs)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    transformers中的一个类,用来记录BertModel的基本配置,继承自PretrainedConfig,用来初始化BERT模型,实例化bert-base-uncased模型。

    from transformers import BertModel, BertConfig
    
    # 默认使用bert-based-uncased初始化
    configuration=BertConfig()
    # 初始化BertModel
    model=BertModel(configuration)
    
    # 获取模型的配置
    configuration=model.config
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    BertConfig继承自父类PretrainedConfig,因此可以调用父类的from_pretrained方法来直接加载模型

    # 加载bert-based-chinese
    configuration=BertConfig.from_pretrained("bert-based-chinese")
    
    • 1
    • 2

    BertTokenizer分词器

    # 定义
    class transformers.BertTokenizer(
    								 vocab_file, do_lower_case=True,
    								 do_basic_tokenize=True,
    								never_split=None,
    		unk_token='[UNK]',sep_token='[SEP]',pad_token='[PAD]',
    		cls_token='[CLS]',mask_token='[MASK]',
    		tokenize_chinese_chars=True, strip_accents=None,**kwargs
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    构建基于WordPiece分词方式的BERT分词器,并进行编码。继承自PretrainedTokenizer,PretrainedTokenizer具有很多功能,可以查看源代码。

    BertTokenizer进行编码有三种方式,直接使用tokenizer()、tokenizer.encode()以及tokenizer.encode_plus()
    三个函数调用时的参数基本一致,主要有以下几个

    • text, text_pair 代表输入的两个句子 str
    • truncation 是否进行截断操作 bool
    • padding 是否进行padding处理 bool
    • return_tensors 'pt’表示pytorch的tensor;'tf’表示tensorflow版本tensor;None表示返回list

    通过tokenizer.vocab查看BertTokenizer的词典,主要注意几个词对应的id: '[PAD]‘对应的id为0,’[UNK]‘对应id为100,’[CLS]‘对应id为101,’[SEP]‘对应id为102,’[MASK]'对应id为103。
    其中tokenizer()和tokenizer.encode_plus()返回结果一致,都返回所有的编码结果,而tokenizer.encode()则是简单的返回词对应的id序列,对于编码器输出的三个编码结果,对应的含义如下。

    • input_ids 是Tokenizer对两个句子的token进行idx映射编码,将对应的句子映射为idx。比如在这里是 [CLS] sen1 [SEP] sen2 [SEP]

    • token_type_idx 是为了区分第一句话和第二句话的编码。0表示第一句话,1表示第二句话

    • attention_mask 是为了区分有多少token是有用的,因为Bert输入为固定长度512,所以不足512的需要进行补全操作。补全的部分对应的attention_mask为0

    from transformers import BertTokenizer
    tokenizer=BertTokenizer.from_pretrained("bert-base-chinese")
    # 编码的两个句子
    sens1="银行贷款允许未成年人吗"
    sens2='未成年人可以办理银行卡吗'
    # 第一种编码
    tokenizer(text=sens1,text_pair=sens2)
    # 输出
    {'input_ids': [101, 7213, 6121, 6587, 3621, 1038, 6387, 3313, 2768, 2399, 782, 1408, 102, 3313, 2768, 2399, 782, 1377, 809, 1215, 4415, 7213, 6121, 1305, 1408, 102], 
     'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
     'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
    
    # 第二种tokenizer.encode_plus()
    tokenizer.encode_plut(text=sens1, text_pair=sens2)
    # 输出
    {'input_ids': [101, 7213, 6121, 6587, 3621, 1038, 6387, 3313, 2768, 2399, 782, 1408, 102, 3313, 2768, 2399, 782, 1377, 809, 1215, 4415, 7213, 6121, 1305, 1408, 102], 
     'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 
     'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
    # 第三种tokenizer.encode()
    tokenizer.encode(text=sens1, text_pair=sens2)
    # 输出
    [101, 7213, 6121, 6587, 3621, 1038, 6387, 3313, 2768, 2399, 782, 1408, 102, 3313, 2768, 2399, 782, 1377, 809, 1215, 4415, 7213, 6121, 1305, 1408, 102]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    BertModel

    # 原始定义
    BertModel(config, add_pooling_layer=True)
    
    • 1
    • 2

    这里需要讨论一下BertModel的两个加载方式

    • BertConfig加载,用来加载配置,但不加载模型权重,相当于加载一个空的Bert模型,用作预训练任务。
    • .from_pretrained()方法加载。.from_pretrained()方法是来自于父类PreTrainedModel,用来加载模型权重,相当于加载一个与训练好的Bert模型,用作下游微调。
      BertModel也是nn.Module的子类,forward函数定义如下
    # BertModel.forward
    forward(input_ids: typing.Optional[torch.Tensor] = None,attention_mask: typing.Optional[torch.Tensor] = None,token_type_ids: typing.Optional[torch.Tensor] = None,position_ids: typing.Optional[torch.Tensor] = None,head_mask: typing.Optional[torch.Tensor] = None,inputs_embeds: typing.Optional[torch.Tensor] = None,encoder_hidden_states: typing.Optional[torch.Tensor] = None,encoder_attention_mask: typing.Optional[torch.Tensor] = None,past_key_values: typing.Optional[typing.List[torch.FloatTensor]] = None,use_cache: typing.Optional[bool] = None,output_attentions: typing.Optional[bool] = None,output_hidden_states: typing.Optional[bool] = None,return_dict: typing.Optional[bool] = None )[transformers.modeling_outputs.BaseModelOutputWithPoolingAndCrossAttentions]
    
    • 1
    • 2

    根据forward函数,Bert模型的简单使用如下所示,只用到forward的前三个输入参数。

    from transformers import BertModel
    model=BertModel.from_pretrained("bert-base-chinese")
    
    from transformers import BertTokenizer
    tokenizer=BertTokenizer.from_pretrained("bert-base-chinese")
    
    sens1="银行贷款允许未成年人吗"
    sens2="未成年人可以办理银行卡吗"
    inputs=tokenizer(sens1, sens2, return_tensors='pt')
    outputs=model(**inputs)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    对于outputs,在未定义其他输出的情况下,有两个tensor输出。

    • last_hidden_state Bert给每个输入的token的表示,shape为[1, seq_len, 768]
    • pooler_output last_hidden_state的第一个[CLS]向量,用作分类输出,shape为[1,768]

    总结

    本文主要总结了transformers库中有关Bert模型的一些简单操作,也算是趁着暑期项目和学业没有特别赶的时候填的坑吧,有一些不太清楚或者有问题的可以随时向我反馈,希望大家在讨论中一起学习进步。

    参考

    transformer的BERT官方文档

  • 相关阅读:
    H5游戏开发与App游戏开发:有什么不同?
    如何将 Transformer 应用于时间序列模型
    简单点_c_lesson10(递归)
    代码随想录 -- day46 --139.单词拆分
    Typescript-01
    一种晶圆表面形貌测量方法-无图晶圆几何量测系统
    博兴神经网络优化公司,博兴神经网络优化招聘
    Kong Learning
    springBoot 一表多sheet页导入导出excel ---工具类,实体类,测试类 代码(全)
    Docker部署Tomcat
  • 原文地址:https://blog.csdn.net/qq_43422201/article/details/126111454