代碼在 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."
原因是因為sklearn的代碼validation.py裡面對y的格式有要求,需要把y的格式從二維矩陣轉換成一維矩陣
也可以用postman