最近做了一点微小的工作,搞了下命名实体识别(named entity recongnition, NER),这里总结一下目前的认识。内容比较杂,先亮一下目录,如图0-1。
图0-1 目录
一、什么是命名实体
1.1 什么是实体
实体(entity)指客观存在、并可相互区别的事物。实体可以是具体的人、事、物,也可以是概念。
1.2 命名实体
命名实体就是以名称为标识的实体。简单来说,如果我们听到一个名字,就能知道这个东西是哪一个具体的事物,那么这个事物就是命名实体。
用大众的语言来说,只要有名字,就算阿猫阿狗也是一个命名实体。比如我有一只蟋蟀,名叫“小强”,那么小强就是一个命名实体(当然是对我来说,其他人会踩死它)。
用程序员的语言来说,类的一个实例,就是一个命名实体。比如“Person”这个类实例化后,得到一个名为“孙悟空”的对象,这个“孙悟空”就是一个可以用名称来引用和操作的东西了(叫“孙悟空”,不会有另一个对象答应)。
在生活和生产中,到处有实体。如表1-1,是我们的生产和生活中经常遇到的命名实体和实体的类型。实体的类型是根据需求,人为定义的一种概念,用来区分命名实体的类别,以便区别对待和使用,常见的实体类型有人名、地名(有时候分为地理地名和政治地名两部分)、组织名、时间、产品名等等。
表1-1 常见命名实体实例
1.3 为什么要识别命名实体
命名实体是现实世界里的事物,它们和现实世界相互作用、相互影响,因此命名实体在一些一些场景里特别重要,比如我想知道《红楼梦》里所有的人物在各回的出场情况,进而为每个人物做一个生平简介。这时候,我们就需要某种手段,把文本中的命名实体给识别出来,如表1-2。
有时候,我们需要知道事物之间的关系,进而准确地决策。比如说,王夫人需要知道大观园里所有人和宝玉的交往情况,找出所有可能引诱宝玉不走正道的“狐媚子”。我们可以识别出大观园里出现的所有的人物,并判断人物之间的关系(有想法、没想法),然后做成一个有向图。这样,就可以把所有对宝玉有想法的人拎出来审问了。
这么做似乎代价有点高啊。如果只是为了保护宝玉,做这个图谱就有点铺张了;如果是为了保护所有的人,这个图谱的成本就会被摊的比较薄,值得做。
表1-2 《红楼梦》片段里的人名
1.4 海量文本数据中的命名实体
给我一周的时间,我能把《红楼梦》里面的人名全都标记出来。咬咬牙,把地名、组织名、职位名都标记出来,也是可以的。
什么?还有明代四大奇书以及《四库全书》?我需要亲切问候一下提需求的人。
1.5 什么是命名实体标注
壮士且慢,有没有听过命名实体识别,也就是NER呢?NER指的是一类技术,可以自动地从文本数据中识别出特定类型的命名实体。我们可以用计算机来完成这个任务,用不了一周。
如图1-1,是命名实体标注任务的流程图。我们将原始文本输入到NER工具里,该工具会输出带有命名实体标记的文本或者命名实体列表。
图1-1 命名实体识别的流程
那么,具体是怎么做的呢?
1.6 标签体系的种类与NER的输出
NER工具会给文本序列中的每一个字(或词)打上一个标签,用来表示这个字(或词)是否为命名实体的一部分。如表1-3,是常见的NER标签体系;表1-4展示的,是NER工具的输出结果。以前人们在做NER的时候,通常是先分词,然后基于词语序列来计算标签;最近几年大家发现不分词、直接基于字符序列的效果甚至更好。后者逐渐占据了比较大的话语权,因此这里默认是基于字序列来做NER。
表1-3 常见的NER标签体系
表1-4常见标签体系的使用示例
那么,NER工具是如何计算出这些标签的呢?
二、如何识别命名实体
2.1 人工标注
命名实体是人定义的,人当然可以胜任这个工作。但是,就像前面所说的,有几个限制因素,导致不能依靠人工来做NER:(1)做事情需要人、财、物,而人力资源是其中最金贵的,耗费比较大;(2)我们在标注数据的时候,会面临体力下降、情绪波动等等生理和心理状况的考验,导致不能长时间、高质量地进行数据标注;(3)我们处理数据的速度太慢了,这是最要命的。举个例子,我标注微博文本的情感极性时,一天上千条就烦的不行——生产力太弱。
如果数据量比较小,使用真正的“人工智能”是可以的;当数据量比较大的时候,我们需要机器的帮助。我们一般用人工标注一个足够大的高质量训练数据,然后训练模型来做大规模的NER。
2.3 使用规则
规则是最符合我们直觉的一种算法,任何需要自动化的地方,我们都会尝试用规则来解决问题,NER也不例外。在人工智能发展的初期,人们认为语言规律是可以用规则来描述的,比如“xxx公司”是一个公司名。
一般来说,我们在做命名实体的时候,可以首先考虑一下可否使用正则。假如命名实体的名称规律比较简单,我们可以找出模式,然后设计相应的正则表达式或者规则,然后把符合模式的字符串匹配出来,作为命名实体识别的结果。比如我需要识别图2-1所示文本里的政府机构。这里的机构名称规律比较简单,是“[地名][职能][行政级别]”这样的三元组(然后去掉地名,就是我们要的部门名称了)。符合这个模式的,“基本上”就是一个政府机构。为什么说是“基本上”,因为我只看了很少的数据,总结的模式还很少。
图2-1 神木市政府的官网信息
2.4 基于词典
在仔细查看这个官网的时候,我发现相关部门还是比较负责的,把组织机构框架也公示了出来。这样,我就可以获得一个部门名称词典。
词典是一种非常有价值的数据。在啊命名实体识别任务中,我们可以把部门名称当做一个模式,直接去文本里匹配——如果一个部门名称出现在文本里,说明文本包含了这个名称。
这样做会遇到比较严重的问题:歧义。比如“我国的自然资源局部集中现象很普遍”,这句话里的“自然资源局”是一个部门名称吗?不是。
我们可以用分词的方法,来减少歧义带来的困扰。先将句子切分为“我/国/的/自然/资源/局部/集中/现象/很/普遍”,然后逐词匹配即可。当然,这要求分词算法比较给力。
那要是遇到“我是自然资源局的”,分词结果是“我/是/自然/资源/局/的”,这可怎么办呢?“自然资源局”被切分成若干个词语了。这时候可以使用最大匹配法,检查分词结果中是否在这样的一些子串,可以组成部门名称。
实际上,现在比较流行的分词工具(HanLP,Jieba,IK等),默认用的都是最短路径分词这类算法,支持用户添加自定义词典、使特定字符串优先成词。这样,我们把部门名称添加的词典里,“自然资源局”就不会被切分开了。
图2-2 某地政府官网公示的部门名称
2.5 模型
后来,由于无法解决语言相关的问题,基于规则的人工智能系统退出了C位。取而代之的是统计和机器学习。
2.5.1 分类器
在一些人的眼中,万物皆可分类。NER也可以看做一种分类任务,就是判断一个词语是不是命名实体、是哪一种命名实体。常见的做法就是,基于一个词语或者字的上下文构造特征,来判断这个词语或者字是否为命名实体。
这个方法需要比较好的特征工程,也就是要求我们对文本和业务内容有很深的理解,门槛还是比较高的。
2.5.2 HMM和CRF
NER也可以用序列标注的方式来做。命名实体存在于自然语言中,而自然语言是“人”这个模型在接收外界信号后生成的一种序列,因此有人认为语言符合某种模型。
常见的一种假设是,序列元素具有一种隐藏(不可见)的状态——模型以一种概率分布随机生成隐藏状态,然后基于隐藏状态的取值选择一种概率分布取生成序列。在NER中,词语的标签就是不可见(因此需要推测)的状态。我们可以罗列出所有可能生文字序列或者词语序列的NER标签序列,然后用HMM和CRF评估各个标签序列的质量、择优录取(实际不需要这么暴力,人们为这两个模型提供了缩小搜索空间的算法)。
这两个模型的优点是,使用了文本序列的整体信息,可以找到“最合适的”标注方案。因此,即使深度学习来势汹汹,CRF也没有被淘汰。
2.5.3 深度学习
深度学习领域的模型结构种类比较多,最适合做自然语言处理任务的是RNN类和tansformer类。这些神经网络也把语言看做是序列数据,然后用自身极强的拟合能力,把这种序列转换为标签序列。
如果只使用神经网络,我们会用softmax来作为输出层,本质上是对序列的元素进行分类。这种做法比较自然,不过有一个不足:它认为序列元素之间的相互独立的,损失了不少信息。
还有一种做法,就是以CRF作为输出层,把任务变成序列标注,这样就可以使用上序列元素之间的关系信息了。这个方案结合了神经网络的拟合能力和CRF的全局视野,是非常经典、有效的一种NER模型结构。
当然了,去年开始大家开始关注的transformer做NER更是一把好手。我们可以把transformmer和CRF结合起来。是的,特征提取器总是在变,而CRF一直在顶端。
对这些模型的介绍非常容易找到,百度即可。
三、关于积累语料
3.1 为什么要积累语料
作为一个合格的算法工程师,平时要有积累的习惯。不光积累算法,还要积累数据。
为什么呢?再牛叉的模型,没有数据也是白瞎。大部分模型需要质量较好、规模较大的数据作为饲料,一点点训练成型。没有数据,模型就是”人工智障”。因此,数据科学相关的任务里,数据,尤其是有标签数据经常是最重要的资源。
通常来说,我们做产品或者项目的时候,会采集、购买或者自己标注一定量的数据,用来建模。比如我们要从文本里抽取饭店的名字,就需要构造一份给饭店名字打了标记的文本语料——这份数据用完了,可要保存好了啊。
为什么要保存呢?产品需要迭代,项目可能有二期,你和你的徒弟没准需要学习,饭店名称数据还可以用来做词表……你确定十年之内用不到这份数据吗?如果不确定,就把它管理好。