当前位置: 首页 > 工具软件 > nn-core > 使用案例 >

Rasa教程系列-Core-5-Policies

宿淳
2023-12-01

Configuring Policies

rasa.core.policies.Policy决定了对话中每一步选择哪个action。有不同的策略可供选择,可以在一个rasa.core.agent.Agent中包含多个策略。对于每个用户消息,agent最多可以预测10个后续action。可以将环境变量max_number_of_prediction设置为所需的最大预测数,从而更改该值。

项目的config.yml文件接受一个策略密钥(policies key), 可以使用该密钥自定义策略。在下面的示例中,最后两行说明如何使用自定义策略类并向其传递参数。

policies:
  - name: "KerasPolicy"
    featurizer:
    - name: MaxHistoryTrackerFeaturizer
      max_history: 5
      state_featurizer:
        - name: BinarySingleStateFeaturizer
  - name: "MemoizationPolicy"
    max_history: 5
  - name: "FallbackPolicy"
    nlu_threshold: 0.4
    core_threshold: 0.3
    fallback_action_name: "my_fallback_action"
  - name: "path.to.your.policy.class"
    arg1: "..."

Max History

Rasa Core的策略的一个重要超参数是max_history。这控制了模型查看多少历史对话以决定下一步采取什么action。可以通过在策略配置yaml文件中将值传递给策略的Featurizer来设置max_history
注意:只有MaxHistoryTrackerFeaturizer使用最大历史,而FullDialogueTrackerFeaturizer总是查看完整的历史对话。详细信息请参见对话的特征化

例如,假设有一个描述非主题用户消息的out_of_scope意图。如果你的机器人连续多次看到这个意图,你可能想告诉用户你可以帮助他们做什么。你的story可能是这样的:

* out_of_scope
   - utter_default
* out_of_scope
   - utter_default
* out_of_scope
   - utter_help_message

要让Rasa Core学习这个模式,max_history必须至少为4。如果增加max_history,模型将变得更大,训练将花费更长的时间。如果有一些信息会影响到很遥远的未来对话,应该把它存储为一个槽位。槽信息总是为每个featurizer可用。

Data Augmentation

训练一个模型时,默认情况下,Rasa Core 将通过随机地将story粘在一起来创建更长的stories。这是因为如果你有如下的stories:

# thanks
* thankyou
   - utter_youarewelcome

# bye
* goodbye
   - utter_goodbye

实际上,我们希望教会策略忽略不相关的历史对话,并且无论之前发生了什么,都使用相同的action进行响应。

可以使用标记--augmentation更改此行为。它允许设置augmentation_factoraugmentation_factor确定在训练期间对多少个增强的story进行二次采样(subsampled)。增强的 stories 在训练前会被二次抽样,因为它们的数量很快就会变得非常大,需要限制它。采样的stories 数量是augmentation_factor x10。默认情况下,增强因子设置为20,即最多为200个增强的结果stories。

--augmentation 0将禁用所有增强行为。基于记忆的策略不受增强的影响(与augmentation_factor无关),并且将自动忽略所有增强的stories。

Action Selection

在每一次循环中,在配置中定义的每个策略都将以一定的置信度预测下一个action。关于每个策略如何决策的更多信息,请阅读下面的策略描述。机器人的下一个action由预测置信度最高的策略决定。

当两个策略以相同置信度进行预测时(例如,记忆和映射策略总是以0或1的置信度进行预测),将考虑策略的优先级。Rasa策略有默认的优先级设置,以确保在相同情况下得到预期的结果。它们看起来是这样的,越高的数字优先级越高:

5. FormPolicy
4. FallbackPolicy 和 TwoStageFallbackPolicy
3. MemoizationPolicy 和 AugmentedMemoizationPolicy
2. MappingPolicy
1. EmbeddingPolicy, KerasPolicy, 和 SklearnPolicy

这个优先级层次结构可以确保,比如,如果有一个带有映射操作的意图,但是NLU的置信度没有超过nlu_threshold,机器人仍然会退回(fall back)。通常,不建议在每个优先级级别上有多个策略, 而同一优先级上的某些策略,例如两个回退策略,严格来说不能同时使用。

如果创建自己的策略,请将这些优先级用作确定策略优先级的指南。如果自定义的策略是机器学习策略,那么它很可能具有优先级1,与Rasa机器学习策略相同。

注意:
所有策略优先级都可以通过配置中的priority:参数进行配置,但是官方不建议在特定情况下(例如自定义策略)更改它们。这样做可能会导致意外和出乎意料的机器人行为。

Keras Policy

KerasPolicy使用Keras中实现的神经网络来选择下一步action。默认的体系结构基于LSTM,但是我们可以重写KerasPolicy.model_architecture方法从而实现自己的体系结构。

def model_architecture(
    self, input_shape: Tuple[int, int], output_shape: Tuple[int, Optional[int]]
) -> tf.keras.models.Sequential:
    """Build a keras model and return a compiled model."""

    from tensorflow.keras.models import Sequential
    from tensorflow.keras.layers import (
        Masking,
        LSTM,
        Dense,
        TimeDistributed,
        Activation,
    )

    # Build Model
    model = Sequential()

    # the shape of the y vector of the labels,
    # determines which output from rnn will be used
    # to calculate the loss
    if len(output_shape) == 1:
        # y is (num examples, num features) so
        # only the last output from the rnn is used to
        # calculate the loss
        model.add(Masking(mask_value=-1, input_shape=input_shape))
        model.add(LSTM(self.rnn_size, dropout=0.2))
        model.add(Dense(input_dim=self.rnn_size, units=output_shape[-1]))
    elif len(output_shape) == 2:
        # y is (num examples, max_dialogue_len, num features) so
        # all the outputs from the rnn are used to
        # calculate the loss, therefore a sequence is returned and
        # time distributed layer is used

        # the first value in input_shape is max dialogue_len,
        # it is set to None, to allow dynamic_rnn creation
        # during prediction
        model.add(Masking(mask_value=-1, input_shape=(None, input_shape[1])))
        model.add(LSTM(self.rnn_size, return_sequences=True, dropout=0.2))
        model.add(TimeDistributed(Dense(units=output_shape[-1])))
    else:
        raise ValueError(
            "Cannot construct the model because"
            "length of output_shape = {} "
            "should be 1 or 2."
            "".format(len(output_shape))
        )

    model.add(Activation("softmax"))

    model.compile(
        loss="categorical_crossentropy", optimizer="rmsprop", metrics=["accuracy"]
    )

    if obtain_verbosity() > 0:
        model.summary()

    return model

训练如下:

def train(
    self,
    training_trackers: List[DialogueStateTracker],
    domain: Domain,
    **kwargs: Any,
) -> None:

    # set numpy random seed
    np.random.seed(self.random_seed)

    training_data = self.featurize_for_training(training_trackers, domain, **kwargs)
    # noinspection PyPep8Naming
    shuffled_X, shuffled_y = training_data.shuffled_X_y()

    self.graph = tf.Graph()
    with self.graph.as_default():
        # set random seed in tf
        tf.set_random_seed(self.random_seed)
        self.session = tf.compat.v1.Session(config=self._tf_config)

        with self.session.as_default():
            if self.model is None:
                self.model = self.model_architecture(
                    shuffled_X.shape[1:], shuffled_y.shape[1:]
                )

            logger.info(
                "Fitting model with {} total samples and a "
                "validation split of {}"
                "".format(training_data.num_examples(), self.validation_split)
            )

            # filter out kwargs that cannot be passed to fit
            self._train_params = self._get_valid_params(
                self.model.fit, **self._train_params
            )

            self.model.fit(
                shuffled_X,
                shuffled_y,
                epochs=self.epochs,
                batch_size=self.batch_size,
                shuffle=False,
                verbose=obtain_verbosity(),
                **self._train_params,
            )
            # the default parameter for epochs in keras fit is 1
            self.current_epoch = self.defaults.get("epochs", 1)
            logger.info("Done fitting keras policy model")

可以通过覆盖这些方法来实现自己的模型,或者使用预定义的keras模型初始化KerasPolicy。为了对相同的输入获得可重复的训练结果,可以将KerasPolicyrandom_seed属性设置为任意整数。

Embedding Policy

Transformer Embedding Dialogue Policy (TEDP),Recurrent Embedding Dialogue Policy的衍生版(REDP)
该策略有一个预定义的框架,包括如下步骤:
(1)将用户输入(用户意图和实体)、之前的系统action、槽位和每个时间步长内的激活形式拼接成输入向量再输入到pre-transformer embedding层;
(2)输入到transformer;
(3)在transformer的输出上加一个稠密层,以获得每个时间步长的对话嵌入;
(4)使用一个稠密层以获取每个时间步长内系统action的嵌入;
(5)计算对话嵌入与系统action嵌入之间的相似度。这一步是基于StarSpace中的想法。

建议使用的featurizer是state_featurizer=LabelTokenizerSingleStateFeaturizer(...),可以进一步查看Featurization of Conversations中的细节。

Configuration:
可以将配置参数作为参数传递给策略配置文件中的EmbeddingPolicy。注意:需要向EmbeddingPolicy传递适当数量的epoch,否则策略将只训练1个epoch。

该算法也有一些超参数可以设置,这里就不一一介绍了,主要包括神经网络架构参数、训练参数、嵌入参数、正则化参数和训练过程中精度计算相关的参数。
注意:
(1)该策略下的max_history默认情况下是None,这意味着此时该策略将使用FullDialogueTrackerFeaturizer。建议将max_history设置为某个有限的值,以便使用MaxHistoryTrackerFeaturizer进行更快的训练。建议增加batch_sizeMaxHistoryTrackerFeaturizer,比如batch_size: [32,64]。
(2)当evaluate_on_num_examples非0,随机的样本将被分层分割,作为hold out验证集使用,因此他们将被排除在训练数据之外。如果数据集中包含大量独特的对话回合的例子,建议将其设置为0。
(3)Droprate应该在0和1之间,例如,Droprate =0.1将drop out 10%的输入单元。
(4)对于余弦相似度mu_posmu_neg应该在-1和1之间。
可以在策略配置文件中指定这些参数。默认值在embeddingpolicy.default中定义:

defaults = {
    # nn architecture
    # a list of hidden layers sizes before user embed layer
    # number of hidden layers is equal to the length of this list
    "hidden_layers_sizes_pre_dial": [],
    # a list of hidden layers sizes before bot embed layer
    # number of hidden layers is equal to the length of this list
    "hidden_layers_sizes_bot": [],
    # number of units in transformer
    "transformer_size": 128,
    # number of transformer layers
    "num_transformer_layers": 1,
    # type of positional encoding in transformer
    "pos_encoding": "timing",  # string 'timing' or 'emb'
    # max sequence length if pos_encoding='emb'
    "max_seq_length": 256,
    # number of attention heads in transformer
    "num_heads": 4,
    # training parameters
    # initial and final batch sizes:
    # batch size will be linearly increased for each epoch
    "batch_size": [8, 32],
    # how to create batches
    "batch_strategy": "balanced",  # string 'sequence' or 'balanced'
    # number of epochs
    "epochs": 1,
    # set random seed to any int to get reproducible results
    "random_seed": None,
    # embedding parameters
    # dimension size of embedding vectors
    "embed_dim": 20,
    # the type of the similarity
    "num_neg": 20,
    # flag if minimize only maximum similarity over incorrect labels
    "similarity_type": "auto",  # string 'auto' or 'cosine' or 'inner'
    # the type of the loss function
    "loss_type": "softmax",  # string 'softmax' or 'margin'
    # how similar the algorithm should try
    # to make embedding vectors for correct labels
    "mu_pos": 0.8,  # should be 0.0 < ... < 1.0 for 'cosine'
    # maximum negative similarity for incorrect labels
    "mu_neg": -0.2,  # should be -1.0 < ... < 1.0 for 'cosine'
    # the number of incorrect labels, the algorithm will minimize
    # their similarity to the user input during training
    "use_max_sim_neg": True,  # flag which loss function to use
    # scale loss inverse proportionally to confidence of correct prediction
    "scale_loss": True,
    # regularization
    # the scale of L2 regularization
    "C2": 0.001,
    # the scale of how important is to minimize the maximum similarity
    # between embeddings of different labels
    "C_emb": 0.8,
    # dropout rate for dial nn
    "droprate_a": 0.1,
    # dropout rate for bot nn
    "droprate_b": 0.0,
    # visualization of accuracy
    # how often calculate validation accuracy
    "evaluate_every_num_epochs": 20,  # small values may hurt performance
    # how many examples to use for hold out validation set
    "evaluate_on_num_examples": 0,  # large values may hurt performance
}

Mapping Policy

MappingPolicy可用于直接将意图映射到action。映射通过给意图的属性分配一个触发器(triggers),例如:

intents:
 - ask_is_bot:
     triggers: action_is_bot

一个意图最多只能映射到一个action。一旦收到触发意图的消息,bot将运行映射的action。然后,它将监听下一条消息。对于下一用户消息,将恢复正常的预测。

如果不希望意图-action映射影响对话的历史记录,则映射的action必须返回UserUtteranceReverted()事件。这将从对话历史记录中删除用户的最新消息及其后发生的任何事件。这意味着不应该在stories中包含意图-action交互。

例如,如果用户在流程进行到一半时问“Are you a bot?”, 你可能想要在不影响下一次action预测的情况下回答这个题。一个被触发的自定义action可以做任何事情,但这里有一个简单的例子,调度一个机器人的utterance,然后恢复互动:

class ActionIsBot(Action):
"""Revertible mapped action for utter_is_bot"""

def name(self):
    return "action_is_bot"

def run(self, dispatcher, tracker, domain):
    dispatcher.utter_template(template="utter_is_bot")
    return [UserUtteranceReverted()]

注意:
(1)如果使用MappingPolicy直接预测机器人的utterances(例如,trigger:utter_{}),这些交互则必须出现在stories中,因为在这种情况下没有UserUtteranceReverted(),意图和映射的utterance将出现在对话历史中。
(2)MappingPolicy还负责执行默认动作action_backaction_restart来响应/back/restart。如果它不包括在策略示例中,这些意图将不起作用。

Memoization Policy

MemoizationPolicy只记录训练数据中的对话。如果训练数据中存在这样的对话,那么它将以confidence 1.0预测下一个action,否则它将以confidence 0.0预测没有任何action。

Augmented Memoization Policy

增强的MemoizationPolicy可以记住的训练stories最多max_history,就像MemoizationPolicy一样。此外,它还有一个遗忘机制,可以忘记会话历史中的某些步骤,并尝试在stories中找到与之匹配的简化历史。如果找到匹配项,它将使用置信度1.0预测下一个action,否则将使用置信度0.0预测None。

Fallback Policy

如果出现以下至少一种情况,则回退策略调用回退操作:
(1)意图识别的置信度低于nlu_threshold
(2)排名最高的意图与排名第二的意图之间的置信度差异小于二义性阈值ambiguity_threshold,即存在歧义。
(3)所有的对话策略都不能预测信心高于core_threshold的action。

Configuration:
阈值和回退操作可以在策略配置文件中作为FallbackPolicy的参数进行调整:

policies:
  - name: "FallbackPolicy"
    nlu_threshold: 0.3
    ambiguity_threshold: 0.1
    core_threshold: 0.3
    fallback_action_name: 'action_default_fallback'

其中,nlu_threshold表示接受NLU的预测的最小置信度;ambiguity_threshold表示最高意图的置信度必须超过排名第二的意图的置信度的最小值;core_threshold表示接受Rasa Core预测的action的最小置信度;fallback_action_name表示fallback action的名字,
如果意图或action的置信度低于相应的阈值,则调用该fallback action。

可以在代码中配置FallbackPolicy

from rasa.core.policies.fallback import FallbackPolicy
from rasa.core.policies.keras_policy import KerasPolicy
from rasa.core.agent import Agent

fallback = FallbackPolicy(fallback_action_name="action_default_fallback",
                          core_threshold=0.3,
                          nlu_threshold=0.3,
                          ambiguity_threshold=0.1)

agent = Agent("domain.yml", policies=[KerasPolicy(), fallback])

注意:
可以在配置中包含FallbackPolicyTwoStageFallbackPolicy,但不能两者都包含。

Two-Stage Fallback Policy

TwoStageFallbackPolicy用以在多个阶段处理低NLU置信度的情况,使用的方法是通过消除用户输入的歧义。
(1)如果NLU预测的置信度较低,或者不显著高于排名第二的预测,则要求用户确认意图的分类。

  • 如果他们确认了,story就会继续下去,就好像这个意图从一开始就被高度保密了一样。
  • 如果他们拒绝了,用户被要求重新陈述他们的信息。

(2)Rephrasing(改述)

  • 如果对重新改述的意图的分类是可靠的,则story将继续下去,就好像用户从一开始就有此意图一样。
  • 如果重新表达的意图没有被高度信任地分类,则要求用户确认分类的意图。

(3)Second affirmation(再确认)

  • 如果用户确认了意图,story就会继续下去,就好像用户从一开始就有这个意图一样。
  • 如果用户拒绝,则原始意图被分类为指定的deny_tion_intent_name,并触发最终的fallback action回退操作(例如,切换到人工)。

Configuration:
使用TwoStageFallbackPolicy时需要在策略配置文件中进行如下配置:

policies:
  - name: TwoStageFallbackPolicy
    nlu_threshold: 0.3
    ambiguity_threshold: 0.1
    core_threshold: 0.3
    fallback_core_action_name: "action_default_fallback"
    fallback_nlu_action_name: "action_default_fallback"
    deny_suggestion_intent_name: "out_of_scope"

其中nlu_thresholdambiguity_thresholdcore_threshold之前已经介绍过。fallback_core_action_name表示fallback action的名字,当Rasa Core 预测的action的置信度低于core_threshold,通过该名字调用 fallback action 。fallback_nlu_action_name 是当Rasa NLU 意图分类器识别结果低于nlu_threshold时调用的fallback action名字。当用户第二次拒绝时调用此操作。deny_suggestion_intent_name表示意图的名称,用于检测用户是否拒绝所建议的意图。

Form Policy

FormPolicyMemoizationPolicy的扩展,用以处理表单填写。。一旦调用了FormAction, FormPolicy将不断地预测FormAction,直到表单中所有需要的槽都被填满为止。更多相关信息,参考这里

 类似资料: