本指南的目的是解释组件在Rasa NLU管道中扮演的角色,以及它们如何相互作用。
在Rasa中,NLU管道是在config.yml
文件中定义的。此文件描述了,Rasa通过使用管道检测意图和实体的所有步骤。它以文本作为输入开始,并一直解析,直到有实体和意图作为输出。
在管道中可以找到不同类型的组件。主要有:
Tokenizers
)Featurizers
)Intent Classifiers
)Entity Extractors
)在讨论这些组件如何相互作用之前,我们将讨论它们各自的作用。
第一步是将话语分成更小的文本块,称为tokens
。这必须在为机器学习对文本进行特征化之前发生,这就是为什么通常在管道的开头会首先列出一个分词器。
分词器的详细信息。
分词器将话语中的每个单词分割成一个单独的标记(token
),通常分词器的输出是一个单词列表。我们也可能会得到单独的标点符号,这取决于分词器和我们的设置。
对于英语,我们通常使用WhiteSpaceTokenizer,但是对于非英语,通常选择其他的。比如,对于非英语的欧洲语言,通常选择SpaCy;对于汉语则通常选择Jieba。
请注意,分词器不会更改基础文本,它们只将文本分隔为标记(token
)。例如,这意味着首字母大写仍然没有受到影响。可能您只希望为管道编码小写文本,但添加此类信息是Featureizer的工作,我们将在下一步讨论。
特征化器为机器学习模型生成数字特征,即将文本转化为数字。下图显示了单词“Hi”的编码方式。
特征有两种类型:
CountVectorizer
生成。注意,这些计数也可以表示子词。我们还有一个LexicalSyntacticFeaturizer
,它生成window-based
的特征,用于实体识别。当与spaCy结合使用时,LexicalSyntacticFeaturizer
还可以配置词性特征。
除了标记(token
)的特征,我们还为整个句子生成特征。这有时也称为CLS token
。
句子特征的细节
在CLS token
的稀疏特征是标记(token
)中所有稀疏特征的总和。密集特征要么是词向量的和/平均值(在spaCy的情况下),要么是整个文本的语境化表示(在huggingface模型的情况下)。
请注意,您可以完全自由地使用自定义特征化工具添加自己的组件。作为一个例子,有一个社区维护的项目叫做rasa-nlu-examples,它有许多非英语语言的实验特性化工具。它并没有得到Rasa的官方支持,但是它可以帮助很多用户,因为它拥有超过275种语言。
一旦我们为所有标记和整个句子生成了特征,我们就可以将其传递给意图分类模型。我们建议使用Rasa的DIET模型,它可以处理意图分类和实体提取。它还能够从标记和句子特征中学习。
DIET细节
我们应该理解DIET算法是特殊的。过去,Rasa所承载的大多数算法要么是实体检测,要么是意图分类,它们并没有同时进行。这通常也意味着意向分类模型只关注管道的句子特征,而忽略了token特征。
即使DIET能够学会如何检测实体,我们也不一定推荐对每一种实体都使用它。例如,遵循结构化模式的实体(如电话号码)实际上不需要算法来检测它们。你可以用RegexEntityExtractor来处理它。
这就是为什么管道中有多个实体提取程序的常见原因。
现在我们已经大概了解NLU管道中不同类型的组件,我们可以继续解释这些组件如何相互共享信息。
Rasa管道中的组件相互依赖,所以它们是如何相互作用的。为了理解这是如何工作的,可以拆解一个config.yml
文件。
NLU管道是一系列组件。这些组件按照在管道中列出的顺序进行训练和处理。这意味着管道配置可以被认为是数据需要通过的一系列线性步骤。
每当用户与助手交谈时,Rasa都会通过一个Message
对象在内部跟踪话语的状态。此对象由管道中的每个步骤处理。下图概述了处理消息时发生的情况。
在这个图表中有几点需要指出:
Token
对象表示。sparse_features
和dense_features
,以便进行预测。处理完成后,它将把意图预测附加到消息对象。每次消息通过管道步骤时,消息对象都将获得新信息。这也意味着,如果要向消息中添加信息,可以继续向管道中添加步骤。这也是为什么可以附加额外的实体提取模型。
如您所见,管道中的每一步都可以向消息中添加信息。这意味着您可以添加多个实体提取步骤,并且可以并行地将实体添加到消息中。
自己检查消息对象
如果您自己对查看消息状态感兴趣,可以通过下面的代码检查模型的输出。
from rasa.cli.utils import get_validated_path
from rasa.model import get_model, get_model_subdirectories
from rasa.core.interpreter import RasaNLUInterpreter
from rasa.shared.nlu.training_data.message import Message
def load_interpreter(model_dir, model):
path_str = str(pathlib.Path(model_dir) / model)
model = get_validated_path(path_str, "model")
model_path = get_model(model)
_, nlu_model = get_model_subdirectories(model_path)
return RasaNLUInterpreter(nlu_model)
# Loads the model
mod = load_interpreter(model_dir, model)
# Parses new text
msg = Message({TEXT: text})
for p in interpreter.interpreter.pipeline:
p.process(msg)
print(msg.as_dict())
通过NLU管道,我们可以检测意图和实体。但这条管道并不能预测对话中的下一步行动。这就是策略管道的目的。策略利用NLU的预测以及目前为止的对话状态来预测下一步要采取什么行动。
如果您对这些策略如何生成操作感兴趣,您可能会喜欢我们在这里就这个主题撰写的博客文章。
在这篇博文中,我们回顾了Rasa NLU管道中的组件是如何相互作用的。了解组件在管道中如何交互是很好的,因为它将帮助您确定哪些组件与助手相关。
同样重要的是要理解您可以完全定制管道。如果您不需要组件,您可以删除它们;如果您想使用自己的工具,您甚至可以编写自己的组件。如果您使用的是非英语语言,并且希望使用熟悉的自定义语言工具,我们建议您查看rasa-nlu-examples库。该存储库有许多分词器、特性化器和模型,您可以自由地从中获得灵感,用于自己的项目。