rasa

Rasa聊天机器人(二):训练及构建

本文只要介绍了基于Rasa Core及Rasa NLU构建聊天机器人。
代码详见:https://github.com/xiaoxiong74/rasa_chatbot

Introduction
这个聊天机器人demo是用开源NLU框架rasa-nlu完成意图识别与实体识别,用rasa-core完成对话管理和与对话生成。

本demo完成的对话主要有:
1: 办理套餐、查询话费和流量(会话场景1)
2:案件查询(会话场景2)
3:Q&A问答+闲聊(合并在unknow_intent的场景里)
本demo实现流程

demo主要参考了
rasa_chatbot_cn
_rasa_chatbot
WeatherBot
主要包版本
python: 3.6.8
rasa-nlu: 0.14.4
rasa-core: 0.13.2
rasa-core-sdk: 0.12.1
tensorflow 1.12.0
1
2
3
4
5
主要文件描述
data/rasa_dataset_training.json :nlu训练数据
configs/_config.yml 类文件:模型流程定义(language、pipeline等)。nlu_model_config.yml中的pipeline可自定义,这里由于数据量较少,用了开源的方法和词向量(total_word_feature_extractor.dat)。如果你的rasa_dataset_training.json上数据足够多,可以尝试使用nlu_embedding_config.yml(本demo使用)配置来训练nlu model.
mobile_domain.yml :各组件、动作的定义集合,其实就是特征
endpoint.yml 服务地址、会话存储地址(url)
data/mobile_edit_story.md :定义各种对话场景,会话流训练数据
bot.py :各种训练nul与 dialogue的方法
actions.py :负责执行自定义 Action (通常都是具体的业务动作,在本项目中通信业务查询、案件查询、闲聊或Q&A)
data/total_word_feature_extractor.dat : 一个训练好的中文特征数据(使用nlu_moel_config.yml配置训练时会用到)
data/news_12g_baidubaike_20g_novel_90g_embedding_64.bin :训练好的word2vec模型(train_nlu_wordvector:wordvector_config.yml中用到),可下载更大的训练好的模型,下载地址:连接 密码:9aza
Command
train nlu model 训练NLU模型(可选择其他的,如train-nlu-wordvector)
python bot.py train-nlu
1
test nlu model 测试NLU模型,主要是看意图是否识别准确,是否抽取到实体
python -m rasa_nlu.server –path models/nlu 启动NUL模型服务

curl -XPOST 192.168.109.232:5000/parse -d ‘{“q”:”我要查昨天下午的抢劫案”, “project”: “default”, “model”: “current”}’
1
2
3
train dialogue 训练会话流程(可选择其他的,如train-nlu-transformer)
python bot.py train-dialogue-keras
1
test dialogue -client端测试对话流程(开启core client服务)
python -m rasa_core_sdk.endpoint –actions actions &

python -m rasa_core.run –nlu default/current –core models/dialogue_keras –endpoints endpoints.yml

1
2
3
4
dialogue 交互式训练生成新的story(相当于自己构造对话场景数据。新的story可以append到之前训练使用的story中重新训练,重复此过程)
python -m rasa_core.train interactive -o models/dialogue_keras -d mobile_domain.yml -s data/mobile_edit_story.md –endpoints endpoints.yml 重头开始训练story,零启动
python -m rasa_core.train interactive –core models/dialogue_keras –nlu default/current –endpoints endpoints.yml 通过已有story模型训练(构造更多的story,一般用这种方法)
1
2
provide dialogue service -Service端:提供对话服务接口(channel(如web)接入时开启此服务)
python -m rasa_core_sdk.endpoint –actions actions &

python -m rasa_core.run –nlu default/current –core models/dialogue_keras –credentials credentials.yml –endpoints endpoints.yml 开启core服务(Service)
1
2
3
compare policy
python -m rasa_core.train compare -c keras_policy.yml embed_policy.yml -d mobile_domain.yml -s data/mobile_edit_story.md -o comparison_models/ –runs 3 –percentages 0 25 50 70
1
evaluate policy
python -m rasa_core.evaluate compare -s data/mobile_edit_story.md –core comparison_models/ -o comparison_results/
1
Some tips
批量生产nlu训练数据
训练数据的构造是非常费时的一件事,本demo data/rasa_dataset_training.json 是通过一些规则自动生成的,节省很多人力。

工具地址here,
具体用法可参考chatito_gen_nlu_data中的使用文档。
标注语料可参考标注工具rasa-nlu-trainer
UI界面接入
UI界面接入可参考 https://github.com/howl-anderson/WeatherBot_UI 直接更改相应的端口或ip即可使用。

启动方法:
1、启动NLU服务
2、启动dialogue service
3、启动web服务
多看官方文档 rasa_nlu、rasa_core
其中也有些坑,使用期间有任何问题,欢迎随时issue!

Q&A
ner_duckling 无法使用
从rasa_nlu=0.14.0 开始就不使用ner_duckling,详见changelog,仅保留ner_duckling_http。因自己启动ner_duckling_http
报错,故自己把ner_duckling的模块又重新添加到了rasa_nlu中。添加方法如下:

1、找到rasa_nul包的位置,我的是/root/anaconda3/envs/rasa/lib/python3.6/site-packages/rasa_nlu
2、在rasa_nlu/extractors(前置路径省略) 中添加duckling_extractor.py文件 直接复制粘贴:https://github.com/RasaHQ/rasa_nlu/blob/0.13.x/rasa_nlu/extractors/duckling_extractor.py
3、在rasa_nlu/registry.py 中注册duckling_extractor组件
导入方法: from rasa_nlu.extractors.duckling_extractor import DucklingExtractor
添加组件: 在组件列表component_classes 中加入 DucklingExtractor
train_dialogue_transformer训练报维度不匹配错误
在policy/attention_keras 中要求输入的特征是偶数个,即mobile_domain.yml的特征数据量,若报错删除一个或增加一个特征即可

train_nlu_wordvector报编码错误
因为rasa_nlu_gao中的word2vec模型使用的txt文本模型,我这里用的bin二进制模型,所以如果使用bin的二进制模型需要更改
rasa_nlu_gao中的源码。修改方法:

1、定位到site-packages/rasa_nlu_gao/featurizers/intent_featurizer_wordvector.py
2、定位到两处模型加载的地方 model = gensim.models.KeyedVectors.load_word2vec_format 将里面的binary 改为True即可
Some magical functions
rasa-nlu-gao新增了N多个个自定义组件,具体用法和说明请参考该作者的 rasa对话系统踩坑记,个人觉得对新入坑聊天机器人的童鞋很有帮助,感谢作者的贡献。简单使用方法如下:

首先需要下载rasa-nlu-gao
pip install rasa-nlu-gao
1
训练模型
python bot.py train-nlu-gao
1
测试使用模型
python -m rasa_nlu_gao.server -c config_embedding_bilstm.yml –path models/nlu_gao/
1
效果截图

 

 

————————————————
版权声明:本文为CSDN博主「Mr_不想起床」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42189083/article/details/88076128

rasa语义模型报错:”error”: “bad value(s) in fds_to_keep”

在测试模型的时报,训练模型没问题,但是在测试的时候出现问题

不要慌,这种问题是因为sklearn与rasa的框架不兼容导致的

 

这时候需要首先卸载sklearn:

pip uninstall scikit-learn

然后重新安装并指定版本

pip install scikit-learn==0.19.2

ok!问题解决
————————————————
版权声明:本文为CSDN博主「聪明的小k」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuanzhuanguo/article/details/105033105

rasa_nlu_chi 测试不成功 “error“: “y should be a 1d array, got an array of shape (1, 5) instead.

rasa_nlu_chi原始git链接:
https://github.com/crownpku/rasa_nlu_chi

rasa_nlu_chi实现博客链接:

实现过程中有问题解决方法的博客:
https://ptorch.com/news/243.html

大牛写的rasa-UI链接:
https://github.com/paschmann/rasa-ui
UI安装教程:
https://blog.csdn.net/u011244708/article/details/82924823?spm=1001.2014.3001.5501
UI与nlu_chi整合问题:
https://ask.csdn.net/questions/3370686

问题贴:
https://github.com/crownpku/Rasa_NLU_Chi/issues

训练Rasa NLU的模型

python -m rasa_nlu.train -c sample_configs/config_jieba_mitie_sklearn.yml –data data/examples/rasa/demo-rasa_zh.json –path models
1
启动rasa_nlu的后台服务:

python -m rasa_nlu.server -c sample_configs/config_jieba_mitie_sklearn.yml –path models
1
打开一个新的terminal,我们现在就可以使用curl命令获取结果了, 尝试下面命令均不成功:

curl -XPOST localhost:5000/parse -d ‘{“q”:”我发烧了该吃什么药?”, “project”: “rasa_nlu_test”, “model”: “models\default\model_20210617-142700”}’ | python -mjson.tool
1
curl -XPOST localhost:5000/parse -d ‘{“q”:”我发烧了该吃什么药?”, “project”: “”, “model”: “models\default\model_20210617-142700”}’ | python -mjson.tool
1
curl -XPOST localhost:5000/parse -d ‘{“q”:”我发烧了该吃什么药?”, “model”: “models\default\model_20210617-142700”}’ | python -mjson.tool
1
curl -XPOST localhost:5000/parse -d ‘{“q”:”我发烧了该吃什么药?”}’ | python -mjson.tool
1
curl -XPOST localhost:5000/parse -d ‘{“q”:“我发烧了该吃什么药?”, “model”: “models\default\model_20210617-111551”}’ | python -mjson.tool

E:\1rasa\code\Rasa_NLU_Chi\Rasa_NLU_Chi-master\models\default\model_20210617-111551

测试命令始终报错

更换测试方式:
打开浏览器,地址中输入

http://localhost:5000/parse?q=你好
1
报错:

尝试scikit-learn降级:
https://github.com/RasaHQ/rasa/issues/1436

报错:

rasa 2.5.0 requires networkx<2.6,>=2.4, but you have networkx 2.1 which is incompatible.
rasa 2.5.0 requires packaging<21.0,>=20.0, but you have packaging 17.1 which is incompatible.
rasa 2.5.0 requires pykwalify<1.9,>=1.7, but you have pykwalify 1.6.0 which is incompatible.
rasa 2.5.0 requires scikit-learn<0.25,>=0.22, but
1
2
3
4
重新装这四个的最小匹配版本

rasa-nlu 0.14.4

rasa 2.5.0 requires cloudpickle<1.7,>=1.2, but you have cloudpickle 0.6.1 which is incompatible.
rasa 2.5.0 requires jsonschema<3.3,>=3.2, but you have jsonschema 2.6.0 which is incompatible.
rasa 2.5.0 requires matplotlib<3.4,>=3.1, but you have matplotlib 2.2.5 which is incompatible.
rasa 2.5.0 requires packaging<21.0,>=20.0, but you have packaging 18.0 which is incompatible.
rasa 2.5.0 requires ruamel.yaml<0.17.0,>=0.16.5, but you have ruamel-yaml 0.15.100 which is incompatible.
rasa 2.5.0 requires scikit-learn<0.25,>=0.22,

问题贴:按照教程发送请求后,返回”error”: “y should be a 1d array, got an array of shape (1, 5) instead.”

实测成功!!热泪!!

找到sklearn_intent_classifier.py
C:\Users\Administrator\Desktop\Rasa_NLU_Chi\rasa_nlu\classifiers\sklearn_intent_classifier.py
return self.le.inverse_transform(y) 修改为 return
self.le.inverse_transform(np.squeeze(y))

 

 

问题:curl测试仍然不成功
尝试方法1:

可以参考train.py ,def create_argument_parser():
parser.add_argument(’–project’, python -m rasa_nlu.train -c
sample_configs/config_jieba_mitie_sklearn.yml –data
data/examples/rasa/demo-rasa_zh.json –path rasa_nlu_test –project
rasa_nlu_test
————————————————
版权声明:本文为CSDN博主「Silber 甜」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42639575/article/details/117988319

Rasa NLU for Chinese, a fork from RasaHQ/rasa_nlu

Please refer to newest instructions at official Rasa NLU document

中文Blog

 

Files you should have:

  • data/total_word_feature_extractor_zh.dat

Trained from Chinese corpus by MITIE wordrep tools (takes 2-3 days for training)

For training, please build the MITIE Wordrep Tool. Note that Chinese corpus should be tokenized first before feeding into the tool for training. Close-domain corpus that best matches user case works best.

A trained model from Chinese Wikipedia Dump and Baidu Baike can be downloaded from 中文Blog.

  • data/examples/rasa/demo-rasa_zh.json

Should add as much examples as possible.

Usage:

  1. Clone this project, and run
python setup.py install
  1. Modify configuration.

    Currently for Chinese we have two pipelines:

    Use MITIE+Jieba (sample_configs/config_jieba_mitie.yml):

language: "zh"

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_classifier_mitie"

RECOMMENDED: Use MITIE+Jieba+sklearn (sample_configs/config_jieba_mitie_sklearn.yml):

language: "zh"

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"
  1. (Optional) Use Jieba User Defined Dictionary or Switch Jieba Default Dictionoary:

    You can put in file path or directory path as the “user_dicts” value. (sample_configs/config_jieba_mitie_sklearn_plus_dict_path.yml)

language: "zh"

pipeline:
- name: "nlp_mitie"
  model: "data/total_word_feature_extractor_zh.dat"
- name: "tokenizer_jieba"
  default_dict: "./default_dict.big"
  user_dicts: "./jieba_userdict"
#  user_dicts: "./jieba_userdict/jieba_userdict.txt"
- name: "ner_mitie"
- name: "ner_synonyms"
- name: "intent_entity_featurizer_regex"
- name: "intent_featurizer_mitie"
- name: "intent_classifier_sklearn"
  1. Train model by running:

    If you specify your project name in configure file, this will save your model at /models/your_project_name.

    Otherwise, your model will be saved at /models/default

python -m rasa_nlu.train -c sample_configs/config_jieba_mitie_sklearn.yml --data data/examples/rasa/demo-rasa_zh.json --path models
  1. Run the rasa_nlu server:
python -m rasa_nlu.server -c sample_configs/config_jieba_mitie_sklearn.yml --path models
  1. Open a new terminal and now you can curl results from the server, for example:
$ curl -XPOST localhost:5000/parse -d '{"q":"我发烧了该吃什么药?", "project": "rasa_nlu_test", "model": "model_20170921-170911"}' | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   652    0   552  100   100    157     28  0:00:03  0:00:03 --:--:--   157
{
    "entities": [
        {
            "end": 3,
            "entity": "disease",
            "extractor": "ner_mitie",
            "start": 1,
            "value": "发烧"
        }
    ],
    "intent": {
        "confidence": 0.5397186422631861,
        "name": "medical"
    },
    "intent_ranking": [
        {
            "confidence": 0.5397186422631861,
            "name": "medical"
        },
        {
            "confidence": 0.16206323981749196,
            "name": "restaurant_search"
        },
        {
            "confidence": 0.1212448457737397,
            "name": "affirm"
        },
        {
            "confidence": 0.10333600028547868,
            "name": "goodbye"
        },
        {
            "confidence": 0.07363727186010374,
            "name": "greet"
        }
    ],
    "text": "我发烧了该吃什么药?"
}

用Rasa NLU构建自己的中文NLU系统

代码在 https://github.com/crownpku/rasa_nlu_chi

自然语言理解(NLU)系统是问答系统、聊天机器人等更高级应用的基石。基本的NLU工具,包括实体识别和意图识别两个任务。

已有的NLU工具,大多是以服务的方式,通过调用远程http的restful API来对目标语句进行解析完成上述两个任务。这样的工具有Google的API.ai, Microsoft的Luis.ai, Facebook的Wit.ai等。刚刚被百度收购的Kitt.ai除了百度拿出来秀的语音唤醒之外,其实也有一大部分工作是在NLU上面,他们很有启发性的的Chatflow就包含了一个自己的NLU引擎。

(话说,现在.ai的域名都好贵呢…其实是安圭拉的国家域名,这个小岛就这么火了…)

以上这些工具,一边为用户提供NLU的服务,一边也通过用户自己上传的大量标注和非标注数据不断训练和改进自己的模型。而对于数据敏感的用户来说,开源的NLU工具如Rasa.ai就为我们打开了另一条路。更加重要的是,这样的开源工具可以本地部署,自己针对实际需求训练和调整模型,据说对一些特定领域的需求效果要比那些通用的在线NLU服务还要好很多。

我们在这里就简单介绍使用Rasa NLU构建一个本地部署的特定领域的中文NLU系统。

Rasa NLU本身是只支持英文和德文的。中文因为其特殊性需要加入特定的tokenizer作为整个流水线的一部分。我加入了jieba作为我们中文的tokenizer,这个适用于中文的rasa NLU的版本代码在github上。

语料获取及预处理

Rasa NLU的实体识别和意图识别的任务,需要一个训练好的MITIE的模型。这个MITIE模型是非监督训练得到的,类似于word2vec中的word embedding。

要训练这个MITIE模型,我们需要一个规模比较大的中文语料。最好的方法是用对应自己需求的语料,比如做金融的chatbot就多去爬取些财经新闻,做医疗的chatbot就多获取些医疗相关文章。

我使用的是awesome-chinese-nlp中列出的中文wikipedia dump和百度百科语料。其中关于wikipedia dump的处理可以参考这篇帖子

仅仅获取语料还不够,因为MITIE模型训练的输入是以词为单位的。所以要先进行分词,我们使用结巴分词。

安装结巴分词:

$ pip install jieba

将一个语料文件分词,以空格为分隔符:

$ python -m jieba -d " " ./test > ./test_cut

MITIE模型训练

我们把所有分好词的语料文件放在同一个文件路径下。接下来我们要训练MITIE模型。

首先将MITIE clone下来:

$ git clone https://github.com/mit-nlp/MITIE.git

我们要使用的只是MITIE其中wordrep这一个工具。我们先build它。

$ cd MITIE/tools/wordrep
$ mkdir build
$ cd build
$ cmake ..
$ cmake --build . --config Release

然后训练模型,得到total_word_feature_extractor.dat。注意这一步训练会耗费几十GB的内存,大概需要两到三天的时间。。。

$ ./wordrep -e /path/to/your/folder_of_cutted_text_files

我用中文wikipedia和百度百科语料生成了一个total_word_feature_extractor_chi.dat,分享如下。

链接:https://pan.baidu.com/s/1kNENvlHLYWZIddmtWJ7Pdg 密码:p4vx

对于一些比较general的NLU使用场景,这个应该是够用了。

构建rasa_nlu语料和模型

  • 将rasa_nlu_chi clone下来并安装:
$ git clone https://github.com/crownpku/rasa_nlu_chi.git
$ cd rasa_nlu_chi
$ python setup.py install
  • 构建尽可能多的示例数据来做意图识别和实体识别的训练数据:

data/examples/rasa/demo-rasa_zh.json

格式是json,例子如下。’start’和’end’是实体对应在’text’中的起止index。

     {
        "text": "找个吃拉面的店",
        "intent": "restaurant_search",
        "entities": [
          {
            "start": 3,
            "end": 5,
            "value": "拉面",
            "entity": "food"
          }
        ]
      },
      {
        "text": "这附近哪里有吃麻辣烫的地方",
        "intent": "restaurant_search",
        "entities": [
          {
            "start": 7,
            "end": 10,
            "value": "麻辣烫",
            "entity": "food"
          }
        ]
      },
      {
        "text": "附近有什么好吃的地方吗",
        "intent": "restaurant_search",
        "entities": []
      },
      {
        "text": "肚子饿了,推荐一家吃放的地儿呗",
        "intent": "restaurant_search",
        "entities": []
      }

这里有个小bug,就是这个entity一定要刚刚好是text被jieba分词后其中的一个词。如果jieba分词的结果中分错了你设定的entity这个词就会报错。所以写这个示例数据的时候,要参考jieba对text的分词结果来写。

上述bug已解决。

  • 修改pipeline的设置

对于中文我们现在有两种pipeline:

使用 MITIE+Jieba:

[“nlp_mitie”, “tokenizer_jieba”, “ner_mitie”, “ner_synonyms”, “intent_classifier_mitie”]

这种方式训练比较慢,效果也不是很好,最后出现的intent也没有分数排序。

我们推荐使用下面的pipeline:

MITIE+Jieba+sklearn (sample_configs/config_jieba_mitie_sklearn.json):

[“nlp_mitie”, “tokenizer_jieba”, “ner_mitie”, “ner_synonyms”, “intent_featurizer_mitie”, “intent_classifier_sklearn”]

这里也可以看到Rasa NLU的工作流程。”nlp_mitie”初始化MITIE,”tokenizer_jieba”用jieba来做分词,”ner_mitie”和”ner_synonyms”做实体识别,”intent_featurizer_mitie”为意图识别做特征提取,”intent_classifier_sklearn”使用sklearn做意图识别的分类。

2017.11.16更新: 关于加入jieba自定义词典,暂时没有找到非常优雅的做法。现在的版本,需要用户把jieba自定义词典放到rasa_nlu_chi/jieba_userdict/下面。系统在训练和预测时都会自动寻找并导入jieba分词。

  • 训练Rasa NLU的模型
$ python -m rasa_nlu.train -c sample_configs/config_jieba_mitie_sklearn.json

这样就会生成一个类似model_20170714-195758的文件在 /models/your_project_name 的文件夹里。

如果config文件中没有project_name,模型会存储在默认的 /models/default 文件夹下。

搭建本地rasa_nlu服务

  • 启动rasa_nlu的后台服务:
python -m rasa_nlu.server -c sample_configs/config_jieba_mitie_sklearn.json
  • 打开一个新的terminal,我们现在就可以使用curl命令获取结果了, 举个例子:
$ curl -XPOST localhost:5000/parse -d '{"q":"我发烧了该吃什么药?", "project": "rasa_nlu_test", "model": "model_20170921-170911"}' | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   652    0   552  100   100    157     28  0:00:03  0:00:03 --:--:--   157
{
    "entities": [
        {
            "end": 3,
            "entity": "disease",
            "extractor": "ner_mitie",
            "start": 1,
            "value": "发烧"
        }
    ],
    "intent": {
        "confidence": 0.5397186422631861,
        "name": "medical"
    },
    "intent_ranking": [
        {
            "confidence": 0.5397186422631861,
            "name": "medical"
        },
        {
            "confidence": 0.16206323981749196,
            "name": "restaurant_search"
        },
        {
            "confidence": 0.1212448457737397,
            "name": "affirm"
        },
        {
            "confidence": 0.10333600028547868,
            "name": "goodbye"
        },
        {
            "confidence": 0.07363727186010374,
            "name": "greet"
        }
    ],
    "text": "我发烧了该吃什么药?"
}

Rasa UI界面

上面可以看到这种后台服务、前台curl的方式,其实已经可以代替之前提到的一大票云端的NLU服务了。

有热心的前端大牛还做了一个Rasa UI,提供Rasa的界面。理论上是要将前面提到的示例数据的添加、模型的训练以及服务的监控等等都做成一个漂亮的web界面。只是现在还开发的非常不完善,大部分的功能还都没有加进去。

有兴趣的朋友可以clone下来装一个试试。效果如下:

 

Rasa_NLU_Chi

Rasa NLU 是一个开源的、可本地部署并配套有语料标注工具(rasa-nlu-trainer)的自然语言理解框架。其本身是只支持英文和德文,中文因为其特殊性需要加入特定的 tokenizer 作为整个流水线的一部分,Rasa_NLU_Chi 作为 Rasa_NLU 的一个 fork 版本,加入了 jieba 作为中文的 tokenizer,实现了中文支持。

本篇即简单介绍基于 Rasa_NLU_Chi 构建一个本地部署的特定领域的中文 NLU 系统的过程和注意事项。

Why Rasa NLU

自然语言理解(NLU)系统是 chatbot 的基石,尽管使用正则或者模板匹配的方式也能在很多场景下实现一个简单的问答系统,但却缺乏泛化和学习的能力,而基于机器学习的 NLU 系统则可以举一反三不断学习改进模型从而获得越来越好的性能表现。

目前已有的 NLU 工具,大多是以服务的方式,通过调用远程 http 的 restful API 来对目标语句进行解析。包括 Google 的 API.ai、Microsoft 的 Luis.ai、Facebook 的 Wit.ai 等。这些 NLU 系统一边为用户提供NLU的服务,一边也通过用户自己上传的大量标注和非标注数据不断训练和改进自己的模型。对于数据敏感的用户来说,开源的 NLU 工具如 Rasa.ai 就为我们提供了另一种选择。而且这样的开源工具可以本地部署,针对实际需求训练和调整模型,甚至对一些特定领域的需求效果要比那些通用的在线 NLU 服务还要好。

Rasa Stack

Rasa Stack 包括 Rasa NLU 和 Rasa Core,前者负责进行语义理解(意图识别和槽值提取),而后者负责会话管理,控制跟踪会话并决定下一步要做什么,两者都使用了机器学习的方法可以从真实的会话数据进行学习;另外他们之间还相互独立,可以单独使用。

下图是一个简单的基于 Rasa 的 workflow 示意:

Pipeline

rasa nlu 支持不同的 Pipeline,其后端实现可支持 spaCy、MITIE、MITIE + sklearn 以及 tensorflow,其中 spaCy 是官方推荐的,另外值得注意的是从 0.12 版本后,MITIE 就被列入 Deprecated 了。

本例使用的 pipeline 为 MITIE+Jieba+sklearn, rasa nlu 的配置文件为 config_jieba_mitie_sklearn.yml 如下:

language: "zh"

pipeline:
- name: "nlp_mitie"
  model: "data/total_word_feature_extractor_zh.dat"  // 加载 mitie 模型
- name: "tokenizer_jieba"  // 使用 jieba 进行分词
- name: "ner_mitie"  // mitie 的命名实体识别
- name: "ner_synonyms"
- name: "intent_entity_featurizer_regex"
- name: "intent_featurizer_mitie"  // 特征提取
- name: "intent_classifier_sklearn" // sklearn 的意图分类模型

Preparation Work

由于在 pipeline 中使用了 MITIE,所以需要一个训练好的 MITIE 模型。MITIE 模型是非监督训练得到的,类似于 word2vec 中的 word embedding,需要大量的中文语料,由于训练这个模型对内存要求较高,并且耗时很长,这里直接使用了网友分享的中文 wikipedia 和百度百科语料生成的模型文件 total_word_feature_extractor_chi.dat,通过下面的百度网盘可以直接下载。

链接:https://pan.baidu.com/s/1kNENvlHLYWZIddmtWJ7Pdg 密码:p4vx

实际应用中,如果做某个特定领域的 NLU 并收集了很多该领域的语料,可以自己去训练 MITIE 模型,具体训练方法可以参考MITIE – Github

构建 rasa_nlu 语料

得到 MITIE 词向量模型以后便可以借助其训练 Rasa NLU 模型,这里需要使用标注好的数据来训练 rasa_nlu,标注的数据格式如下,Rasa 也很贴心的提供了数据标注平台rasa-nlu-trainer供用户标注数据。这里我们使用项目里提供的标注好的数据(demo-rasa_zh.json)直接进行训练。

[
    {
        "text": "我生病了,不知道去哪里看病",
        "intent": "medical_department",
        "entities": []
    },
    {
        "text": "头上烫烫的,感觉发烧了,该去看哪个诊所哪个科室好呢",
        "intent": "medical_department",
        "entities": [
          {
            "start": 8,
            "end": 10,
            "value": "发烧",
            "entity": "disease"
          }
        ]
    }

]

训练 rasa_nlu 模型

通过上面的准备工作,我们已经有了词向量模型 MITIE 和标注数据,接下来就可以直接按照下面的流程进行训练

$ source activate learn // 切换到之前创建的虚拟环境

$ git clone https://github.com/crownpku/Rasa_NLU_Chi.git // clone 源码

$ cd Rasa_NLU_Chi

$ python setup.py install  // 安装依赖

// 训练Rasa NLU的模型
$ python -m rasa_nlu.train -c sample_configs/config_jieba_mitie_sklearn.yml --data data/examples/rasa/demo-rasa_zh.json --path models

最后一步执行训练会得到一个模型文件如下所示,这个模型文件也是我们应用中进行意图识别和槽值提取直接使用到的模型,这一步可以离线进行训练,也可以在线实时训练。

测试验证

// 启动服务
$ python -m rasa_nlu.server -c sample_configs/config_jieba_mitie_sklearn.yml --path models

//测试服务
$ curl -XPOST localhost:5000/parse -d '{"q":"我感觉headache该吃什么药?", "project": "", "model": "model_20180912-202427"}' | python -mjson.tool

首先启动 Rasa NLU 服务,使用 curl 调用服务验证一下,可以看到如下结果,意图和实体都可以正确识别,同时还会给出识别的打分排序,便于我们观察和调整模型。

{
    "entities": [
        {
            "confidence": null,
            "end": 11,
            "entity": "disease",
            "extractor": "ner_mitie",
            "start": 3,
            "value": "headache"
        }
    ],
    "intent": {
        "confidence": 0.40319739542291566,
        "name": "medical"
    },
    "intent_ranking": [
        {
            "confidence": 0.40319739542291566,
            "name": "medical"
        },
        {
            "confidence": 0.22340213611408624,
            "name": "restaurant_search"
        },
        {
            "confidence": 0.18051898067667496,
            "name": "affirm"
        },
        {
            "confidence": 0.11803116503887297,
            "name": "goodbye"
        },
        {
            "confidence": 0.07485032274745018,
            "name": "greet"
        }
    ],
    "text": "\u6211\u611f\u89c9headache\u8be5\u5403\u4ec0\u4e48\u836f\uff1f"
}

注意事项

实践的过程中遇到了一些问题花了一些时间去解决,记录一下避免下次继续踩坑。

问题一

异常信息:

Exception: Not all required packages are installed. To use this pipeline, you need to install the missing dependencies. Please install sklearn

解决方法:

$pip install -U scikit-learn scipy sklearn-crfsuite

参考:https://github.com/RasaHQ/rasa_nlu/issues/660