天天看點

支援中文的Rasa NLU訓練服務部署---Rasa_NLU_Chi

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

本文大部分内容抄自http://www.crownpku.com/2017/07/27/%E7%94%A8Rasa_NLU%E6%9E%84%E5%BB%BA%E8%87%AA%E5%B7%B1%E7%9A%84%E4%B8%AD%E6%96%87NLU%E7%B3%BB%E7%BB%9F.html

但是它的内容已經嚴重過時,根本跑不起來,結合自己部署過程中踏過的一些坑,形成此文。

部署環境:Ubuntu 16.04+python 3.6

Rasa NLU本身是隻支援英文和德文的。中文因為其特殊性需要加入特定的tokenizer作為整個流水線的一部分。我加入了jieba作為我們中文的tokenizer,這個适用于中文的rasa NLU的版本代碼在github上。

語料擷取及預處理

如果直接使用中文wikipedia和百度百科語料生成的total_word_feature_extractor_chi.dat(連結如下),可直接跳至建構rasa_nlu語料和模型部分

連結:https://pan.baidu.com/s/1kNENvlHLYWZIddmtWJ7Pdg 密碼:p4vx
           

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下來:

我們要使用的隻是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
           

建構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": []
      }
           

對于中文我們現在有兩種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做意圖識别的分類。

  • 訓練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
           

這樣就會生成一個類似model_20xxxxxx-xxxxxxx的檔案在 /models/default 的檔案夾裡。

如果報錯提示需要安裝mitie或sklearn,可用pip install安裝。

搭建本地rasa_nlu服務

  • 啟動rasa_nlu的背景服務:
python -m rasa_nlu.server -c sample_configs/config_jieba_mitie_sklearn.yml --path models
           
  • 打開一個新的terminal,我們現在就可以使用curl指令擷取結果了, 舉個例子:
curl -XPOST localhost:5000/parse -d '{"q":"我發燒了該吃什麼藥","model": "model_20200821-002830"}' | python -mjson.tool
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   781    0   713  100    68    234     22  0:00:03  0:00:03 --:--:--   234
{
    "intent": {
        "name": "medical",
        "confidence": 0.41050353032074
    },
    "entities": [
        {
            "entity": "disease",
            "value": "\u53d1\u70e7",
            "start": 1,
            "end": 3,
            "confidence": null,
            "extractor": "ner_mitie"
        }
    ],
    "intent_ranking": [
        {
            "name": "medical",
            "confidence": 0.41050353032074
        },
        {
            "name": "restaurant_search",
            "confidence": 0.268388781853104
        },
        {
            "name": "affirm",
            "confidence": 0.1452713537374723
        },
        {
            "name": "goodbye",
            "confidence": 0.11560279492180317
        },
        {
            "name": "greet",
            "confidence": 0.06023353916688072
        }
    ],
    "text": "\u6211\u53d1\u70e7\u4e86\u8be5\u5403\u4ec0\u4e48\u836f"
}
           

當然,你需要把model_20xxxxxx替換成你的model名字。

如果報錯 "y should be a 1d array, got an array of shape() instead."

支援中文的Rasa NLU訓練服務部署---Rasa_NLU_Chi

原因是因為sklearn的代碼validation.py裡面對y的格式有要求,需要把y的格式從二維矩陣轉換成一維矩陣

支援中文的Rasa NLU訓練服務部署---Rasa_NLU_Chi

也可以用postman

支援中文的Rasa NLU訓練服務部署---Rasa_NLU_Chi

繼續閱讀