BERT是谷歌公司于2018年11月发布的一款新模型,它一种预训练语言表示的方法,在大量文本语料(维基百科)上训练了一个通用的“语言理解”模型,而后用这个模型去执行想作的NLP任务。一经公布,它便引爆了整个NLP界,其在11个主流NLP任务中都取得优异的结果,所以成为NLP领域最吸引人的一个模型。简单来讲,BERT就是在训练了大量的文本语料(无监督)以后,可以在对英语中的单词(或中文的汉字)给出一个向量表示,使得该单词(或汉字)具备必定的语义表示能力,所以,BERT具备必定的先验知识,在NLP任务中表现十分抢眼。
在文章利用bert-serving-server搭建bert词向量服务(一) 中,做者简洁明了地介绍了如何利用bert-serving-server来获取中文汉字的词向量,这大大下降了通常从业者使用BERT的门槛。
结合笔者这段时间的工做体会以及思考,笔者尝试着给出BERT的几个可能的应用,以下:python
因为笔者才疏学浅且撰写文章时间仓促,文章中有不足之处,请读者多多批评指正!git
BERT公布已经半年多了,如今已经成为NLP中的深度学习模型中必不可少的工具,通常会加载在模型中的Embedding层。因为篇幅缘由,笔者再也不介绍本身的BERT项目,而是介绍几个BERT在基本任务中的Github项目:github
能够看到,BERT已经普遍应用于NLP基本任务中,在开源项目中导出能够见到它的身影,而且这些项目的做者也写了很是细致的代码工程,便于上手。web
其中,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词向量,它在必定程度上能够做为补充策略,帮助咱们定位到事件的元素。具体的想法以下:spa
在这里,咱们的事件元素为恐怖组织,指定的模板为“伊斯兰组织”,完整的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), 欢迎你们关注~