自己实现了一个bert4keras
By 苏剑林 | 2019-08-27 | 179402位读者 |分享个人实现的bert4keras:
https://github.com/bojone/bert4keras这是笔者重新实现的keras版的bert,致力于用尽可能清爽的代码来实现keras下调用bert。
说明 #
目前已经基本实现bert,并且能成功加载官方权重,经验证模型输出跟keras-bert一致,大家可以放心使用。
本项目的初衷是为了修改、定制上的方便,所以可能会频繁更新。
因此欢迎star,但不建议fork,因为你fork下来的版本可能很快就过期了。
使用 #
快速安装;
pip install git+https://www.github.com/bojone/bert4keras.git
参考代码:
#! -*- coding: utf-8 -*- # 测试代码可用性 from bert4keras.models import build_transformer_model from bert4keras.tokenizers import Tokenizer import numpy as np config_path = '../../kg/bert/chinese_L-12_H-768_A-12/bert_config.json' checkpoint_path = '../../kg/bert/chinese_L-12_H-768_A-12/bert_model.ckpt' dict_path = '../../kg/bert/chinese_L-12_H-768_A-12/vocab.txt' tokenizer = Tokenizer(dict_path) # 建立分词器 model = build_transformer_model(config_path, checkpoint_path) # 建立模型,加载权重 # 编码测试 token_ids, segment_ids = tokenizer.encode(u'语言模型') print(model.predict([np.array([token_ids]), np.array([segment_ids])]))
之前在《当Bert遇上Keras:这可能是Bert最简单的打开姿势》中基于keras-bert给出的例子,仍适用于本项目,只需要将base_model的加载方式换成本项目的。
目前只保证支持Python 2.7,实验环境是Tesorflow 1.8+以及Keras 2.2.4+。
(有朋友测试过,python 3也可以直接用,没报错,反正python 3的用户可以直接试试。但我自己没测试过,所以不保证。)当然,乐于贡献的朋友如果发现了某些bug的话,也欢迎指出修正甚至Pull Requests~
背景 #
之前一直用CyberZHG大佬的keras-bert,如果纯粹只是为了在keras下对bert进行调用和fine tune来说,keras-bert已经足够能让人满意了。
然而,如果想要在加载官方预训练权重的基础上,对bert的内部结构进行修改,那么keras-bert就比较难满足我们的需求了,因为keras-bert为了代码的复用性,几乎将每个小模块都封装为了一个单独的库,比如keras-bert依赖于keras-transformer,而keras-transformer依赖于keras-multi-head,keras-multi-head依赖于keras-self-attention,这样一重重依赖下去,改起来就相当头疼了。
所以,我决定重新写一个keras版的bert,争取在几个文件内把它完整地实现出来,减少这些依赖性,并且保留可以加载官方预训练权重的特性。
鸣谢 #
感谢CyberZHG大佬实现的keras-bert,本实现有不少地方参考了keras-bert的源码,在此衷心感谢大佬的无私奉献。
转载到请包括本文地址:https://spaces.ac.cn/archives/6915
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (Aug. 27, 2019). 《自己实现了一个bert4keras 》[Blog post]. Retrieved from https://spaces.ac.cn/archives/6915
@online{kexuefm-6915,
title={自己实现了一个bert4keras},
author={苏剑林},
year={2019},
month={Aug},
url={\url{https://spaces.ac.cn/archives/6915}},
}
你也许还对下面的内容感兴趣
智能搜索
最近评论
- jorjiang: 是的 我之前就是吃了文字表达理解的亏。因为很多书和文章都用类似“和过去状态无关”这样的表达方式...
- 苏剑林: 是求导,结果不对的话你再认真检查一下你的求导过程~
- 苏剑林: 远程衰减其实是个期望性质,随机选两个向量不一定成立,简单来说就是两个原本比较相近的向量才成立(...
- 苏剑林: 你这个看上去更像是“高观点2”~
- 苏剑林: ViT不是很普遍了吗
- 苏剑林: 实际情况是去掉效果更差。
- 苏剑林: 不合并的话,K Cache是$h$个$d_k + d_r$维向量,合并的话则是$1$个$d_c...
- 苏剑林: 跟GAN同理的,$p(\boldsymbol{x}_{t-2}|\boldsymbol{x}_...
- 苏剑林: 赋值这个词很精准,受教了!
- 苏剑林: 我理解你的意思,但事实上对于一般优化器,比如简单的SignSGD,它对应的SDE很难找到类似的...
August 29th, 2019
苏老师好,
直接运行您的test.py文件,遇到了一个bug,麻烦帮忙看一下
ValueError:
Dimension must be 6 but is 4 for 'Encoder-1-MultiHeadSelfAttention/transpose_9'
(op: 'Transpose') with input shapes: [?,12,?,?,12,64], [4].
一分钟前测试,直接运行test.py文件,没有任何报错。
请确认环境一致性。
也碰到这个问题,应该是Keras==2.2.5的原因造成的,回退到2.2.4之后没有出现问题。
感谢苏神。
谢谢提醒,经测试keras 2.2.5确实会有问题,已经修复了,目前兼容keras 2.2.4和2.2.5
请问苏老师,我也遇到类似的问题,请问应该怎么做兼容?
没有固定的方案啊,找出哪一行报错,然后写到正确为止。
September 16th, 2019
苏老师您好,最近我一直在阅读您的文章,收获匪浅。在这里,我有一点疑惑的是:bert在处理中文时,直接是以单个字为单位作为输入,而不是分词之后再进行处理,我想知道bert能够用分好词的文本作为输入吗?
不可以。原则上只能用它自带的tokenizer
September 22nd, 2019
苏老师好
October 7th, 2019
苏老师好!
model = load_pretrained_model(
config_path,
checkpoint_path,
keep_words=keep_words,
albert=True
)加载参数时,会报错,如下:
ValueError: You called `set_weights(weights)` on layer "Encoder-1-MultiHeadSelfAttention" with a weight list of length 8, but the layer was expecting 16 weights. Provided weights: [array([[-0.01839516, -0.02298158, 0.07288713, .....
暂时不知道怎么回事,请苏老师指点
github上已经回复你了
October 14th, 2019
苏神你好,请问你有考虑过从注意力可视化的角度结合例子解读下Bert模型吗?
谢谢你修改的代码,对我的帮助非常大
November 12th, 2019
大大 这个怎么解决?(卡了好久了)
Received a label value of 5797 which is outside the valid range of [0, 768).
我也不知道
November 21st, 2019
苏老师您好,在加载模型时出现You called `set_weights(weights)` on layer "Encoder-1-MultiHeadSelfAttention" with a weight list of length 8, but the layer was expecting 0 weights. Provided weights: [array([[-0.04925128, -0.10506688, -0.1389927 , .....
请看准所需要的keras版本。
好的,我解决了,谢谢
您好,我也碰到了同样的问题,请问您是怎么处理的
我也解决了谢谢
Tensorflow是1.15.0
Keras 2.3.1
May 3rd, 2020
看下bert4keras/examples/task_relation_extraction.py 的第287行,s应该在循环里面,f1, precision, recall = 2 * X / (Y + Z), X / Y, X / Z在循环外面是吗?
还有两个问题:
1.如果不返回keras的bert模型返回的是什么?
bert = build_transformer_model(
config_path=config_path,
checkpoint_path=checkpoint_path,
return_keras_model=False,
)
2.在关系抽取里特意的上了mask防止那部分信息被回传,但是ner的代码包括这篇文章都padding了。却没有上padding的原因是什么?
1.subject_loss = K.binary_crossentropy(subject_labels, subject_preds)
2.subject_loss = K.mean(subject_loss, 2)
3.subject_loss = K.sum(subject_loss * mask) / K.sum(mask)
bert4keras/examples/task_relation_extraction.py,还想说下,这里的2和3是不是应该互换位置,算出来损失先mask,再求平均
@wd|comment-13284
不是
@wd|comment-13285
1.返回bert4keras自带的模型基类。这些只需要看看bert4keras的源码就知道了,没必要问。
2.不知道你说什么,请表达清楚意思
@wd|comment-13286
不应该。
PS:最后,想提醒一下,当你有此类疑惑时,应当质疑一下自己的理解是否有错,而不是来质疑作者,毕竟,这些examples发布已久,算是经过了一定的考验了,出现这些粗浅错误的概率应该是比较低的。
June 8th, 2020
苏老师,有这么一种说法,取bert的倒数第二层的输出是比较好的,因为最后一层的输出和最后的目标太近,前面的层没有学习到抽象的语义,https://blog.csdn.net/u012526436/article/details/87697242 可以让这个模型抽取向量能到任意制定层吗
build_transformer_model(num_hidden_layers=11)
另外,就算我不提供这个功能,只要对keras熟悉的话,自己也可以实现~
June 16th, 2020
苏老师,你好。
已有一部分新语料
想在chinese_L-12_H-768_A-12模型的基础上再训练model的权重, 应该怎么操作了?
from bert4keras.models import build_transformer_model
from bert4keras.tokenizers import Tokenizer
# 载入google训练好的chinese_L-12_H-768_A-12
config_path = '../../kg/bert/chinese_L-12_H-768_A-12/bert_config.json'
checkpoint_path = '../../kg/bert/chinese_L-12_H-768_A-12/bert_model.ckpt'
dict_path = '../../kg/bert/chinese_L-12_H-768_A-12/vocab.txt'
tokenizer = Tokenizer(dict_path) # 建立分词器
model = build_transformer_model(config_path, checkpoint_path) # 建立模型,加载权重
# 已有一部分新语料,想在chinese_L-12_H-768_A-12模型的基础上再训练model的权重, 应该怎么操作了
建议跑官方的训练脚本。
bert4keras的话,参考github上的pretraining目录。
嗯 多谢苏老师,我这就去看看pretraining目录