
Rasa2 NLU 架构及源码解析(二)
尊龙时凯
李丹 郑飞 杜昕宸 韩彤 秦帅帅

Rasa是当前智能机器人中最流行的的聊天机器人框架,,,,是基于机器学习和自然语言处理技术开发的系统,,,用于构建上下文AI助手和聊天机器人。。。
1.
背景
近年来,,,聊天机器人受到了学术界和工业界的广泛关注。。。。人工智能技术的快速发展突破了聊天机器人原有的技术瓶颈,,,,并且实践证明,,聊天机器人的使用不仅能够为企业减少一大笔人力成本,,,,而且能够明显提高工作效率,,,国内外多家企业纷纷布局聊天机器人行业。。微软推出了基于情感计算的聊天机器人小冰,,百度推出了用于交互式搜索的聊天机器人小度,,,,进而推动了聊天机器人产品化的发展。。。聊天机器人系统可以看作是机器人产业与“互联网+”的结合,,符合国家的科研及产业化发展方向。。
随着人工智能在银行和金融科技的客户服务方面取得了重大改进,,,,客户越来越习惯于获得快速响应。。。金融机构必须全天候回答客户问题和进行交易。。金融机构业务扩展的加速使人工客服的成本大幅攀升的同时又无法持续满足服务质量,,,人工智能机器人通过金融机构长期积累的业务经验和数据培训聊天机器人,,可明显改善客户体验。。基于上述痛点和需求,,各类聊天机器人框架应运而生。。根据社区活跃度、、技术的成熟完备度及被引用、、点赞等指标,,,我们采用Rasa作为人机交互对话机器人基本框架。。
2.
Rasa简介
Rasa Open Source有两个主要模块:
●Rasa NLU :用于理解用户消息,,,,包括意图识别和实体识别。。以pipeline的方式处理用户对话,,,,可在config.yml中配置。。
●Rasa Core:主要负责对话管理。。。。根据NLU输出的信息、、、以及Tracker记录的历史信息,,,,得到上下文的语境,,从而预测用户当前步最可能执行哪一个action。。。
其中,,,,Rasa NLU主要依赖自然语言处理技术,,是可以独立的、、与整体框架解耦的模块,,可支持大量NLP前沿技术,,,以组件的形式,,,可以灵活与其他开源、、自研框架搭配使用。。。。
3.
Rasa NLU架构及源码解析
3.2 Extractor
3.2.1 主流技术支持情况

3.2.2 CRF extractor
3.2.2.1架构


3.2.2.2模型支持及说明
CRF 即条件随机场,,,是在给定一组输入随机变量条件下另外一组输出随机变量的条件概率分布模型,,它是一种判别式的概率无向图模型。。。。
CRF 可以对序列数据建模,,,,适用于做序列标注任务,,,比如分词,,,命名实体识别,,词性标注等。。。
rasa中使用crf用来进行实体提取,,,,使用BILOU 进行标注。。
BILOU is short for Beginning, Inside, Last, Outside, and Unit-length.
CRF特征函数:
状态特征函数,,, 状态特征函数只和当前节点 i 相关,,,,是定义在 i上的节点特征函数。。。。
转移特征函数,,,,与结点的上下文相关,,,即与节点 i 和节点 i - 1 都有关系,,,,是定义在 i上下文的局部特征函数。。。

无论是节点特征函数还是局部特征函数,,,,它们的取值只能是0或者1。。。。即满足特征条件或者不满足特征条件。。。。同时,,,,为每个特征函数赋予一个权值,,用以标示这个特征函数的信任度。。
CRF的优点:
HMM,,,由于其输出独立性假设,,,导致其不能考虑上下文的特征,,,限制了特征的选择,,,,CRF没有HMM那样严格的独立性假设条件,,,,因而可以容纳任意的上下文信息,,,,特征设计灵活。。。。
MEMM只在局部做归一化,,,,所以容易陷入局部最优,,CRF模型中,,统计了全局概率,,,在做归一化时,,考虑数据在全局的分布,,,解决了MEMM中的标记偏置的问题,,可以得到全局最优。。
CRF的缺点:
训练代价大、、复杂度高。。。。
3.2.2.3配置样例
分词(SpacyTokenizer)数据标注输出:
{'text': '可以找到泰餐吗', 'intent': '找饭店', 'entities': [{'start': 4, 'end': 6, 'value': '泰餐', 'entity': 'cuisine'}], 'text_tokens': [...], 'bilou_entities': ['O', 'O', 'U-cuisine', 'O']]}


分字(BertTokenizer)数据标注输出:
{'text': '可以找到泰餐吗', 'intent': '找饭店', 'entities': [{'start': 4, 'end': 6, 'value': '泰餐', 'entity': 'cuisine'}], 'text_tokens': [...], 'bilou_entities': ['O', 'O', 'O', 'O', 'B-cuisine', 'L-cuisine', 'O']}


预训练模型只是用来进行 tokenizer,,,用于 ner,,,, 本示例没有考虑意图分类的功能。。。。
预训练模型地址:https://huggingface.co/Langboat/mengzi-bert-base-fin
3.2.2.4 核心代码解析
●_convert_to_crf_tokens(): 转换基于 Message 的数据为 CRFToken对象格式的列表
●_crf_tokens_to_features(): 构造模型输入数据
●_crf_tokens_to_tags(): 构造模型标签数据
●_tag_confidences(): 输出标签置信度
3.2.3 Duckling extractor
3.2.3.1架构

3.2.3.2模块说明
使用 Facebook 的 Duckling 进行基于规则的实体识别:ner_http_duckling
Duckling 是 Facebook 基于规则开发的实体提取库。。如果你要提取任何与数字有关的信息,,,例如:金额、、、日期、、距离或持续时间等,,那么它是个不错的选择。。。Duckling 是在 Haskell 中实现的,,,,Python 库并未很好地支持它。。。。为了与 Duckling 通信,,Rasa NLU 使用了 Duckling 的 REST 接口。。因此,,,,当你将 ner_duckling_http 组件添加 NLU pipeline 中时,,,,你必须运行 Duckling 服务器。。。
启动服务器的最简单方法是使用 docker 映像 rasa/rasa_duckling 并运行服务器 :
docker run -p 8000:8000 rasa/rasa_duckling
3.2.3.3主要函数
_duckling_parse():解析输入文本并请求 rest api 进行数据处理,,,返回标注结果。。。
3.2.4 Entity synonyms
3.2.4.1模型支持及说明
ner_synonyms不是一个命名实体的提取组件,它主要是将各种同义词(synonyms)映射成标准词汇,,比如将实体“KFC”映射成“肯德基”,,归一化操作为后续业务处理提供便利。。。
3.2.4.2配置样例
nlu.yml配置

pipeline配置

样例结果:

3.2.4.3核心代码解析
train:

add_entities_if_synonyms:把实体与同义词映射存储到synonyms
process:

replace_synonyms: 把识别出的实体替换成synonyms中的key
3.2.5 Mitie extractor
3.2.5.1模型支持及说明
mitie 使用多分类线性svm做实体抽取,,使用BILOU进行标注。。。在MitieEntityExtractor执行的时候,,,会自己重新生成feature。。。MITIE能生成的良好的特征向量和实体识别,,,与sklearnIntentClassifier训练效果比较好。。
3.2.5.2配置样例
pipeline

示例结果:

3.2.5.3核心代码解析
train

filter_trainable_entities: 去除不可训练的实体标注
_prepare_mitie_sample: 去掉不包含实体的example
process:

extract_entities:提取实体
add_extractor_name:添加提取器的名称到实体列表

3.2.6 Regex extractor
3.2.6.1架构

RegexEntityExtractor主要由train,,,,process,,,,persist和load四部分组成
3.2.6.2工作机制
该组件使用在训练数据中定义的查找表和正则表达式提取实体。。该组件检查用户消息是否包含某个查找表的条目或与某个正则表达式匹配。。。如果找到匹配项,,则将该值提取为实体。。
此组件只使用实体名称等于训练数据中定义的实体之一的正则表达式的pattern,,,所以训练数据中,,,要确保每个实体至少注释一个示例。。。。
case_sensitive:配置参数case_sensitive指定是否大小写敏感。。
use_word_boundaries:在中文中没用,,,在whitespaceTokenizer中使用
3.2.6.3核心代码
●def extract_patterns():训练阶段核心函数,,,,根据lookup_tables表和正则表达式生成pattern
●def _extract_entities():推理阶段核心函数,,,根据pattern抽取实体
3.2.6.4使用样例
1.配置config.yml文件

注意中文场景use_word_boundaries需要置为False,,,否则不识别
2.regex抽取实体
● nlu.yml文件配置

●样例

3.look_up tables抽取实体
●nlu.yml文件配置
(1)nlu.yml文件中配置lookup_tables

(2).文件导入look_up tables
文件导入不需要在config.yml或nlu.yml文件中进行路径配置,,,只需要将要导入的look_up tables.yml文件放在./data/nlu/lookups/look_up tables.yml路径下即可

●样例

3.2.7 Spacy extractor
3.2.7.1架构

3.2.7.2.工作机制
使用SpacyNLP提取命名实体。。。需要引入SpacyNLP语言模型,,,, SpacyTokenizer,,, SpacyFeaturizer。。。
SpaCyNLP 使用统计BILOU转换模型。。SpacyEntityExtractor只能使用内置的NER模型,,,,不支持重新训练新模型,,,,而且模型输出无置信度分数。。。
SpacyEntityExtractor配置使用的时候,,可以通过dimensions参数指定提取的实体包括的内容,,种类如下:

如果不指定,,,默认会返回所有。。。配置方式如下:

3.2.7.3.核心代码
●def process():SpacyNLP抽取实体,,,,根据dimensions参数选择返回用户配置的维度
3.2.7.4.SpacyNLP NER工具
1.快速使用
(1).抽取实体


(2).详细实体信息


2.基于规则抽取实体

3.pipeline
在对文本调用nlp时,,spaCy首先标记文本以生成Doc对象。。。。然后,,,,在几个不同的步骤中处理该文档——这也被称为processing pipeline。。。。pipeline通常包括tagger、、、、lemmatizer、、parser和entity recognizer。。。

4.Embeddings & Transformers
SpacyNLP工具支持从FastText和Gensim等工具转换词向量,,,,或者通过安装spacy transformers,,加载任何预训练的transformer模型。。还可以通过spacy pretrain命令进行自己的语言模型预训练,,,且可以跨多个组件共享模型。。

5.Training
通过命令spaCy train命令训练Spacy pipeline。。进行训练需要配置一个包含所有设置和超参数的config.cfg文件。。Spacy支持加载Python文件进行自定义训练。。。。

3.2.7.5.SpacyNLP NER算法原理
1.构建action集合,,,spacy默认BILUO标注体系为实体抽取器的action集合,,,,具体为[M, B, I, L, U, O]
2.构建neural network state prediction model,,,使用两层或者三层网络,,分别是
●tok2vec:token的embedding映射层
●lower:为每一对(token, feature)构造特定的特征向量
●upper(可选):预测动作分数的前馈网络。。。如果不存在,,则来自较低模型的输出直 接用作行动分数(对于transformers等大型预训练模型,,,建议将其设置为False,,,,对于较小的网络,,建议将其设置为True)
3.构建stack与buffer容器,,,stack主要用来储存处理之后的spans,,buffer用来储存未处理 的tokens。。给定parse state的状态,,,,结合贪心算法(支持beam_search)和神经网络预测用于更改parse state的action(状态),,,,当预测到表示实体末尾的action,,,stack会将标注的实体片段从stack弹出,,,从buffer继续载入token进入stack进行action预测,,直至处理完全部token

3.2.7.6.使用样例
1.环境配置
(1).安装Spacy

(2).安装Spacy模型
●首先需要下载Spacy模型文件,,,可以选择到官方链接(Chinese · spaCy Models Documentation:https://spacy.io/models/zh/)下载模型或自行搜索下载.whl文件或者.tar.gz文件
●安装Spacy模型文件(rasa中使用Spacy工具必须安装模型文件,,不可路径导入)

2.配置config.yml文件

3.实体抽取
●样例(未指定dimensions,默认按照Spacy指定名称抽取全部类型实体)

我怎样30号在中国给乔布斯转账10000元购买苹果手机
"entities": [
{
"entity": "DATE",
"value": "30号",
"start": 3,
"confidence": null,
"end": 6,
"extractor": "SpacyEntityExtractor"
},
{
"entity": "GPE",
"value": "中国",
"start": 7,
"confidence": null,
"end": 9,
"extractor": "SpacyEntityExtractor"
},
{
"entity": "PERSON",
"value": "乔布斯",
"start": 10,
"confidence": null,
"end": 13,
"extractor": "SpacyEntityExtractor"
},
{
"entity": "MONEY",
"value": "10000元",
"start": 15,
"confidence": null,
"end": 21,
"extractor": "SpacyEntityExtractor"
}
]
●指定dimensions

我怎样30号在中国给乔布斯转账10000元购买苹果手机
"entities": [
{
"entity": "GPE",
"value": "中国",
"start": 7,
"confidence": null,
"end": 9,
"extractor": "SpacyEntityExtractor"
},
{
"entity": "PERSON",
"value": "乔布斯",
"start": 10,
"confidence": null,
"end": 13,
"extractor": "SpacyEntityExtractor"
}
]
●注意事项
Spacy工具抽取的实体名称只能是Spacy指定的实体名称。。当样例中实体名称与Spacy指定实体名称不同时,,会将其更改为指定实体名称


3.2.8 Custom Component
在Rasa中,,NLU部分由各功能组件(component)以一定顺序排列形成的pipeline构成。。。

Message变量类似pipeline流水线上的“工件”,,组件的操作相当于流水线上的各道“工序”,,,将提取当下message的数据信息,,,,计算完毕后将结果更新到message中,,,,进入下一道“工序”。。。
组件继承于component类,,,,不局限于其主要功能,,,,在结构上应该包含以下重要属性和方法:

每个组件在pipeline中都需要承上启下,,因此除了基本的name组件名外,,,需要明确其依赖的变量或组件(requires)以及能为后续组件生成提供的数据(provides),,,defaults中一般规定默认参数,,,,如模型的训练参数、、、、分词器的词典路径等。。
从实际使用角度,,,,组件需要考虑到训练和推理两方面:
●训练:def train、、、persist
●推理:def load、、、、process
自定义组件可以自主编写代码实现功能或引用现成模型(仍需封装露出train、、、、load、、、、process适配rasa框架),,这里需要注意的是,,,,两种方式都需要格外注意数据格式统一的问题:
1)现成模型可能对维度等数据格式有特定要求
2)自定义组件与相邻组件间数据格式严格对齐,,,因此引用外部模型作为组件是需要需要经历数据格式的转换与恢复
自定义组件一般以.py文件的形式保存于components文件夹下,,对应地使用方式如下:

自定义Extractor案例分享
1) 绝对匹配实体提取:
https://blog.csdn.net/lly1122334/article/details/106140615
2) 模糊实体提取
https://github.com/ESCdeGmbH/rasa-custom-entity-extraction/blob/master/simple_entity_extractor.py
3) 数据库实体提取
https://github.com/ESCdeGmbH/rasa-custom-entity-extraction/blob/master/database_entity_extractor.py
4) LUIS实体提取
https://github.com/ESCdeGmbH/rasa-custom-entity-extraction/blob/master/luis_entity_extractor.py
其他案例:意图修改组件
https://github.com/vba34520/rasa_nlu_xercis

