语义角色标注

    最近在做一个聊天机器人,其中一个基础要求是理解用户说的话,而这需要用到语义角色标注,先将资料整理于此。


背景

    自然语言分析技术大致分为三个层面:词法分析、句法分析和语义分析。语义角色标注是实现浅层语义分析的一种方式。在一个句子中,谓词是对主语的陈述或说明,指出“做什么”、“是什么”或“怎么样,代表了一个事件的核心,跟谓词搭配的名词称为论元。语义角色是指论元在动词所指事件中担任的角色。主要有:施事者(Agent)、受事者(Patient)、客体(Theme)、经验者(Experiencer)、受益者(Beneficiary)、工具(Instrument)、处所(Location)、目标(Goal)和来源(Source)等。

    请看下面的例子,“遇到” 是谓词(Predicate,通常简写为“Pred”),“小明”是施事者(Agent),“小红”是受事者(Patient),“昨天” 是事件发生的时间(Time),“公园”是事情发生的地点(Location)。

image.png

概念

    语义角色标注 (Semantic Role Labeling, SRL) 是一种浅层的语义分析技术,标注句子中某些短语为给定谓词的论元 (语义角色) ,如施事、受事、时间和地点等。其能够对问答系统、信息抽取和机器翻译等应用产生推动作用。

    语义角色标注(Semantic Role Labeling,SRL)以句子的谓词为中心,不对句子所包含的语义信息进行深入分析,只分析句子中各成分与谓词之间的关系,即句子的谓词(Predicate)- 论元(Argument)结构,并用语义角色来描述这些结构关系,是许多自然语言理解任务(如信息抽取,篇章分析,深度问答等)的一个重要中间步骤。在研究中一般都假定谓词是给定的,所要做的就是找出给定谓词的各个论元和它们的语义角色。

例:

intro_how_srl.jpg

其中有三个谓词提出,调研和探索。以探索为例,积极是它的方式(一般用ADV表示),而新机制则是它的受事(一般用A1表示)


语义角色

    核心的语义角色

A0-5六种,
A0 通常表示动作的施事,
A1 通常表示动作的影响等,
A2-5 根据谓语动词不同会有不同的语义含义。

    附加语义角色(15种):

b.png

标注流程

传统的SRL系统大多建立在句法分析基础之上,通常包括5个流程:

  1.构建一棵句法分析树,例如,图1是对上面例子进行依存句法分析得到的一棵句法树。
  2.从句法树上识别出给定谓词的候选论元。
  3.候选论元剪除;一个句子中的候选论元可能很多,候选论元剪除就是从大量的候选项中剪除那些最不可能成为论元的候选项。
  4.论元识别:这个过程是从上一步剪除之后的候选中判断哪些是真正的论元,通常当做一个二分类问题来解决。
  5.对第4步的结果,通过多分类得到论元的语义角色标签。可以看到,句法分析是基础,并且后续步骤常常会构造的一些人工特征,这些特征往往也来自句法分析。


07-01.png

    然而,完全句法分析需要确定句子所包含的全部句法信息,并确定句子各成分之间的关系,是一个非常困难的任务,目前技术下的句法分析准确率并不高,句法分析的细微错误都会导致SRL的错误。为了降低问题的复杂度,同时获得一定的句法结构信息,“浅层句法分析”的思想应运而生。浅层句法分析也称为部分句法分析(partial parsing)或语块划分(chunking)。和完全句法分析得到一颗完整的句法树不同,浅层句法分析只需要识别句子中某些结构相对简单的独立成分,例如:动词短语,这些被识别出来的结构称为语块。为了回避 “无法获得准确率较高的句法树” 所带来的困难,一些研究[1]也提出了基于语块(chunk)的SRL方法。基于语块的SRL方法将SRL作为一个序列标注问题来解决。序列标注任务一般都会采用BIO表示方式来定义序列标注的标签集,我们先来介绍这种表示方法。在BIO表示法中,B代表语块的开始,I代表语块的中间,O代表语块结束。通过B、I、O 三种标记将不同的语块赋予不同的标签,例如:对于一个角色为A的论元,将它所包含的第一个语块赋予标签B-A,将它所包含的其它语块赋予标签I-A,不属于任何论元的语块赋予标签O。

07-02.png

    从上面的例子可以看到,根据序列标注结果可以直接得到论元的语义角色标注结果,是一个相对简单的过程。这种简单性体现在:
  (1)依赖浅层句法分析,降低了句法分析的要求和难度;
  (2)没有了候选论元剪除这一步骤;
  (3)论元的识别和论元标注是同时实现的。
    这种一体化处理论元识别和论元标注的方法,简化了流程,降低了错误累积的风险,往往能够取得更好的结果。


pyltp语义角色标注

    pyltp(https://github.com/HIT-SCIR/pyltp) 是 语言技术平台(Language Technology Platform, LTP)的 Python 封装。语言技术平台(Language Technology Platform,LTP)是 哈工大社会计算与信息检索研究中心 历时十年开发的一整套中文语言处理系统。LTP制定了基于XML的语言处理结果表示,并在此基础上提供了一整套自底向上的丰富而且高效的中文语言处理模块(包括词法、句法、语义等6项中文处理核心技术),以及基于动态链接库(Dynamic Link Library, DLL)的应用程序接口,可视化工具,并且能够以网络服务(Web Service)的形式进行使用。

    pyltp可用的自然语言处理功能包括:

下面给出测试代码:

# -*- coding: utf-8 -*-
from pyltp import SentenceSplitter as ss
import os
from pyltp import Segmentor
from pyltp import NamedEntityRecognizer
from pyltp import Postagger
from pyltp import Parser
from pyltp import SementicRoleLabeller

text='我今天摔了一跤,很生气。'

DIR_LTP_DATA_PATH=r'D:\AI\NLP\pyltp'

#分句
sents=ss.split(text)
sents=[s for s in sents]
print(sents)

#分词
path=os.path.join(DIR_LTP_DATA_PATH,'cws.model')
segmentor=Segmentor()
segmentor.load(path)
words=segmentor.segment(text)
words=[w for w in words]
print(words)

#词性标注
postagger=Postagger()
postagger.load(os.path.join(DIR_LTP_DATA_PATH,'pos.model'))
postags=postagger.postag(words)
postags=[p for p in postags]
print(postags)

#命名实体标注
recognizer=NamedEntityRecognizer()
recognizer.load(os.path.join(DIR_LTP_DATA_PATH,'ner.model'))
netags=recognizer.recognize(words,postags)
netags=[n for n in netags]
print(netags)

#依存句法分析
parser=Parser()
parser.load(os.path.join(DIR_LTP_DATA_PATH,'parser.model'))
arcs=parser.parse(words,postags)
i=0
for arc in arcs:
    print(words[i]+':'+str(arc.head)+' '+arc.relation)
    i=i+1
    
#语义角色标注
labeller=SementicRoleLabeller()
labeller.load(os.path.join(DIR_LTP_DATA_PATH,'pisrl_win.model'))
roles=labeller.label(words,postags,arcs)
for role in roles:
    print(str(role.index)+str([" %s:(%d,%d)" % (arg.name, arg.range.start, arg.range.end) for arg in role.arguments]))

segmentor.release()
postagger.release()
recognizer.release()
parser.release()
labeller.release()

程序运行结果如下:

['我今天摔了一跤,很生气。']
['我', '今天', '摔', '了', '一', '跤', ',', '很', '生气', '。']
['r', 'nt', 'v', 'u', 'm', 'n', 'wp', 'd', 'a', 'wp']
['O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O', 'O']
我:3 SBV
今天:3 ADV
摔:0 HED
了:3 RAD
一:6 ATT
跤:3 VOB
,:3 WP
很:9 ADV
生气:3 COO
。:3 WP
[dynet] random seed: 1227180928
[dynet] allocating memory: 2000MB
[dynet] memory allocation done.
2[' A0:(0,0)', ' TMP:(1,1)', ' A1:(4,5)']
8[' A0:(0,0)', ' ADV:(7,7)']

运行结果的最后两行便是语义角色标注的结果,分析:

第一个谓词的语义角色分析:2表示谓词第3个单词,即摔'摔',施事者A0是'我',受事A1是'一跤',时间TMP在'今天'。

第二个谓词的语义角色分析:谓词为生气,施事者是'我',形容词ADV是'很'。可以看到,其结果还是很准确的。


参考文献

[1]OnlyChristmas.语义角色标注 Semantic Role Labeling(SRL) 初探(整理英文tutorial).https://blog.csdn.net/huhehaotechangsha/article/details/80463118.2018-05-26

[2]语言云.使用文档.https://www.ltp-cloud.com/intro#srl_how

[3]极客学院.语义角色标注.http://wiki.jikexueyuan.com/project/deep-learning/wordSence-identify.html.2018-11-28

首页 所有文章 机器人 计算机视觉 自然语言处理 机器学习 编程随笔 关于