本文主要介绍如果使用huggingface的transformers 2.0 进行NLP的模型训练
除了transformers,其它兼容tf2.0的bert项目还有:
我的博客里有介绍使用方法 [深度学习] 自然语言处理--- 基于Keras Bert使用(上)
bert4keras (Star:692)支持tf2,bert/roberta/albert的预训练权重进行finetune
huggingface的transformers也发布了transformers2.0,开始支持tf.2.0的各个预训练模型,虽然没有对pytorch支持的那么全面但在我们的场景已经足够适用了。
(1)先将原始google预训练的模型文件转换成pytorch格式
这个命令在安装transformers时会回到环境变量中。
python convert_bert_original_tf_checkpoint_to_pytorch.py -h
python convert_bert_original_tf_checkpoint_to_pytorch.py \
--tf_checkpoint_path Models/chinese_L-12_H-768_A-12/bert_model.ckpt.index \
--bert_config_file Models/chinese_L-12_H-768_A-12/bert_config.json \
--pytorch_dump_path Models/chinese_L-12_H-768_A-12/pytorch_model.bin
output:
INFO:transformers.modeling_bert:Converting TensorFlow checkpoint from /home/work/Bert/Models/chinese_L-12_H-768_A-12/bert_model.ckpt.index
Save PyTorch model to Models/chinese_L-12_H-768_A-12/pytorch_model.bin
在开源代码库下面有好多有关转换的py文件
在使用transformers的时候,由于Bert、XLNet的文件都在AWS上存储,transformers的默认下载地址指向的是AWS,因此在国内下载速度非常慢。需要我们自己手动下载。
1、下载.txt、.json、.bin文件到本地
以Bert为例,相关的.bin文件(预训练权重)下载地址如下所示:
BERT_PRETRAINED_MODEL_ARCHIVE_MAP = {
'bert-base-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-pytorch_model.bin",
'bert-large-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-pytorch_model.bin",
'bert-base-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-pytorch_model.bin",
'bert-large-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-pytorch_model.bin",
'bert-base-multilingual-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-uncased-pytorch_model.bin",
'bert-base-multilingual-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-cased-pytorch_model.bin",
'bert-base-chinese': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-chinese-pytorch_model.bin",
'bert-base-german-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-cased-pytorch_model.bin",
'bert-large-uncased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-whole-word-masking-pytorch_model.bin",
'bert-large-cased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-whole-word-masking-pytorch_model.bin",
'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",
'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",
'bert-base-cased-finetuned-mrpc': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-finetuned-mrpc-pytorch_model.bin",
'bert-base-german-dbmdz-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-cased-pytorch_model.bin",
'bert-base-german-dbmdz-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-uncased-pytorch_model.bin",
}
若需要下载.json文件,则下载地址为:
BERT_PRETRAINED_CONFIG_ARCHIVE_MAP = {
'bert-base-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-config.json",
'bert-large-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-config.json",
'bert-base-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-config.json",
'bert-large-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-config.json",
'bert-base-multilingual-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-uncased-config.json",
'bert-base-multilingual-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-cased-config.json",
'bert-base-chinese': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-chinese-config.json",
'bert-base-german-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-cased-config.json",
'bert-large-uncased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-whole-word-masking-config.json",
'bert-large-cased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-whole-word-masking-config.json",
'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",
'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",
'bert-base-cased-finetuned-mrpc': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-finetuned-mrpc-config.json",
'bert-base-german-dbmdz-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-cased-config.json",
'bert-base-german-dbmdz-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-uncased-config.json",
}
.txt相关文件(词表文件)下载地址如下:
PRETRAINED_VOCAB_FILES_MAP = {
'vocab_file':
{
'bert-base-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-uncased-vocab.txt",
'bert-large-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-vocab.txt",
'bert-base-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-vocab.txt",
'bert-large-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-vocab.txt",
'bert-base-multilingual-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-uncased-vocab.txt",
'bert-base-multilingual-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-multilingual-cased-vocab.txt",
'bert-base-chinese': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-chinese-vocab.txt",
'bert-base-german-cased': "https://int-deepset-models-bert.s3.eu-central-1.amazonaws.com/pytorch/bert-base-german-cased-vocab.txt",
'bert-large-uncased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-uncased-whole-word-masking-vocab.txt",
'bert-large-cased-whole-word-masking': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-large-cased-whole-word-masking-vocab.txt",
'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",
'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",
'bert-base-cased-finetuned-mrpc': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-cased-finetuned-mrpc-vocab.txt",
'bert-base-german-dbmdz-cased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-cased-vocab.txt",
'bert-base-german-dbmdz-uncased': "https://s3.amazonaws.com/models.huggingface.co/bert/bert-base-german-dbmdz-uncased-vocab.txt",
}
}
清华源还支持huggingface hub自动下载。注意:transformers > 3.1.0
的版本支持下面的 mirror
选项。
只需在 from_pretrained
函数调用中添加 mirror
选项,如:
AutoModel.from_pretrained('bert-base-uncased', mirror='tuna')
目前内置的两个来源为 tuna
与 bfsu
。此外,也可以显式提供镜像地址,如:
AutoModel.from_pretrained('bert-base-uncased', mirror='https://mirrors.tuna.tsinghua.edu.cn/hugging-face-models')
直接在网站里面搜索模型,之后点击List all files in model
放在一个文件夹下面导入即可啦~
(1)加载转换后的模型
import logging
logging.basicConfig(level=logging.INFO)
import tensorflow as tf
print("Tensorflow Version:", tf.__version__)
import torch
print("Pytorch Version:", torch.__version__)
from transformers import *
import os
pretrained_path = 'Models/chinese_L-12_H-768_A-12'
config_path = os.path.join(pretrained_path, 'bert_config.json')
vocab_path = os.path.join(pretrained_path, 'vocab.txt')
# 加载config
config = BertConfig.from_json_file(config_path)
# 加载torch原始模型
bert_model = BertModel.from_pretrained(pretrained_path, config=config)
# 加载tf原始模型
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等错误。
之后使用下面的代码进行测试即可:
UNCASED = './bert-base-uncased'
VOCAB = 'vocab.txt'
tokenizer=BertTokenizer.from_pretrained(os.path.join(UNCASED,VOCAB))
bert = BertModel.from_pretrained(UNCASED)
tokenizer是一个将纯文本转换为编码的过程,该过程不涉及将词转换成为词向量,仅仅是对纯文本进行分词,并且添加[MASK]、[SEP]、[CLS]标记,然后将这些词转换为字典索引。
tokenizer = BertTokenizer.from_pretrained(vocab_path)
第一步 使用 BERT tokenizer 将单词首先分割成 tokens。
第二步 添加句子分类所需的特殊 tokens(在第一个位置是[CLS],在句子的末尾是[SEP])。
第三步 用嵌入表中的 id 替换每个 token,嵌入表是我们从训练模型中得到的一个组件。
注意,tokenizer 在一行代码中完成所有这些步骤:
1. encode(text, ...)
:将文本分词后编码为包含对应 id 的列表
>>> tokenizer.encode('Hello word!')
[101, 8667, 1937, 106, 102]
2. encode_plus(text, ...)
:将文本分词后创建一个包含对应 id,token 类型及是否遮盖的词典;
tokenizer.encode_plus('Hello world!')
{'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
>>> tokenizer.convert_ids_to_tokens(tokens)
['[CLS]', 'Hello', 'word', '!', '[SEP]']
4. decode(token_ids)
:将 id 解码
>>> tokenizer.decode(tokens)
'[CLS] Hello word! [SEP]'
5. convert_tokens_to_ids(tokens)
:将 token 映射为 id
>>> tokenizer.convert_tokens_to_ids(['[CLS]', 'Hello', 'word', '!', '[SEP]'])
[101, 8667, 1937, 106, 102]
tokenizer.encode("a visually stunning rumination on love", add_special_tokens=True)
print(tokenizer.encode('我不喜欢你')) #[101, 2769, 679, 1599, 3614, 872, 102]
sen_code = tokenizer.encode_plus('我不喜欢这世界','我只喜欢你')
print(sen_code)
# {'input_ids': [101, 2769, 679, 1599, 3614, 6821, 686, 4518, 102, 2769, 1372, 1599, 3614, 872, 102],
# 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
# 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]}
print(tokenizer.convert_ids_to_tokens(sen_code['input_ids']))
#['[CLS]', '我', '不', '喜', '欢', '这', '世', '界', '[SEP]', '我', '只', '喜', '欢', '你', '[SEP]']
数据集将其作为输入处理之前,我们需要使用 token id 0 填充更短的句子,从而使所有向量具有相同的大小。填充之后,我们有了一个矩阵/张量,准备传给 BERT:
下载bert-base-chinese的config.json,vocab.txt,pytorch_model.bin三个文件后,放在bert-base-chinese文件夹下,此例中该文件夹放在\home/work\transformers_file\下
根据任务需要,如果不需要为指定任务finetune,可以选择使用BertModel
import numpy as np
import torch
from transformers import BertTokenizer, BertConfig, BertForMaskedLM, BertForNextSentencePrediction
from transformers import BertModel
model_name = 'bert-base-chinese'
MODEL_PATH = '/home/work/transformers_file/bert-base-chinese/'
# a.通过词典导入分词器
tokenizer = BertTokenizer.from_pretrained(model_name)
# b. 导入配置文件
model_config = BertConfig.from_pretrained(model_name)
# 修改配置
model_config.output_hidden_states = True
model_config.output_attentions = True
# 通过配置和路径导入模型
bert_model = BertModel.from_pretrained(MODEL_PATH, config=model_config)
inputs = tokenizer("Hello, my dog is cute", return_tensors="pt")
outputs = model(**inputs)
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。
input_ids 就是一连串 token 在字典中的对应id。形状为 (batch_size, sequence_length)。
token_type_ids 可选。就是 token 对应的句子id,值为0或1(0表示对应的token属于第一句,1表示属于第二句)。形状为(batch_size, sequence_length)。
1 input_ids 就是一连串 token 在字典中的对应id。形状为 (batch_size, sequence_length)。Bert 的输入需要用 [CLS] 和 [SEP] 进行标记,开头用 [CLS],句子结尾用 [SEP],各类bert模型对应的输入格式如下所示:
bert: [CLS] + tokens + [SEP] + padding
roberta: [CLS] + prefix_space + tokens + [SEP] + padding
distilbert: [CLS] + tokens + [SEP] + padding
xlm: [CLS] + tokens + [SEP] + padding
xlnet: padding + tokens + [SEP] + [CLS]
2 token_type_ids 可选。就是 token 对应的句子id,值为0或1(0表示对应的token属于第一句,1表示属于第二句)。形状为(batch_size, sequence_length)。如为None则BertModel会默认全为0(即a句)。
tokens:[CLS] is this jack ##son ##ville ? [SEP] no it is not . [SEP]
token_type_ids:0 0 0 0 0 0 0 0 1 1 1 1 1 1
tokens:[CLS] the dog is hairy . [SEP]
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会自动生成。
形如[0,1,2,......,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)。
class BertNerModel(TFBertPreTrainedModel):
def __init__(self, config, *inputs, **kwargs):
super(BERT_NER, self).__init__(config, *inputs, **kwargs)
self.bert_layer = TFBertMainLayer(config, name='bert')
self.bert_layer.trainable = False
self.concat_layer = tf.keras.layers.Concatenate(name='concat_bert')
def call(self, inputs):
outputs = self.bert_layer(inputs)
#将后n层的结果相连
tensor = self.concat_layer(list(outputs[2][-4:]))
这里给出的是简要的代码,可以自行根据任务在bert_layer
之后加入RNN
等
自定义模型的写法可以参考官方源码里的TFBertForSequenceClassification
, 继承TFBertPreTrainedModel
self.bert_layer(inputs)
的返回值为tuple
类型:
shape=(batch_size, max_length, hidden_dimention)
[CLS]
对应的输出值,shape=(batch_size, hidden_dimention)
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
因此这里初始化使用的父类的方式。第一个参数是要加载预训练好的模型参数
self.bert.trainable = False
, 模型可以更快收敛,减少训练时间max_length
一致,否则效果完全不可用,猜测可能是我们只给了, 没有给input_mask
,有看到transformers的源码,如果不给attention_mask
,默认全是1的output_hidden_states=True
, 可以得到隐藏层的结果
参考文献
HuggingFace-Transformers
关于transformers库中不同模型的Tokenizer
NLP学习1 - 使用Huggingface Transformers框架从头训练语言模型
Huggingface简介及BERT代码浅析
一起读Bert文本分类代码 (pytorch篇 一)