Adline125's Blog

NLP Engineer, Google Developers Expert

0%

Rasa NLU DIET Classifier解析

本文是对著名对话机器人开源框架Rasa NLU classifier中最受欢迎的DIET Classifier的解析。Rasa是一套开源机器学习框架,用于构建基于上下文的AI小助手和聊天机器人。Rasa有两个主要模块:Rasa NLU 用于对用户消息内容的语义理解;Rasa Core 用于对话管理(Dialogue management)。本文主要针对Rasa NLU classifier 中的DIET Classifier做详细的说明。

本文更多关注算法,主要内容如下:

  • Rasa NLU Classifier架构
  • 主流技术支持情况

DIET Classifier架构

321

模型支持说明

DIET支持的Huggingface模型类型如下表:

模型类型 模型名称 默认加载的预训练模型
BERT bert rasa/LaBSE ( bert-base-uncased )
GPT gpt openai-gpt
GPT2 gpt2 gpt2
XLNet xlnet xlnet-base-cased
DistilBERT distilbert distilbert-base-uncased
RoBERTa roberta roberta-base

对在HuggingFace 中上传的所有预训练模型(Huggingface模型列表),Rasa DIET可以支持满足以下条件的所有模型:

点击Huggingface模型列表->选中一个模型->点击进入模型页面->点击Files and version

  • 检查 config.json 中的 model_type 是否列在上表的 模型名称 列中
  • 检查文件 tf_model.h5 是否存在
  • 模型使用默认tokenizer, config.json 中不包含支持自定义的 tokenizer_class

对满足上述条件的模型,通过2.1.3.3中描述的方式可开箱即用。

DIET支持Huggingface的配置样例

在Rasa2.0中,若想在DIET架构中使用Huggingface提供的预训练模型,除在rasa的config文件中指定使用DIETClassifier外,还需要配合使用对应的模块:

  1. HFTransformersNLP

主要参数:model_name: 预训练模型config.json 中的 model_type的值

​ model_weights: Huggingface模型列表提供的预训练模型名称

  1. LanguageModelTokenizer:确保训练数据token对应的token_id与预训练模型的token_id保持一致
  2. LanguageModelFeaturizer:生成经预训练模型转换后的特征向量,做为架构后续模块的输入。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
language: en
pipeline:
- name: HFTransformersNLP
model_weights: "rasa/LaBSE"
model_name: "bert"
- name: LanguageModelTokenizer
- name: LanguageModelFeaturizer
- name: DIETClassifier
epochs: 20
num_transformer_layers: 2
transfomer_size: 256
use_masked_language_model: True
drop_rate: 0.25
weight_sparsity: 0.7
batch_size: [64, 256]
embedding_dimension: 100
hidden_layer_sizes:
text: [512, 128]
  • DIET样例代码包位置:examples/hf_demo
  • DIET样例代码调用方式:项目根目录/main.py
  • 涉及的源码改动:

如按 ‘样例代码调用方式’ 直接跑报错... set from_pt=true, 请修改: 项目根目录/rasa/nlu/utils/hugging_face/hf_transformers.py: class HFTransformersNLP中的def _load_model_instance中

1
self.model = model_class_dict[self.model_name].from_pretrained(self.model_weights, cache_dir=self.cache_dir)

改为

1
self.model = model_class_dict[self.model_name].from_pretrained(self.model_weights, cache_dir=self.cache_dir, from_pt=True)

DIET核心代码解析

rasa.nlu.model.Trainer.train:遍历pipeline所有components,对每个component调用component.train方法完成训练。在component遍历到DIETClassifier之前,HFTransformersNLP等组件已经提取好了DIETClassifier训练需要的特征。遍历至DIETClassifier后,DIETClassifier开始利用已经提取好的特征进入训练。

rasa.nlu.classifiers.DIETClassifier.train: 该方法主要完成三件事:

  • 语料准备:通过DIETClassifier类中的方法preprocess_train_data,将训练数据和之前提取的特征整理成符合RasaModelData格式的model_data。RasaModelData格式为。。。。。之后将整理好的model_data按batch_size整理成data_generator供batch训练用。

  • 指定模型:将DIETClassifier类的成员self.model通过初始化DIET类完成指定DIET模型训练。

    • DIET模型类继承自TransformerRasaModel类:自定义了

    • TransformerRasaModel继承自RasaModel:自定义了。。。 要求实现。。。

    • RasaModel继承自TmpKerasModel:通过重写tf.keras.Model中的train_step(), test_step(), predict_step(), save()和load()方法,实现自定义的Rasa模型.

      • train_step()使用自定义的batch_loss并对该loss做了正则化。batch_loss需由其子类实现。
      • predict_step()使用自定义的batch_predict()。需由其子类实现。
      • save()只使用tf.keras.Model.save_weights()。
      • load()生成模型结构后加载weights.
    • TmpKerasModel继承自tf.keras.models.Model:重写了tf.keras.models.Model的fit方法来使用自定义的数据适配器。将数据转写成CustomDataHandler后由其处理迭代 epoch 级别的 tf.data.Iterator 对象。

  • 训练