当前位置:   article > 正文

[深度学习] 自然语言处理 --- Bert开发实战 (Transformers)_基于 bert 模型的自然语言处理实战

基于 bert 模型的自然语言处理实战

本文主要介绍如果使用huggingface的transformers 2.0 进行NLP的模型训练

除了transformers,其它兼容tf2.0的bert项目还有:

我的博客里有介绍使用方法  [深度学习] 自然语言处理--- 基于Keras Bert使用(上)

  1. keras-bert(Star:1.4k) 支持tf2,但它只支持bert一种预训练模型
  2. bert4keras (Star:692)支持tf2,bert/roberta/albert的预训练权重进行finetune

  3. bert-for-tf2(Star:329)只给了tf2.0 pipeline示例

huggingface的transformers也发布了transformers2.0,开始支持tf.2.0的各个预训练模型,虽然没有对pytorch支持的那么全面但在我们的场景已经足够适用了。

 

算法流程

 

一 加载预训练Bert模型

1. 下载Google原始预训练Bert模型

(1)先将原始google预训练的模型文件转换成pytorch格式

这个命令在安装transformers时会回到环境变量中。

python convert_bert_original_tf_checkpoint_to_pytorch.py -h

  1. python convert_bert_original_tf_checkpoint_to_pytorch.py \
  2. --tf_checkpoint_path Models/chinese_L-12_H-768_A-12/bert_model.ckpt.index \
  3. --bert_config_file Models/chinese_L-12_H-768_A-12/bert_config.json \
  4. --pytorch_dump_path Models/chinese_L-12_H-768_A-12/pytorch_model.bin

output:

  1. INFO:transformers.modeling_bert:Converting TensorFlow checkpoint from /home/work/Bert/Models/chinese_L-12_H-768_A-12/bert_model.ckpt.index
  2. Save PyTorch model to Models/chinese_L-12_H-768_A-12/pytorch_model.bin

在开源代码库下面有好多有关转换的py文件

2 下载transformers预训练模型

在使用transformers的时候,由于Bert、XLNet的文件都在AWS上存储,transformers的默认下载地址指向的是AWS,因此在国内下载速度非常慢。需要我们自己手动下载。

1、下载.txt、.json、.bin文件到本地

以Bert为例,相关的.bin文件(预训练权重)下载地址如下所示:

  1. BERT_PRETRAINED_MODEL_ARCHIVE_MAP = {
  2. 'bert-base-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-pytorch_model.bin",
  3. 'bert-large-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-pytorch_model.bin",
  4. 'bert-base-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-pytorch_model.bin",
  5. 'bert-large-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-pytorch_model.bin",
  6. 'bert-base-multilingual-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-uncased-pytorch_model.bin",
  7. 'bert-base-multilingual-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-cased-pytorch_model.bin",
  8. 'bert-base-chinese': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-chinese-pytorch_model.bin",
  9. 'bert-base-german-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-cased-pytorch_model.bin",
  10. 'bert-large-uncased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-whole-word-masking-pytorch_model.bin",
  11. 'bert-large-cased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-whole-word-masking-pytorch_model.bin",
  12. 'bert-large-uncased-whole-word-masking-finetuned-squad': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-whole-word-masking-finetuned-squad-pytorch_model.bin",
  13. 'bert-large-cased-whole-word-masking-finetuned-squad': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-whole-word-masking-finetuned-squad-pytorch_model.bin",
  14. 'bert-base-cased-finetuned-mrpc': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-finetuned-mrpc-pytorch_model.bin",
  15. 'bert-base-german-dbmdz-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-cased-pytorch_model.bin",
  16. 'bert-base-german-dbmdz-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-uncased-pytorch_model.bin",
  17. }

若需要下载.json文件,则下载地址为:

  1. BERT_PRETRAINED_CONFIG_ARCHIVE_MAP = {
  2. 'bert-base-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-config.json",
  3. 'bert-large-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-config.json",
  4. 'bert-base-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-config.json",
  5. 'bert-large-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-config.json",
  6. 'bert-base-multilingual-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-uncased-config.json",
  7. 'bert-base-multilingual-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-cased-config.json",
  8. 'bert-base-chinese': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-chinese-config.json",
  9. 'bert-base-german-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-cased-config.json",
  10. 'bert-large-uncased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-whole-word-masking-config.json",
  11. 'bert-large-cased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-whole-word-masking-config.json",
  12. 'bert-large-uncased-whole-word-masking-finetuned-squad': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-whole-word-masking-finetuned-squad-config.json",
  13. 'bert-large-cased-whole-word-masking-finetuned-squad': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-whole-word-masking-finetuned-squad-config.json",
  14. 'bert-base-cased-finetuned-mrpc': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-finetuned-mrpc-config.json",
  15. 'bert-base-german-dbmdz-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-cased-config.json",
  16. 'bert-base-german-dbmdz-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-uncased-config.json",
  17. }

.txt相关文件(词表文件)下载地址如下:

  1. PRETRAINED_VOCAB_FILES_MAP = {
  2. 'vocab_file':
  3. {
  4. 'bert-base-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-vocab.txt",
  5. 'bert-large-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-vocab.txt",
  6. 'bert-base-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-vocab.txt",
  7. 'bert-large-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-vocab.txt",
  8. 'bert-base-multilingual-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-uncased-vocab.txt",
  9. 'bert-base-multilingual-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-cased-vocab.txt",
  10. 'bert-base-chinese': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-chinese-vocab.txt",
  11. 'bert-base-german-cased': "https://int-deepset-models-bert.s3.eu-central-1.amazonaws.com/pytorch/bert-base-german-cased-vocab.txt",
  12. 'bert-large-uncased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-whole-word-masking-vocab.txt",
  13. 'bert-large-cased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-whole-word-masking-vocab.txt",
  14. 'bert-large-uncased-whole-word-masking-finetuned-squad': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-whole-word-masking-finetuned-squad-vocab.txt",
  15. 'bert-large-cased-whole-word-masking-finetuned-squad': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-whole-word-masking-finetuned-squad-vocab.txt",
  16. 'bert-base-cased-finetuned-mrpc': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-finetuned-mrpc-vocab.txt",
  17. 'bert-base-german-dbmdz-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-cased-vocab.txt",
  18. 'bert-base-german-dbmdz-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-uncased-vocab.txt",
  19. }
  20. }

 

清华源还支持huggingface hub自动下载。注意:transformers > 3.1.0 的版本支持下面的 mirror 选项。

只需在 from_pretrained 函数调用中添加 mirror 选项,如:

AutoModel.from_pretrained('bert-base-uncased', mirror='tuna')

目前内置的两个来源为 tunabfsu。此外,也可以显式提供镜像地址,如:

AutoModel.from_pretrained('bert-base-uncased', mirror='https://mirrors.tuna.tsinghua.edu.cn/hugging-face-models')

直接在网站里面搜索模型,之后点击List all files in model放在一个文件夹下面导入即可啦~


3 加载transformers预训练模型

(1)加载转换后的模型

  1. import logging
  2. logging.basicConfig(level=logging.INFO)
  3. import tensorflow as tf
  4. print("Tensorflow Version:", tf.__version__)
  5. import torch
  6. print("Pytorch Version:", torch.__version__)

  1. from transformers import *
  2. import os
  3. pretrained_path = 'Models/chinese_L-12_H-768_A-12'
  4. config_path = os.path.join(pretrained_path, 'bert_config.json')
  5. vocab_path = os.path.join(pretrained_path, 'vocab.txt')
  6. # 加载config
  7. config = BertConfig.from_json_file(config_path)
  1. # 加载torch原始模型
  2. bert_model = BertModel.from_pretrained(pretrained_path, config=config)
  3. # 加载tf原始模型
  4. tfbert_model = TFBertModel.from_pretrained(pretrained_path,from_pt=True, config=config)

发现问题:如果加载为TF2的模型,参数会变少 (请使用 pytorch版本加载转换后的模型)

 

首先我们建立一个文件夹,命名为bert-base-uncased,然后将这个三个文件放入这个文件夹,并且对文件进行重命名,重命名时将bert-base-uncased-去除即可。

假设我们训练文件夹名字为 train.py,我们需要将上面的bert-base-uncased文件夹放到与train.py同级的目录下面。
若不改名以及调整文件夹位置将会出现:
vocab.txt not found;pytorch_model.bin not found;Model name 'xxx/pytorch_model.bin ' was not found in model name list等错误。

之后使用下面的代码进行测试即可:

  1. UNCASED = './bert-base-uncased'
  2. VOCAB = 'vocab.txt'
  3. tokenizer=BertTokenizer.from_pretrained(os.path.join(UNCASED,VOCAB))
  4. bert = BertModel.from_pretrained(UNCASED)

 

二  使用Tokenizer编码

tokenizer是一个将纯文本转换为编码的过程,该过程不涉及将词转换成为词向量,仅仅是对纯文本进行分词,并且添加[MASK]、[SEP]、[CLS]标记,然后将这些词转换为字典索引。

token编码inputs

tokenizer = BertTokenizer.from_pretrained(vocab_path)

第一步 使用 BERT tokenizer 将单词首先分割成 tokens。

第二步 添加句子分类所需的特殊 tokens(在第一个位置是[CLS],在句子的末尾是[SEP])。

第三步 用嵌入表中的 id 替换每个 token,嵌入表是我们从训练模型中得到的一个组件。

注意,tokenizer 在一行代码中完成所有这些步骤:

1. encode(text, ...):将文本分词后编码为包含对应 id 的列表

  1. >>> tokenizer.encode('Hello word!')
  2. [101, 8667, 1937, 106, 102]

2. encode_plus(text, ...):将文本分词后创建一个包含对应 id,token 类型及是否遮盖的词典;

  1. tokenizer.encode_plus('Hello world!')
  2. {'input_ids': [101, 8667, 1937, 106, 102], 'token_type_ids': [0, 0, 0, 0, 0], 'attention_mask': [1, 1, 1, 1, 1]}

3. convert_ids_to_tokens(ids, skip_special_tokens):将 id 映射为 token

  1. >>> tokenizer.convert_ids_to_tokens(tokens)
  2. ['[CLS]', 'Hello', 'word', '!', '[SEP]']

4. decode(token_ids):将 id 解码

  1. >>> tokenizer.decode(tokens)
  2. '[CLS] Hello word! [SEP]'

5. convert_tokens_to_ids(tokens):将 token 映射为 id

  1. >>> tokenizer.convert_tokens_to_ids(['[CLS]', 'Hello', 'word', '!', '[SEP]'])
  2. [101, 8667, 1937, 106, 102]

 

tokenizer.encode("a visually stunning rumination on love", add_special_tokens=True)

利用分词器进行编码:

  • encode仅返回input_ids
  • encode_plus返回所有编码信息
    • input_ids:是单词在词典中的编码
    • token_type_ids:区分两个句子的编码(上句全为0,下句全为1)
    • attention_mask:指定对哪些词进行self-Attention操作
  1. print(tokenizer.encode('我不喜欢你')) #[101, 2769, 679, 1599, 3614, 872, 102]
  2. sen_code = tokenizer.encode_plus('我不喜欢这世界','我只喜欢你')
  3. print(sen_code)
  4. # {'input_ids': [101, 2769, 679, 1599, 3614, 6821, 686, 4518, 102, 2769, 1372, 1599, 3614, 872, 102],
  5. # 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
  6. # 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}

将input_ids转化回token:

  1. print(tokenizer.convert_ids_to_tokens(sen_code['input_ids']))
  2. #['[CLS]', '我', '不', '喜', '欢', '这', '世', '界', '[SEP]', '我', '只', '喜', '欢', '你', '[SEP]']

数据集将其作为输入处理之前,我们需要使用 token id 0 填充更短的句子,从而使所有向量具有相同的大小。填充之后,我们有了一个矩阵/张量,准备传给 BERT:

 

 

三  使用Bert模型

下载bert-base-chinese的config.json,vocab.txt,pytorch_model.bin三个文件后,放在bert-base-chinese文件夹下,此例中该文件夹放在\home/work\transformers_file\下

根据任务需要,如果不需要为指定任务finetune,可以选择使用BertModel

  1. import numpy as np
  2. import torch
  3. from transformers import BertTokenizer, BertConfig, BertForMaskedLM, BertForNextSentencePrediction
  4. from transformers import BertModel
  5. model_name = 'bert-base-chinese'
  6. MODEL_PATH = '/home/work/transformers_file/bert-base-chinese/'
  7. # a.通过词典导入分词器
  8. tokenizer = BertTokenizer.from_pretrained(model_name)
  9. # b. 导入配置文件
  10. model_config = BertConfig.from_pretrained(model_name)
  11. # 修改配置
  12. model_config.output_hidden_states = True
  13. model_config.output_attentions = True
  14. # 通过配置和路径导入模型
  15. bert_model = BertModel.from_pretrained(MODEL_PATH, config=model_config)
  16. inputs = tokenizer("Hello, my dog is cute", return_tensors="pt")
  17. outputs = model(**inputs)
  18. last_hidden_states = outputs[0] # The last hidden-state is the first element of the output tuple

参数:

input_ids、attention_mask、token_type_ids、position_ids、head_mask、inputs_embeds、encoder_hidden_states、encoder_attention_mask、output_attentions、output_hidden_states

模型至少需要有1个输入: input_ids 或 input_embeds。

  1. input_ids 就是一连串 token 在字典中的对应id。形状为 (batch_size, sequence_length)。
  2. token_type_ids 可选。就是 token 对应的句子id,值为010表示对应的token属于第一句,1表示属于第二句)。形状为(batch_size, sequence_length)。

1  input_ids 就是一连串 token 在字典中的对应id。形状为 (batch_size, sequence_length)。Bert 的输入需要用 [CLS] 和 [SEP] 进行标记,开头用 [CLS],句子结尾用 [SEP],各类bert模型对应的输入格式如下所示:

  1. bert: [CLS] + tokens + [SEP] + padding
  2. roberta: [CLS] + prefix_space + tokens + [SEP] + padding
  3. distilbert: [CLS] + tokens + [SEP] + padding
  4. xlm: [CLS] + tokens + [SEP] + padding
  5. xlnet: padding + tokens + [SEP] + [CLS]

2  token_type_ids 可选。就是 token 对应的句子id,值为0或1(0表示对应的token属于第一句,1表示属于第二句)。形状为(batch_size, sequence_length)。如为None则BertModel会默认全为0(即a句)。

  1. tokens:[CLS] is this jack ##son ##ville ? [SEP] no it is not . [SEP]
  2. token_type_ids:0 0 0 0 0 0 0 0 1 1 1 1 1 1
  3. tokens:[CLS] the dog is hairy . [SEP]
  4. token_type_ids:0 0 0 0 0 0 0

3  attention_mask 可选。各元素的值为 0 或 1 ,避免在 padding 的 token 上计算 attention (1不进行masked,0则masked)。形状为(batch_size, sequence_length)。如为None则BertModel默认全为1。

4  position_ids 可选。表示 token 在句子中的位置id。形状为(batch_size, sequence_length)。形状为(batch_size, sequence_length)。如为None则BertModel会自动生成。

形如[012,......,seq_length - 1],

5 head_mask 可选。各元素的值为 0 或 1 ,1 表示 head 有效,0无效。形状为(num_heads,)或(num_layers, num_heads)。

6 input_embeds 可选。替代 input_ids,我们可以直接输入 Embedding 后的 Tensor。形状为(batch_size, sequence_length, embedding_dim)。

7 encoder_hidden_states 可选。encoder 最后一层输出的隐藏状态序列,模型配置为 decoder 时使用。形状为(batch_size, sequence_length, hidden_size)。

8 encoder_attention_mask 可选。避免在 padding 的 token 上计算 attention,模型配置为 decoder 时使用。形状为(batch_size, sequence_length)。

 

 

 

构建模型

  1. class BertNerModel(TFBertPreTrainedModel):
  2. def __init__(self, config, *inputs, **kwargs):
  3. super(BERT_NER, self).__init__(config, *inputs, **kwargs)
  4. self.bert_layer = TFBertMainLayer(config, name='bert')
  5. self.bert_layer.trainable = False
  6. self.concat_layer = tf.keras.layers.Concatenate(name='concat_bert')
  7. def call(self, inputs):
  8. outputs = self.bert_layer(inputs)
  9. #将后n层的结果相连
  10. tensor = self.concat_layer(list(outputs[2][-4:]))

这里给出的是简要的代码,可以自行根据任务在bert_layer之后加入RNN

自定义模型的写法可以参考官方源码里的TFBertForSequenceClassification, 继承TFBertPreTrainedModel

self.bert_layer(inputs)的返回值为tuple类型:

  1. 最后1层隐藏层的输出值,shape=(batch_size, max_length, hidden_dimention)
  2. [CLS] 对应的输出值,shape=(batch_size, hidden_dimention)
  3. 只有设置了config.output_hidden_states = True,才有该值,所有隐藏层的输出值,返回值类型是list 每个list里的值的shape(batch_size, max_length, hidden_dimention)`

模型的初始化

bert_ner_model = BertNerModel.from_pretrained("bert-base-chinese", output_hidden_states=True)

因为是模型继承的TFBertPreTrainedModel因此这里初始化使用的父类的方式。第一个参数是要加载预训练好的模型参数

注意事项

  1. 通过设置:self.bert.trainable = False, 模型可以更快收敛,减少训练时间
  2. 预测的时候,输出的数据一定要与max_length一致,否则效果完全不可用,猜测可能是我们只给了, 没有给input_mask,有看到transformers的源码,如果不给attention_mask,默认全是1的
  3. 通过设置 output_hidden_states=True, 可以得到隐藏层的结果

 

 

参考文献



 

 

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号