赞
踩
本文主要介绍自然语言理解部分,自然语言理解主要包括:意图识别和槽位填充两部分。
意图识别,是判断用户要做什么,比如一个用户向机器人问了一个问题,于是机器人就需要判断这个用户他问的是天气、是旅游还是问某部电影的信息。说到底意图识别就是一个文本分类的问题。既然对应文本分类,那么首先就需要将明确有哪几类意图,也就是说我们需要预先定义好意图的类别然后才能考虑意图识别的问题。那么如何定义意图类别呢,它不像情感分类任务那样,不管什么场景,都能划分成积极、消极和中立情感三分类;意图分类需要将其置于特定的场景中来考虑,不同应用场景就有不同的意图分类。比如在美团APP上,它把用户的搜索意图分为订外卖、订酒店、订旅游门票、订电影票、订机票等类别。
那么识别出用户的意图之后有什么用呢?比如用户输入“订一张今天下午场次的战狼电影票”,系统识别出“订电影票”的意图,于是系统开始操作订电影票的事了,但是系统犯迷糊了,是给用户订战狼1还是战狼2呢?订哪个电影院的呢?系统查了一下最近上映的电影,发现当前只有战狼2在重映;系统又查了一下离用户当前所在位置最近的电影院是一家叫XX影城的电影院;系统又计算了一下时间,现在是下午1点,XX影城战狼2在下午一点半有一个场次,而稍远一点的YY影城在下午两点半有一个场次;于是系统和用户进行交互互动:
“您好,战狼2在XX影城于下午一点半上映,YY影城将在下午两点半上映;你需要去哪个电影院呢?”
“去YY影城”
“您好,您可以选择电影票张数和座位号完成预定”
为什么系统会像人一样思考并且和用户互动?其实系统会有针对性的“思考”是全靠槽位填充来实现的,当系统识别出你的“订电影票”意图之后,它掏出了该意图所对应的语义槽来做“填空”,语义槽格式如下所示
"订电影票": {
"电影名":__________,
"电影院名称":__________,
"时间":__________,
"数量":__________,
"座位位置":__________,
}
需要填的空包含了电影名、影院名称、时间、数量、座位位置等信息,系统通过命名实体识别和槽位预测来填空。首先对用户的输入 订一张今天下午场次的战狼电影票
识别出电影名是“战狼”,时间是“今天下午”;没有识别到影院名称,系统根据用户当前的位置,将其预测为XX影院或YY影院,数量和座位位置无法预测。针对无法预测的槽位,系统向用户发问或者提供选择来确认 您可以选择电影票张数和座位号完成预定
;对于预测到槽位值不唯一的情况,比如XX影院或YY影院,系统让用户自己进行二选一;对于识别到的槽位存在歧义的问题,系统会进行“澄清”,比如战狼实体不是很明确,需要澄清是战狼1还是战狼2,系统根据现在正上映的是战狼2这一情况来进行自动澄清,但如果此时两部电影都在上映的话,系统就得向用户发问澄清了,比如问 您是想要看战狼1还是战狼2?
。
可以看到系统的思考过程完全是按照语义槽来进行的,有什么槽位它就思考什么。当语义槽完全填充且消除了歧义之后,也就完成了整个自然语言理解任务,开始利用知识库回答用户问题或者完成某种操作。但是语义槽到底是怎么来的呢?它是如何和用户进行“发问”交互的呢?
上文中提到意图识别的类别是预定义好的,其实我们也会预定义好意图所对应的语义槽,也就是你的应用场景有多少个意图,那么你就需要事先定义好多少个所对应的语义槽。在上文的例子中我把“订电影票”意图所对应的语义槽定义成表2的形式,这似乎有点简单,并没有体现出系统是依靠什么技能来和用户进行交互的,其实只要在语义槽的每个槽位加上相对应的“话术”就行了,系统发现哪个槽位没填充或者有歧义就使用该槽位事先预定义好的话术去“发问”就好了。因此我们可以把上述“订电影票”的语义槽改为如下表3所示:
"订电影票": {
"电影名":,
{
"槽位值":___,
"追问话术":"请问您需要看那部电影?",
"歧义澄清话术":"你想看XX还是YYY",
"槽位预测":"/api/predict_movie_name/"
}
"电影院名称":,
{
"槽位值":___,
"追问话术":"请问您要去的电影院是哪个?",
"歧义澄清话术":"你想看XX影院还是YY影院?",
"槽位预测":"/api/predict_cinema/"
}
"时间":,
{
"槽位值":___,
"追问话术":"请问您要什么时候去看?",
"歧义澄清话术":"你想X点去还是Y点去?",
"槽位预测":"/api/predict_time/"
}
"数量":,
{
"槽位值":___,
"追问话术":"请问您需要预订几张?",
"歧义澄清话术":"你想订X张还是Y张?",
"槽位预测":"/api/predict_number/"
}
"座位位置":,
{
"槽位值":___,
"追问话术":"请您选择座位号?",
"歧义澄清话术":"你想订X号还是Y号?",
"槽位预测":"/api/predict_seat/"
}
}
上述语义槽的设计并不是最好或者最合适的,此处只是随便设计举个例子而已,实际业务中的语义槽更为复杂;通过上述例子你已经完全明白了意图识别和槽位填充是什么意思,以及理解了为什么要做意图识别和槽位填充。那么如何去做意图识别和槽位填充呢?
通过人工分析每个意图下的有代表性的例句总结出规则模板,然后将用户的输入语句进行分词、词性标注、命名实体识别、依存句法分析、语义分析等操作后套用已有的模板,当与之匹对的某个意图模板达到一定的阈值之后就认为该输入就属于该意图类别。以订机票意图为例,我们可以事先收集一些用户的相关query,然后再进行总结归纳制定模板。
从广州到贵阳市的航班
东营到济南的航班
济南去大连的航班
查询大大后天广州到武汉的航班
十月四号从广州到北京的飞机票多少钱
查询上海到丽江飞机票的价格
明天从桂林飞往杭州的航班
武汉到北京的飞机票
根据以上的示例,可以总结归纳出以下模板:
.*?[地名]{到|去|飞|飞往}[地名].*?{机票|飞机票|航班}.*?
其中 .*?
表示任意字符,[]
表示实体类型或词性,{}
表示关键词,|
表示或。当用户输入“查询后天广州到上海的航班”,我们对query进行分词和词性标注,匹配到地名“广州”、“上海”,关键词“到”、“航班”,他们的组合和预定义好的模板高度匹配,于是我们确认该query是“订机票”意图;另外对于“有没有下周二到贵阳的航班”只能匹配到一个地名和关键词“航班”,也算是和模板比较匹配了,而且如果这个匹配度和其与其他意图的模板的匹配度相比更高的话,那也可以大胆的认为该query是“订机票”意图。
使用规则模板做意图识别精确率较高,但是召回率较低,特别是对长尾query;另外该方法需要大量人工参与制定规则模板,不易自动化,更难以将其移植。
使用统计机器学习算法做文本分类,需要人工提取文本特征,比如ngram、词性特征、实体类型特征;提完特征后进行tf-idf向量化表示,然后使用支持向量机、逻辑回归、随机森林等算法进行训练。该方法显然也需要大量人工操作设计领域相关的特征,且用统计机器学习算法做文本分类效果是不怎么理想的。
使用神经网络来建模做文本分类,它省略了人工设计特征、提取特征的过程,还能借助预训练好的具有语义知识的词向量进行训练;但是该方法需要很多训练数据,这就需要依赖很多人工标注数据了,相比之下规则模板方法则不需要标注数据。
槽位填充包括命名实体识别和槽位预测,其实说命名实体识别是不严谨的,比如在“订机票”意图下的语义槽中,应该有“出发地”和“目的地”,虽然他们都是地名,但是有区别,他们的顺序不能变,也就是不能用“地名”来统一代替,而命名实体识别的做法就是将他们都当做“地名”了。我们只能称槽位填充是一个序列标注任务,但绝不能说序列标注任务就是命名实体识别,且我们在标注数据的时候也不能一样标注,下图表明了两者的区别:
可以看到槽位填充标注中,针对订机票意图的城市实体的标注,我们使用dept和arr来区分出发地和目的地实体,所以我们应该使用上图中第二种标注方式来标注数据,然后训练序列标注模型,最后用该模型去做槽位值识别
槽位预测是指当在用户的query中识别不到某些槽位值时,系统首先需要去做一个较为靠谱的预测,而不是凡事都去跟用户互动来获取这些槽位值。从上文的订电影票例子中我们可以看到针对不同槽位,张三调用了用户的地理位置、当前时间的数据来辅助预测(这就是某些APP要获取你手机的地理位置权限的原因),当然做槽位预测还有更多的操作。
本文中将意图识别和槽位填充分开来讲述,读者们可能觉得这就该是两个步骤依次进行的,其实不是,有非常多工作都是将意图识别和槽位填充进行联合训练模型。
[1]. 大话知识图谱–意图识别和槽位填充
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。