基本认知
曾经我认为Rasa_NLU是一个意图识别工具,如今我意识到并不是,Rasa_NLU只是一个自然语言理解(NLU:Natural Language Understanding的一个框架,它本身并不做任何识别的工作,真正的训练与识别工作是交由框架管理的各个组件来完成的。
Rasa_NLU框架的主要工作是:
- 组件管理
- 训练数据管理
- 模型管理
- 提供Http服务
大体结构图如下:
组件管理
前面说过,Rasa NLU框架是通过管理的组件完成意图识别的。而这个识别的过程并不是一步到位的,需要多个组件的分工合作来完成。组件之间就如同流水线作业一样,每个组件处理加工输入数据并输出处理结果供其它组件使用或者是作为最终输出。这样,可以为每个步骤提供不同的处理方式。
在介绍组件的管理之前,先大概了解一下组件的类型及各个类型的工作职责,以便大致了解意图识别的工作流程。组件的类型分为五类:
- 初始化组件:作用是初始化其它组件工作所需的内容。代码放在utils目录下。目前包含了mitie_util与spacy_util两个。
- 分词组件(tokenizer):作用是将输入的句子切分成一个个单独的词。
- 实体提取组件(extractor):作用是根据切分好的词提取设定的关键词。
- 特征提取组件(featurizer):作用是根据切分好的词提取句子的特征。
- 意图识别组件(classifier):作用是根据提取出来的特征识别意图。
框架将组件的配置存放在一个yml文件中,示例:
pipeline:
- name: "nlp_mitie"
model: "data/total_word_feature_extractor_zh.dat"
- name: "tokenizer_jieba"
- name: "ner_mitie"
- name: "ner_synonyms"
- name: "intent_entity_featurizer_regex"
- name: "intent_featurizer_mitie"
- name: "intent_classifier_sklearn"
首先通过config加载配置文件,然后通过registry查找配置文件中组件名对应的组件,然后根据配置文件中每个组件指定的参数,初始化各个组件。
训练数据管理
训练数据的组织形式有两种:单个文件或者是一个目录。
如果是一个目录时,该框架会自动加载这个目录下的全部文件数据,并进行合并。在训练数据比较多时,非常有利于训练数据的管理。
训练数据的格式也有两种:JSON格式或者是Markdown格式。
JSON格式需要标记实体在句子中的位置,而且比较繁琐。因此个人比较喜欢使用Markdown格式。
/*** JSON 格式 ***/
{
"text": "show me chinese restaurants",
"intent": "restaurant_search",
"entities": [
{
"start": 8,
"end": 15,
"value": "chinese",
"entity": "cuisine"
}
]
}
/*** Markdown 格式 ***/
## intent:restaurant_search
- show me [chinese](cuisine) restaurant
显然,Markdown格式比JSON格式要更清晰明了,也更容易标记。如果已经有了很多的JSON数据或者是只想保存JSON数据也没有关系,框架还提供了convert可以轻松将JSON格式与Markdown格式互相转换。
训练数据的类型有四种:
- 意图(intent): 意图就是普通的训练数据,用于标记句子意图与句子中包含的实体。
- 同义词(synonym): 同义词的作用是在实体被提取出来后,转化为统一的词,以便于后续的处理。
- 正则表达式(regex): 正则表达式的作用是对于句子的,而不是实体,用于提供句子特征,以便于意图的识别。
- 查找表(lookup): 在框架的处理中会被理成一个大的正则表达式。
/*** JSON 格式 ***/
{
"rasa_nlu_data": {
"common_examples": [
{
"text": "hey",
"intent": "greet"
},
{
"text": "hello",
"intent": "greet"
}
],
"entity_synonyms": [
{
"value": "savings",
"synonyms": ["pink pig"]
}
],
"regex_features" : [
{
"name": "zipcode",
"pattern": "[0-9]{5}"
}
],
"lookup_tables" : [
{
"name": "currencies",
"elements": ["Yen", "USD", "Euro"]
},
{
"name": "additional_currencies",
"elements": "path/to/currencies.txt"
}
]
}
}
/*** Markdown 格式 ***/
## intent:greet
- hey
- hello
## synonym:savings
- pink pig
## regex:zipcode
- [0-9]{5}
## lookup:currencies
- Yen
- USD
- Euro
## lookup:additional_currencies
path/to/currencies.txt
训练数据的加载
在框架源代码中,所有训练数据的处理代码放在training_data包中。通过包中的longing模块加载目录或文件中的各种格式的训练数据。然后实例化各训练数据结构,以待各组件训练模型时使用。
模型管理
模型的结构
在Rasa_NLU中有工程和模型的概念,换个说法就是Rasa_NLU框架可以同时管理多个工程与模型。其结构是模型的存储目录下可以有多个工程,每个工程下又可以有多个模型。
模型的训练与存储
在训练时,model模块中的Trainer使用Pipeline中指定并通过config模块加载完成的组件训练转换完成的训练的数据,然后通过persistor模块将模型持久化。
persistor模块中默认存储器可以将模型持久化到本地目录,同时还提供了一些可将模型持久化到云服务中的存储器。
持久化的过程是初始化存储器及模型路径。如果没有指定工程及模型,模型将会被存储在default工程下的一个由框架生成的模型中,模型名为当前时间。然后,再依次调用各个组件,将各个组件中的模型数据持久化。最后将Pipeline持久化到指定模型的Metadata.json中。
模型的加载与使用
在训练完成并持久化存储后,可以通过加载这个模型用来提取句子的意图及包含的实体。前面有说到该框架有工程与模型的概念,对应的,在代码中也有相关的管理代码。通过project来加载工程,model来加载模型。主要逻辑包含了默认模型的加载,default工程下最新训练的模型,指定工程与模型的加载、以及加载远程云服务中存储的模型等。
提供Http服务
Rasa_NLU框架还可以直接启动一个Web Service服务,以便于远程访问。服务提供了模型的训练、句子意图的分析、模型的评估等基本功能,还提供了模型的加载、卸载、服务状态等功能。
框架通过server模块启动服务并接收http请求,然后再使用data_router模块分发使用各个功能模块,执行请求的操作。
框架还通过在data_router中组合emulator,通过各emulator的实现格式化服务输出结过的格式。