NLU意图识别的流程说明

基于智能问答的业务流程,所谓的NLU意图识别就是针对已知的训练语料(如语料格式为\((x,y)\)格式的元组列表,其中\(x\)为训练语料,\(y\)为期望输出类别或者称为意图)采用选定的算法构建一个模型,而后基于构建的模型对未知的文本进行分类。流程梳理如下:

  • 准备训练数据,按照固定的格式进行;
  • 抽取所需要的特征,形成特征向量;
  • 抽取的特征向量与对应的期望输出(也就是目标label)一起输入到机器学习算法中,训练出一个预测模型;
  • 对新到的数据采取同样的特征抽取,得到用于预测的特征向量;
  • 使用训练好的预测模型,对处特征处理后的新数据进行预测,并返回结果。

从流程梳理看,NLU的意图识别从根本上看是有监督的机器学习,即基于给定的人工筛选数据进行特征处理,构建模型用于预测。处理流程图如下所示:

针对NLU意图识别原理的例子说明

基于上述说明的流程,用一个例子来进行原理说明。

场景

小明需要订购一张从上海到北京的机票(意图:订机票),在订票的过程中想要了解下北京的天气情况(意图:查天气),看是否需要准备一把雨伞;同时考虑初到北京对地方不熟悉,希望协助订餐(意图:订餐)。

准备数据

根据第一部分介绍的流程,需要先准备上述场景涉及意图的训练数据,以备模型构建使用,我们准备如下的几条数据(此处为了描述方便,每个意图我们仅提供一条数据进行说明,在实际处理中每个意图至少需要2条语料):

  • 帮我查询明天到北京的机票。---------> 订机票
  • 北京明天是否有雨?---------> 查天气
  • 帮我定个烤鸭送到酒店。---------> 订餐

在第一条的语料“帮我查询明天到北京的机票。”中,我们可以通过实体抽取提取出“时间:明天、目的地:北京”,通过隐含条件可以推算出出发地为上海(基于用户当前的定位数据等),这部分信息可以作为对话过程中的关键信息收集起来,作为后续的订票主要信息。因此处我们主要介绍意图识别,对于实体提取的一些处理流程不做具体的介绍。

特征提取

特征的提取是为了方便后续的计算,在中文文本处理中,常用的特征处理有词袋模型(bag of word)、Tf-idf、SVD奇异值分解等,这里为了方便说明,我们采用词袋模型(bag of word)。特征权重的计算方法采用简单的\(1/n\)进行,其中\(n\)为所有语料中该词出现的个数。

针对上文的数据,首先构造词典,利用jieba分词,对上述语料进行分词,而后统计各个词的权重,结果如下所示:

"帮我查询明天到北京的机票。"分词结果如下:
['帮', '我', '查询', '明天', '到', '北京', '的', '机票', '。']
"北京明天是否有雨?"分词结果如下:
['北京', '明天', '是否', '有雨', '?']
"帮我定个烤鸭送到酒店。"分词结果如下:
['帮', '我定', '个', '烤鸭', '送到', '酒店', '。']
整合后的词典及词权重如下所示:
['帮':0.5, '我':1.0, '查询':1.0, '明天':0.5, '到':1.0, '北京':0.5, '的':1.0, '机票':1.0, '。':0.5, '是否':1.0, '有雨':1.0, '?':1.0, '我定':1.0, '个':1.0, '烤鸭':1.0, '送到':1.0, '酒店':1.0]
模型训练

基于上步构造的词典,对样本数据进行特征权重构造(也就是模型构建的过程,如果是使用神经网络等深度学习技术的话,就是通过样本数据学习各个特征的权重及偏置),如下所示:

"帮我查询明天到北京的机票。"特征如下:
['帮':0.5, '我':1.0, '查询':1.0, '明天':0.5, '到':1.0, '北京':0.5, '的':1.0, '机票':1.0, '。':0.5]
"北京明天是否有雨?"特征如下:
['北京':0.5, '明天':1.0, '是否':1.0, '有雨':1.0, '?':1.0]
"帮我定个烤鸭送到酒店。"特征如下:
['帮':0.5, '我定':1.0, '个':1.0, '烤鸭':1.0, '送到':1.0, '酒店':1.0, '。':0.5]
新数据特征提取

在上述几步流程中,我们已经通过准备的训练数据构建好了预测模型,针对新的数据,需要经过同样的特征提取流程获取新数据的特征向量。

比如新数据为:查询机票。

结巴分词结果如下:

['查询', '机票', '。']

基于构造的词典,获得各个特征的权重如下:

['查询':1.0, '机票':1.0, '。':0.5]
模型预测

通过模型计算新数据与各个类别(意图)的得分(为了方便说明,这里直接比对新数据与各个类别数据特征匹配上的个数,而后计算相关的权重得分),如下所示:

订机票意图特征命中:查询、机票、。
得分:1.0(查询)+1.0(机票)+0.5(。)=2.5 查天气意图特征命中:
得分:0.0(查询)+0.0(机票)+0.0(。)=0.0 订餐意图特征命中:。
得分:0.0(查询)+0.0(机票)+0.5(。)=0.5

采用得分最高作为最终意图,则新数据意图为“订机票”。

备注:在上述的处理过程中,出现了很多的得分为0项,在实际的处理过程中会做平滑处理,常用的平滑处理有\(add-k smoothing、Good-turning\)等平滑方法。

NLU识别引擎中使用的pipline分析

上面是简单的描述了文本分类模型的构建及模型使用的介绍,在实际的场景处理中会比较复杂,本节针对我们在使用RASA框架的NLU模块的一个文本处理pipline进行流程分析说明。

pipline如下所示:

language: "zh"

pipeline:
- name: JiebaTokenizer
- name: CRFEntityExtractor
- name: EntitySynonymMapper
- name: CountVectorsFeaturizer
- name: EmbeddingIntentClassifier

意图识别的三个流程涉及JiebaTokenizer(分词)、CountVectorsFeaturizer(特征向量表示)、EmbeddingIntentClassifier(分类)三个过程,我们主要对上述三个进行说明。

JiebaTokenizer 分词

分词组件这里主要是使用的一个开源分词jieba分词,通过结巴分词将我们的训练语料或者是传入的用户语句进行分词处理,获取分词后的结果。

关注下,语料经过jieba分词后会得到一个词在该条语料中的开始start、结束end位置信息,在最终返回给其他算法处理时仅返回词条在训练语料的开始start位置,结束end信息后续会通过开始start+len(word)的方式获得。

分词的示例:

import jieba
text = "帮我查询明天到北京的机票。"
tokenized = jieba.tokenize(text)
# tokens = [Token(word, start) for (word, start, end) in tokenized]
print(list(tokenized)) [('帮', 0, 1), ('我', 1, 2), ('查询', 2, 4), ('明天', 4, 6), ('到', 6, 7), ('北京', 7, 9), ('的', 9, 10), ('机票', 10, 12), ('。', 12, 13)]
CountVectorsFeaturizer 特征向量表示

CountVectorsFeaturizer 是一种基于特征的tf表示的向量标识方法,其核心思想与上述示例中的基本一致,也是通过对训练集数据经过分词后构建词典,而后针对每一条训练文本统计其特征的相关tf,形成特征向量表示(或者认为是词频矩阵)。这里需要注意下,CountVectorsFeaturizer 中有一些默认参数,会对分词后的数据进行一些处理,比如针对英文的一些大小写转换、针对中文的单字过滤、停用词过滤等操作。

我们仍然使用上文示例中出现的3条语料进行CountVectorsFeaturizer 的表示,示例代码采用sklearn中的CountVectorizer,如下所示:

from sklearn.feature_extraction.text import CountVectorizer
# "帮 我 查询 明天 到 北京 的 机票" 为输入列表元素,即代表一个文章的经过分词后的词,这里为了便于说明去除了其他一些信息,每个语料为一条信息
texts = ["帮 我 查询 明天 到 北京 的 机票", "北京 明天 是否 有雨", "帮 我定 个 烤鸭 送到 酒店"]
# 创建词袋模型
cv = CountVectorizer()
# 词袋模型构建
cv_fit = cv.fit_transform(texts)
# 打印所有的训练语料形成的词典中的词
print(cv.get_feature_names())
结果: ['北京', '我定', '明天', '是否', '有雨', '机票', '查询', '烤鸭', '送到', '酒店'] # 打印所有的训练语料形成的词典及该词在词典中的标号
print(cv.vocabulary_)
结果: {'查询': 6, '明天': 2, '北京': 0, '机票': 5, '是否': 3, '有雨': 4, '我定': 1, '烤鸭': 7, '送到': 8, '酒店': 9} # 打印出特征的词频标识
print(cv_fit)
结果: (0, 5) 1 0:texts中的第0个元素; 5:词典中顺序为5的词,即“机票”; 1:词频
(0, 0) 1
(0, 2) 1
# 结果转化为稀疏举证标识
print(cv_fit.toarray())
结果: [[1 0 1 0 0 1 1 0 0 0]
[1 0 1 1 1 0 0 0 0 0]
[0 1 0 0 0 0 0 1 1 1]]

上述示例中单条语料中没有出现重复的词,我们对第一条语料增加一个“北京”对比看下,结果如下所示:

from sklearn.feature_extraction.text import CountVectorizer

# "帮 我 查询 明天 到 北京 的 机票" 为输入列表元素,即代表一个文章的字符串
texts = ["帮 我 查询 明天 到 北京 的 机票 北京", "北京 明天 是否 有雨", "帮 我定 个 烤鸭 送到 酒店"]
# 创建词袋模型
cv = CountVectorizer()
cv_fit = cv.fit_transform(texts)
# print(cv.get_feature_names())
# print(cv.vocabulary_)
# print(cv_fit)
print(cv_fit.toarray()) 结果:[[2 0 1 0 0 1 1 0 0 0]
[1 0 1 1 1 0 0 0 0 0]
[0 1 0 0 0 0 0 1 1 1]]

经过处理后就将我们所提供的训练文本转换成了特征的向量表示形式,这些特征向量在传入到EmbeddingIntentClassifier中与各条语料的类别标识一同进行训练成模型。

EmbeddingIntentClassifier 分类(模型构建)

rasa框架是通过集成TensorFlow来进行模型构建的,一些细节进行了封装,为了说明清晰,这里撇开TensorFlow框架进行分析。

同样使用上文处理好的稀疏向量为例:

三条语料:帮我查询明天到北京的机票。 北京明天是否有雨? 帮我定个烤鸭送到酒店。 其对应的特征向量如下所示:
[[1 0 1 0 0 1 1 0 0 0]
[1 0 1 1 1 0 0 0 0 0]
[0 1 0 0 0 0 0 1 1 1]] 三条语料的意图分别为:订机票、查天气、订餐

基于上述的特征数据,我们构建一个4层的神经网络,其中第一层为输入层,其接收我们处理后的特征向量数据,根据上述示例,每个语料有10个向量值,则我们的第一层输入层对应有10个神经元;最后一层为输出层,也就是结构层,我们这里有三个意图分类,则我们的输出神经元对应有3个;中间两层时隐藏层,我们可以根据需要进行设计。

备注:神经网络的主要思想可以看做是通过大量的训练样本,自动学习一个模拟函数,进而对未知数据进行预测。或者说神经网络使用样本数据自动推断出每一类的的特征规则,然后应用的新的位置数据上,进而达到分类的目的。

经过上述说明后,设计如下的神经网络结构:

输入层较多,我们仅画出部分表示,层与层之间采用全连接的方式,激活函数我们选择使用sigmoid函数。

针对上述的神经网络结构,每一个神经元的结构如下所示:

其中\(x_1,x_2,...,x_{10}\)就是我们上文处理后的特征向量,我们上文示例是10维度的,一般的情况下输出的维度都比较大,\(z=w_1x_1+w_2x_2+...+w_{10}x_{10}+b\)为加权输入,输出则为激活函数作用在加权输入\(z\)上,即\(y=\sigma(z)\).

上述我们已经构建了一个4层的神经网络,那该神经网络如何与我们的分类结合在一起呢?在数学上,我们一般将这类问题归纳为优化问题,也就是有了训练数据与相关的数据标识,则可以通过设计相关的优化函数进行。比如我们在上文已经将语料 “帮我查询明天到北京的机票。” 标识成一个1X10的向量表示 [1 0 1 0 0 1 1 0 0 0],我们设计了一个模拟函数\(y=y(x)\)标识对应的期望输出,根据上文示例,这个输出是一个3维的向量,对于语料 “帮我查询明天到北京的机票。” 我们期望的输出应该是\(y(x)=(1,0,0)^T\),如何求出这个模拟函数(一般情况下则是求相关的权重和偏置)则是我们模型构建的过程,即上面说的最优化问题。

针对我们上面是设计的神经网络,我们选择二次代价函数(也称为均方误差代价函数):

\[C = \frac{1}{2n}\sum_{x}^{}(y(x)-a)^2
\]

模型的构建过程就是基于训练语料对上述代价函数进行最优化的过程,最终得到\(y(x)\)函数的权重及偏置,则在新的用户数据请求到来后,直接进行计算则可以得到相应的分类结果。

注:上述最优化过程在深度学习中最常用的是反向传播算法,这块内容因为涉及的细节后数学公式推导较多,可以参考我整理的笔记 神经网络的几点记录反向传播的四个基本方程

上述流程即是使用RASA的NLU进行模型构建及模型预测的流程,其思想与上述中的例子所讲基本上类似。

智能问答中的NLU意图识别流程梳理的更多相关文章

  1. 浅谈意图识别各种实现&数学原理

    \[ J_\alpha(x) = \sum_{m=0}^\infty \frac{(-1)^m}{m! \Gamma (m + \alpha + 1)} {\left({ \frac{x}{2} }\ ...

  2. 使用LSTM和Softmx来进行意图识别

    前言 在前面我们大致介绍了什么是意图识别,把这个问题抽象出来其实是一个分类问题.在结构上面,我们使用LSTM来提取特征,Softmax来进行最后的多分类.由于语料的限制,我们目前仅考虑电台,音乐,问答 ...

  3. 如何使用padlepadle 进行意图识别-开篇

    前言 意图识别是通过分类的办法将句子或者我们常说的query分到相应的意图种类.举一个简单的例子,我想听周杰伦的歌,这个query的意图便是属于音乐意图,我想听郭德纲的相声便是属于电台意图.做好了意图 ...

  4. 计算广告(5)----query意图识别

    目录: 一.简介: 1.用户意图识别概念 2.用户意图识别难点 3.用户意图识别分类 4.意图识别方法: (1)基于规则 (2)基于穷举 (3)基于分类模型 二.意图识别具体做法: 1.数据集 2.数 ...

  5. 【audio】耳机插拔 线控按键识别流程【转】

    耳机插拔/线控按键识别流程 耳机插拔/线控按键识别流程 1.文档概述 本文以msm8909平台,android N为例,介绍了通用情况下,耳机插拔的流程步骤,以及对耳机类型的识别逻辑.以方便在项目工作 ...

  6. 智能家居中的物联网网关的可信计算平台模块(TPM)设计

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/BlueCloudMatrix/article/details/24184461 摘要: 随着智能家居 ...

  7. 完整的验证码识别流程基于svm(若是想提升,可优化)

    字符型图片验证码识别完整过程及Python实现 首先很感觉这篇文章的作者,将这篇文章写的这么好.我呢,也是拿来学习,觉得太好,所以忍不住就进行了转载. 因为我个人现在手上也有个验证码识别的项目,只是难 ...

  8. springboot+lucene实现公众号关键词回复智能问答

    一.场景简介 最近在做公众号关键词回复方面的智能问答相关功能,发现用户输入提问内容和我们运营配置的关键词匹配回复率极低,原因是我们采用的是数据库的Like匹配. 这种模糊匹配首先不是很智能,而且也没有 ...

  9. Action4D:人群和杂物中的在线动作识别:CVPR209论文阅读

    Action4D:人群和杂物中的在线动作识别:CVPR209论文阅读 Action4D: Online Action Recognition in the Crowd and Clutter 论文链接 ...

随机推荐

  1. Mysql----左连接、右连接、内连接、全连接的区别

    最近,突然想起来数据库有好些时间没用到,所以,想把数据库有关的知识回顾一下,所以接下来这个月,基本上会以数据库的帖子来写为主,首先,很多同学都会有个错觉,觉得学习数据库会sql语句的增删改查就够了,其 ...

  2. Ethical Hacking - POST EXPLOITATION(4)

    PIVOTING Use the hacked device as a pivot. Try to gain access to other devices in the network. Tool: ...

  3. fastjson将json字符串转化为java对象

    目录 一.导入一个fastjson的jar包 二.Json字符串格式 三.根据json的格式创建Java类 四.给java类的所有属性添加setter方法 五.转换为java对象 一.导入一个fast ...

  4. TLV通信协议

    基础 TLV协议是BER编码的一种,全称是Tag.length.value.该协议简单高效,能适用于各种通信场景,且具有良好的可扩展性.TLV协议的基本格式如下: 其中,Tag占2个字节,是报文的唯一 ...

  5. springAOP的三种实现方式

    springAOP的实现方式 三种 纯XML方式,XML+注解,纯注解方式. Spring 实现AOP思想使⽤的是动态代理技术 默认情况下, Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还 ...

  6. 支持向量机SMO算法实现(注释详细)

    一:SVM算法 (一)见西瓜书及笔记 (二)统计学习方法及笔记 (三)推文https://zhuanlan.zhihu.com/p/34924821 (四)推文 支持向量机原理(一) 线性支持向量机 ...

  7. 面试题十八:在O(1)的时间内删除链表的节点

    方法一:将要删除的·节点的下一个节点的内容复制到该节点上,然后删除下一个节点注意特殊情况:链表只有一个节点时,则删除头节点,则把头节点设置为null, 如果删除的尾节点则需要顺序遍历链表,取得前序节点 ...

  8. 第三节:Centos下安装Mysql5.6数据库

    1.下载mysql5.6版本 [官网-需要什么版本自己去找]https://dev.mysql.com/downloads/mysql/5.6.html [版本]linux通用 cd /usr/loc ...

  9. 花了一个月的时间在一个oj网站只刷了这些题,从此入门了绝大多数算法

    如果你想入门算法,那么我这篇文章也许可以帮到你. oj网站有这么多,当然还有其他的.我当初是在hdu上面刷的,不要问我为什么,问就是当时我也是一个新手,懵懵懂懂就刷起来了.点这里可以进入这个网站htt ...

  10. 2020想学习JAVA的同学看过来,最基础的编程CRUD你会了没?

    一 JDBC简介 Java DataBase Connectivity Java语言连接数据库 官方(Sun公司)定义的一套操作所有关系型数据库的规则(接口) 各个数据库厂商去实现这套接口 提供数据库 ...