BERT是谷歌公司于2018年11月发布的一款新模型,它一种预训练语言表示的方法,在大量文本语料(维基百科)上训练了一个通用的“语言理解”模型,然后用这个模型去执行想做的NLP任务。一经公布,它便引爆了整个NLP界,其在11个主流NLP任务中都取得优异的结果,因此成为NLP领域最吸引人的一个模型。简单来说,BERT就是在训练了大量的文本语料(无监督)之后,能够在对英语中的单词(或中文的汉字)给出一个向量表示,使得该单词(或汉字)具有一定的语义表示能力,因此,BERT具有一定的先验知识,在NLP任务中表现十分抢眼。

  在文章利用bert-serving-server搭建bert词向量服务(一) 中,作者简洁明了地介绍了如何利用bert-serving-server来获取中文汉字的词向量,这大大降低了一般从业者使用BERT的门槛。

  结合笔者这段时间的工作体会以及思考,笔者尝试着给出BERT的几个可能的应用,如下:

  • NLP基本任务
  • 查找相似词语
  • 提取文本中的实体
  • 问答中的实体对齐

由于笔者才疏学浅且撰写文章时间仓促,文章中有不足之处,请读者多多批评指正!

NLP基本任务

  BERT公布已经半年多了,现在已经成为NLP中的深度学习模型中必不可少的工具,一般会加载在模型中的Embedding层。由于篇幅原因,笔者不再介绍自己的BERT项目,而是介绍几个BERT在基本任务中的Github项目:

可以看到,BERT已经广泛应用于NLP基本任务中,在开源项目中导出可以见到它的身影,并且这些项目的作者也写了非常细致的代码工程,便于上手。


  在具体讲述下面的三个应用前,我们先了解下BERT应用的项目结构,如下:

其中,bert_client_lmj.py为调用BERT词向量服务,具体可参考文章利用bert-serving-server搭建bert词向量服务(一) ,完整的Python代码如下:

# -*- coding:utf-8 -*-
from bert_serving.client import BertClient
from sklearn.metrics.pairwise import cosine_similarity class Encoding(object):
def __init__(self):
self.server_ip = "127.0.0.1"
self.bert_client = BertClient(ip=self.server_ip) def encode(self, query):
tensor = self.bert_client.encode([query])
return tensor def query_similarity(self, query_list):
tensors = self.bert_client.encode(query_list)
return cosine_similarity(tensors)[0][1] if __name__ == "__main__":
ec = Encoding()
print(ec.encode("中国").shape)
print(ec.encode("美国").shape)
print("中国和美国的向量相似度:", ec.query_similarity(["中国", "美国"]))

查找相似词语

  利用词向量可以查找文章中与指定词语最相近的几个词语。具体的做法为:现将文章分词,对分词后的每个词,查询其与指定词语的相似度,最后按相似度输出词语即可。我们的示例文章为老舍的《养花》,内容如下:

我爱花,所以也爱养花。我可还没成为养花专家,因为没有工夫去研究和试验。我只把养花当做生活中的一种乐趣,花开得大小好坏都不计较,只要开花,我就高兴。在我的小院子里,一到夏天满是花草,小猫只好上房去玩,地上没有它们的运动场。

花虽然多,但是没有奇花异草。珍贵的花草不易养活,看着一棵好花生病要死,是件难过的事。北京的气候,对养花来说不算很好,冬天冷,春天多风,夏天不是干旱就是大雨倾盆,秋天最好,可是会忽然闹霜冻。在这种气候里,想把南方的好花养活,我还没有那么大的本事。因此,我只养些好种易活、自己会奋斗的花草。

不过,尽管花草自己会奋斗,我若是置之不理,任其自生自灭,大半还是会死的。我得天天照管它们,像好朋友似的关心它们。一来二去,我摸着一些门道:有的喜阴,就别放在太阳地里;有的喜干,就别多浇水。摸着门道,花草养活了,而且三年五载老活着、开花,多么有意思啊!不是乱吹,这就是知识呀!多得些知识决不是坏事。

我不是有腿病吗,不但不利于行,也不利于久坐。我不知道花草们受我的照顾,感谢我不感谢;我可得感谢它们。我工作的时候,我总是写一会儿就到院中去看看,浇浇这棵,搬搬那盆,然后回到屋里再写一会儿,然后再出去。如此循环,让脑力劳动和体力劳动得到适当的调节,有益身心,胜于吃药。要是赶上狂风暴雨或天气突变,就得全家动员,抢救花草,十分紧张。几百盆花,都要很快地抢到屋里去,使人腰酸腿疼,热汗直流。第二天,天气好了,又得把花都搬出去,就又一次腰酸腿疼,热汗直流。可是,这多么有意思呀!不劳动,连棵花也养不活,这难道不是真理吗?

送牛奶的同志进门就夸“好香”,这使我们全家都感到骄傲。赶到昙花开放的时候,约几位朋友来看看,更有秉烛夜游的味道——昙花总在夜里开放。花分根了,一棵分为几棵,就赠给朋友们一些。看着友人拿走自己的劳动果实,心里自然特别欢喜。

当然,也有伤心的时候,今年夏天就有这么一回。三百棵菊秧还在地上(没到移入盆中的时候),下了暴雨,邻家的墙倒了,菊秧被砸死三十多种,一百多棵。全家人几天都没有笑容。

有喜有忧,有笑有泪,有花有果,有香有色,既须劳动,又长见识,这就是养花的乐趣。

指定词语为“开心”,查询《养花》一文中与“开心”最为接近的5个词语,完整的Python代码如下:(find_similar_words.py)

# -*- coding:utf-8 -*-
import jieba
from bert_client_lmj import Encoding
from operator import itemgetter # 读取文章
with open('./doc.txt', 'r', encoding='utf-8') as f:
content = f.read().replace('\n', '') ec = Encoding()
similar_word_dict = {} # 查找文章中与'开心'的最接近的词语
words = list(jieba.cut(content))
for word in words:
print(word)
if word not in similar_word_dict.keys():
similar_word_dict[word] = ec.query_similarity([word, '开心']) # 按相似度从高到低排序
sorted_dict = sorted(similar_word_dict.items(), key=itemgetter(1), reverse=True) print('与%s最接近的5个词语及相似度如下:' % '开心')
for _ in sorted_dict[:5]:
print(_)

输出的结果如下:

与开心最接近的5个词语及相似度如下:
('难过', 0.9070794)
('高兴', 0.89517105)
('乐趣', 0.89260685)
('骄傲', 0.87363803)
('我爱花', 0.86954254)

提取文本中的实体

  在事件抽取中,我们往往需要抽取一些指定的元素,比如在下面的句子中,

巴基斯坦当地时间2014年12月16日早晨,巴基斯坦塔利班运动武装分子袭击了西北部白沙瓦市一所军人子弟学校,打死141人,其中132人为12岁至16岁的学生。

我们需要抽取袭击者,也就是恐怖组织这个元素。

  直接从句法分析,也许可以得到一定的效果,但由于事件描述方式多变,句法分析会显得比较复杂且效果不一定能保证。这时候,我们尝试BERT词向量,它在一定程度上可以作为补充策略,帮助我们定位到事件的元素。具体的想法如下:

  • 指定事件元素模板
  • 句子分词,对词语做n-gram
  • 查询每个n-gram与模板的相似度
  • 按相似度对n-gram排序,取相似度最高的n-gram

在这里,我们的事件元素为恐怖组织,指定的模板为“伊斯兰组织”,完整的Python程序如下(find_similar_entity_in_sentence.py):

# -*- coding:utf-8 -*-

import jieba
from operator import itemgetter
from bert_client_lmj import Encoding # 创建n-gram
def compute_ngrams(sequence, n):
lst = list(zip(*[sequence[index:] for index in range(n)]))
for i in range(len(lst)):
lst[i] = ''.join(lst[i])
return lst # 模板
template = '伊斯兰组织'
# 示例句子
doc = "巴基斯坦当地时间2014年12月16日早晨,巴基斯坦塔利班运动武装分子袭击了西北部白沙瓦市一所军人子弟学校,打死141人,其中132人为12岁至16岁的学生。" words = list(jieba.cut(doc))
all_lst = []
for j in range(1, 5):
all_lst.extend(compute_ngrams(words, j)) ec = Encoding()
similar_word_dict = {} # 查找文章中与template的最接近的词语
for word in all_lst:
print(word)
if word not in similar_word_dict.keys():
similar_word_dict[word] = ec.query_similarity([word, template]) # 按相似度从高到低排序
sorted_dict = sorted(similar_word_dict.items(), key=itemgetter(1), reverse=True) print('与%s最接近的实体是: %s,相似度为 %s.' %(template, sorted_dict[0][0], sorted_dict[0][1]))

输出的结果如下:

与伊斯兰组织最接近的实体是: 塔利班运动武装分子,相似度为 0.8953854.

可以看到,该算法成功地帮助我们定位到了恐怖组织:塔利班运动武装分子,效果很好,但是由于是无监督产生的词向量,效果不一定可控,而且该算法运行速度较慢,这点可以从工程上加以改进。

问答中的实体对齐

  在智能问答中,我们往往会采用知识图谱或者数据库存储实体,其中一个难点就是实体对齐。举个例子,我们在数据库中储存的实体如下:(entities.txt)

094型/晋级

052C型(旅洋Ⅱ级)

辽宁舰/瓦良格/Varyag

杰拉尔德·R·福特号航空母舰

052D型(旅洋III级)

054A型

CVN-72/林肯号/Lincoln

这样的实体名字很复杂,如果用户想查询实体“辽宁舰”,就会碰到困难,但是由于实体以储存在数据库或知识图谱中,实体不好直接修改。一种办法是通过关键字匹配定位实体,在这里,我们可以借助BERT词向量来实现,完整的Python代码如下:(Entity_Alignment.py)

# -*- coding:utf-8 -*-
from bert_client_lmj import Encoding
from operator import itemgetter with open('entities.txt', 'r', encoding='utf-8') as f:
entities = [_.strip() for _ in f.readlines()] ec = Encoding() def entity_alignment(query): similar_word_dict = {} # 查找已有实体中与query最接近的实体
for entity in entities:
if entity not in similar_word_dict.keys():
similar_word_dict[entity] = ec.query_similarity([entity, query]) # 按相似度从高到低排序
sorted_dict = sorted(similar_word_dict.items(), key=itemgetter(1), reverse=True) return sorted_dict[0] query = '辽宁舰'
result = entity_alignment(query)
print('查询实体:%s,匹配实体:%s 。' %(query, result)) query = '林肯号'
result = entity_alignment(query)
print('查询实体:%s,匹配实体:%s 。' %(query, result))

输出的结果如下:

查询实体:辽宁舰,匹配实体:('辽宁舰/瓦良格/Varyag', 0.8534695) 。
查询实体:林肯号,匹配实体:('CVN-72/林肯号/Lincoln', 0.8389378) 。

  在这里,查询的速度应该不是困难,因为我们可以将已储存的实体以离线的方式查询其词向量并储存,这样进来一个查询到实体,只查询一次词向量,并计算其与离线的词向量的相似度。这种方法也存在缺陷,主要是由于词向量的无监督,实体对齐有时候不会很准,但作为一种补充策略,也许可以考虑。

总结

  本文介绍了笔者这段时间所思考的BERT词向量的几个应用,由于能力有限,文章中会存在考虑不当的地方,还请读者多多批评指正。

  另外,笔者将会持续调研词向量方面的技术,比如腾讯词向量,百度词向量等,欢迎大家关注~

注意:不妨了解下笔者的微信公众号: Python爬虫与算法(微信号为:easy_web_scrape), 欢迎大家关注~

BERT的几个可能的应用的更多相关文章

  1. BERT模型在多类别文本分类时的precision, recall, f1值的计算

    BERT预训练模型在诸多NLP任务中都取得最优的结果.在处理文本分类问题时,即可以直接用BERT模型作为文本分类的模型,也可以将BERT模型的最后层输出的结果作为word embedding导入到我们 ...

  2. NLP句子表征,NLP 的巨人肩膀(下):从 CoVe 到 BERT (转载)

    深度长文:NLP的巨人肩膀(上):https://www.jiqizhixin.com/articles/2018-12-10-17 NLP 的巨人肩膀(下):从 CoVe 到 BERT: https ...

  3. 从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史(转载)

    转载 https://zhuanlan.zhihu.com/p/49271699 首发于深度学习前沿笔记 写文章   从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史 张 ...

  4. 【算法】Bert预训练源码阅读

    Bert预训练源码 主要代码 地址:https://github.com/google-research/bert create_pretraning_data.py:原始文件转换为训练数据格式 to ...

  5. 文本分类实战(十)—— BERT 预训练模型

    1 大纲概述 文本分类这个系列将会有十篇左右,包括基于word2vec预训练的文本分类,与及基于最新的预训练模型(ELMo,BERT等)的文本分类.总共有以下系列: word2vec预训练词向量 te ...

  6. 【译】BERT表示的可解释性分析

    目录 从词袋模型到BERT 分析BERT表示 不考虑上下文的方法 考虑语境的方法 结论 本文翻译自Are BERT Features InterBERTible? 从词袋模型到BERT ​ Mikol ...

  7. 【译】为什么BERT有3个嵌入层,它们都是如何实现的

    目录 引言 概览 Token Embeddings 作用 实现 Segment Embeddings 作用 实现 Position Embeddings 作用 实现 合成表示 结论 参考文献 本文翻译 ...

  8. 【译】深度双向Transformer预训练【BERT第一作者分享】

    目录 NLP中的预训练 语境表示 语境表示相关研究 存在的问题 BERT的解决方案 任务一:Masked LM 任务二:预测下一句 BERT 输入表示 模型结构--Transformer编码器 Tra ...

  9. 图解BERT(NLP中的迁移学习)

    目录 一.例子:句子分类 二.模型架构 模型的输入 模型的输出 三.与卷积网络并行 四.嵌入表示的新时代 回顾一下词嵌入 ELMo: 语境的重要性 五.ULM-FiT:搞懂NLP中的迁移学习 六.Tr ...

  10. 深入理解BERT Transformer ,不仅仅是注意力机制

    来源商业新知网,原标题:深入理解BERT Transformer ,不仅仅是注意力机制 BERT是google最近提出的一个自然语言处理模型,它在许多任务 检测上表现非常好. 如:问答.自然语言推断和 ...

随机推荐

  1. Spark MLlib Deep Learning Convolution Neural Network (深度学习-卷积神经网络)3.2

    3.Spark MLlib Deep Learning Convolution Neural Network(深度学习-卷积神经网络)3.2 http://blog.csdn.net/sunbow0 ...

  2. layer弹出层不居中解决方案,仅显示遮罩,没有弹窗

    问题:项目中layer询问层的弹窗仅显示遮罩层,并不显示弹窗…… 原因:图片太多将layer弹窗挤出屏幕下方,看不见了…… 解决方案:让layer的弹出层居中显示 一.问题描述 用layer做操作结果 ...

  3. huawei校招测试题

    三道题两小时. 第一题,圈住所有点的长方形,很简单略过. 第二题:奇偶排序. 奇偶排序 描述: 输入若干(不超过1000个)非负整数数字,请先取出为奇数的数字按从大到小排序,再取出偶数从小到大进行排序 ...

  4. 初识跨终端Web

    近期试读了<跨终端Web>这本书的部分章节,既为了拿到书,也为了记录下读后的收获的东西,这会是个非常好的习惯吧. 标题为"初识跨终端Web".对我来说最贴切了,在此之前 ...

  5. Mac中配置eclipse的php开发环境

    1.mac中自带php和apache,不过版本不是最新的. 2.打开apache配置文件中php相关设置,并设置php的工程目录为你想要的目录 3.复制php.ini.default为php.ini, ...

  6. UIPageControll 的属性和用法

    UIPageControll 是继承于UIControl的一个IOS系统UI控件,可以提供给开发者设计分页效果的功能. 初始化方法 UIPageControl * page = [[UIPageCon ...

  7. (linux)container_of()宏

      在学习Linux驱动的过程中,遇到一个宏叫做container_of. 该宏定义在include/linux/kernel.h中,首先来贴出它的代码: /**  * container_of - ...

  8. 计算机学院大学生程序设计竞赛(2015’12)Study Words

    Study Words Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Tota ...

  9. dedecms专题列表页不显示标题的解决办法

    在网站专题中的标题都是比较长的,所以在调用title的时候没有使用title而是使用fulltitle的,fulltitle在其他的模型中都是可以正常使用的,也可以调用出字段,但是在专题中就没有调用出 ...

  10. Navicat——如何导出所有的查询数据

    前言 很简单就是通过Navicat的查询来查询~ 步骤 真的不要太简单了~ 打开Navicat并点击查询 新建查询 选择对应的连接和库 写入SQL并运行 导出结果 1.选择导出当前的结果 2.选择保存 ...