KerasBERT官⽹中⽂⽂档
的⾮官⽅实现,可以加载官⽅的预训练模型进⾏特征提取和预测。
安装
pip install keras-bert
使⽤
使⽤官⽅模型
分词
训练和使⽤
关于training和trainable
使⽤Warmup
关于输⼊
下载预训练模型
提取特征
模型存储与加载
使⽤任务嵌⼊
使⽤tf.keras
External Links
Kashgari是⼀个极简且强⼤的 NLP 框架,可⽤于⽂本分类和标注的学习,研究及部署上线
当Bert遇上Keras:这可能是Bert最简单的打开姿势
Keras ALBERT
使⽤官⽅模型
中使⽤官⽅预训练好的chinese_L-12_H-768_A-12可以得到和官⽅⼯具⼀样的结果。
中可以填补出缺失词并预测是否是上下⽂。
使⽤TPU
⽰例中展⽰了如何在TPU上进⾏特征提取。
中在IMDB数据集上对模型进⾏了微调以适应新的分类任务。
分词
Tokenizer类可以⽤来进⾏分词⼯作,包括归⼀化和英⽂部分的最⼤贪⼼匹配等,在CJK字符集内的中⽂会以单字分隔。
from keras_bert import Tokenizer
token_dict ={
'[CLS]':0,
'[SEP]':1,
'un':2,
'##aff':3,
'##able':4,
'[UNK]':5,
}
tokenizer = Tokenizer(token_dict)
kenize('unaffable'))# 分词结果是:`['[CLS]', 'un', '##aff', '##able', '[SEP]']`
indices, segments = de('unaffable')
print(indices)# 词对应的下标:`[0, 2, 3, 4, 1]`
print(segments)# 段落对应下标:`[0, 0, 0, 0, 0]`
kenize(first='unaffable', second='钢'))
# 分词结果是:`['[CLS]', 'un', '##aff', '##able', '[SEP]', '钢', '[SEP]']`
indices, segments = de(first='unaffable', second='钢', max_len=10)
print(indices)# 词对应的下标:`[0, 2, 3, 4, 1, 5, 1, 0, 0, 0]`
print(segments)# 段落对应下标:`[0, 0, 0, 0, 0, 1, 1, 0, 0, 0]`
Tokenizer也提供了尝试去寻分词后的结果在原始⽂本中的起始和终⽌下标的功能,输⼊可以是decode后的结果,包含少量的错词:
from keras_bert import Tokenizer
intervals = atch("All rights reserved.",["[UNK]","righs","[UNK]","ser","[UNK]","[UNK]"])
# 结果是:[(0, 3), (4, 10), (11, 13), (13, 16), (16, 19), (19, 20)]
训练和使⽤
训练过程推荐使⽤官⽅的代码。这个代码库内包含⼀个的训练过程,training为True的情况下使⽤的是带warmup的Adam优化器:
import keras
from keras_bert import get_base_dict, get_model, compile_model, gen_batch_inputs
# 随便的输⼊样例:
sentence_pairs =[
[['all','work','and','no','play'],['makes','jack','a','dull','boy']],
[['from','the','day','forth'],['my','arm','changed']],
[['and','a','voice','echoed'],['power','give','me','more','power']],
]
# 构建⾃定义词典
token_dict = get_base_dict()# 初始化特殊符号,如`[CLS]`
for pairs in sentence_pairs:
for token in pairs[0]+ pairs[1]:
if token not in token_dict:
token_dict[token]=len(token_dict)
token_list =list(token_dict.keys())# Used for selecting a random word
# 构建和训练模型
model = get_model(
token_num=len(token_dict),
python官方文档中文版head_num=5,
transformer_num=12,
embed_dim=25,
feed_forward_dim=100,
seq_len=20,
pos_num=20,
dropout_rate=0.05,
)
compile_model(model)
model.summary()
def_generator():
while True:
yield gen_batch_inputs(
sentence_pairs,
token_dict,
token_list,
seq_len=20,
mask_rate=0.3,
swap_sentence_rate=1.0,
)
model.fit_generator(
generator=_generator(),
steps_per_epoch=1000,
epochs=100,
validation_data=_generator(),
validation_steps=100,
callbacks=[
keras.callbacks.EarlyStopping(monitor='val_loss', patience=5)
],
)
# 使⽤训练好的模型
inputs, output_layer = get_model(
token_num=len(token_dict),
head_num=5,
transformer_num=12,
embed_dim=25,
feed_forward_dim=100,
seq_len=20,
pos_num=20,
dropout_rate=0.05,
training=False,# 当`training`是`False`,返回值是输⼊和输出
trainable=False,# 模型是否可训练,默认值和`training`相同
output_layer_num=4,# 最后⼏层的输出将合并在⼀起作为最终的输出,只有当`training`是`False`有效
)
关于training和trainable
虽然看起来相似,但这两个参数是不相关的。training表⽰是否在训练BERT语⾔模型,当为True时完整的BERT模型会被返回,当为False 时没有MLM和NSP相关计算的结构,返回输⼊层和根据output_layer_num合并最后⼏层的输出。加载的层是否可训练只跟trainable有关。
此外,trainable可以是⼀个包含字符串的列表,如果某⼀层的前缀出现在列表中,则当前层是可训练的。在使⽤预训练模型时,如果不想再训练嵌⼊层,可以传⼊trainable=[‘Encoder’]来只对编码层进⾏调整。
使⽤Warmup
AdamWarmup优化器可⽤于学习率的「热⾝」与「衰减」。学习率将在warmpup_steps步线性增长到lr,并在总共decay_steps步后线性减少到min_lr。辅助函数calc_train_steps可⽤于计算这两个步数:
import numpy as np
from keras_bert import AdamWarmup, calc_train_steps
train_x = np.random.standard_normal((1024,100))
total_steps, warmup_steps = calc_train_steps(
num_example=train_x.shape[0],
batch_size=32,
epochs=10,
warmup_proportion=0.1,
)
optimizer = AdamWarmup(total_steps, warmup_steps, lr=1e-3, min_lr=1e-5)
关于输⼊
在training为True的情况下,输⼊包含三项:token下标、segment下标、被masked的词的模版。当training为False时输⼊只包含前两项。位置下标由于是固定的,会在模型内部⽣成,不需要⼿动再输⼊⼀遍。被masked的词的模版在输⼊被masked的词是值为1,否则为0。
下载预训练模型
库中记录了⼀些预训练模型的下载地址,可以通过如下⽅式获得解压后的checkpoint的路径:
from keras_bert import get_pretrained, PretrainedList, get_checkpoint_paths
model_path = get_pretrained(PretrainedList.multi_cased_base)
paths = get_checkpoint_paths(model_path)
fig, paths.checkpoint, paths.vocab)
提取特征
如果不需要微调,只想提取词/句⼦的特征,则可以使⽤extract_embeddings来简化流程。如提取每个句⼦对应的全部词的特征:
from keras_bert import extract_embeddings
model_path ='xxx/yyy/uncased_L-12_H-768_A-12'
texts =['all work and no play','makes jack a dull boy~']
embeddings = extract_embeddings(model_path, texts)
返回的结果是⼀个list,长度和输⼊⽂本的个数相同,每个元素都是numpy的数组,默认会根据输出的长度进⾏裁剪,所以在这个例⼦中输出的⼤⼩分别为(7, 768)和(8, 768)。
如果输⼊是成对的句⼦,想使⽤最后4层特征,且提取NSP位输出和max-pooling的结果,则可以⽤:
from keras_bert import extract_embeddings, POOL_NSP, POOL_MAX
model_path ='xxx/yyy/uncased_L-12_H-768_A-12'
texts =[
('all work and no play','makes jack a dull boy'),
('makes jack a dull boy','all work and no play'),
]
embeddings = extract_embeddings(model_path, texts, output_layer_num=4, poolings=[POOL_NSP, POOL_MAX])
输出结果中不再包含词的特征,NSP和max-pooling的输出会拼接在⼀起,每个numpy数组的⼤⼩为(768 x 4 x 2,)。
第⼆个参数接受的是⼀个generator,如果想读取⽂件并⽣成特征,可以⽤下⾯的⽅法:
import codecs
from keras_bert import extract_embeddings
model_path ='xxx/yyy/uncased_L-12_H-768_A-12'
with codecs.open('','r','utf8')as reader:
texts =map(lambda x: x.strip(), reader)
embeddings = extract_embeddings(model_path, texts)
模型存储与加载
from keras_bert import load_trained_model_from_checkpoint, get_custom_objects
model = load_trained_model_from_checkpoint('xxx','yyy')
model.save('save_path.h5')
model.load('save_path.h5', custom_objects=get_custom_objects())
使⽤任务嵌⼊
如果有多任务训练的需求,可以启⽤任务嵌⼊层,针对不同任务将嵌⼊的结果加上不同的编码,注意要让Embedding-Task层可训练:from keras_bert import get_pretrained, PretrainedList, get_checkpoint_paths, load_trained_model_from_checkpoint
model_path = get_pretrained(PretrainedList.multi_cased_base)
paths = get_checkpoint_paths(model_path)
model = load_trained_model_from_checkpoint(
config_fig,
checkpoint_file=paths.checkpoint,
training=False,
trainable=True,
use_task_embed=True,
task_num=10,
)
使⽤tensorflow.python.keras
在环境变量⾥加⼊TF_KERAS=1可以启⽤tensorflow.python.keras。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论