專案地址:https://github.com/deepmipt/DeepPavlov
這是一個開源的對話 AI 庫,建立在 TensorFlow 和 Keras 上,其用途是:
NLP 和對話系統研究;
複雜對話系統的實現和評估。
我們的目標是為研究者提供:
用於實現和測試他們自己的對話模型並隨後將模型共享的框架;
一系列預定義的 NLP 模型/對話系統元件(機器學習/深度學習/規則系統)和流程模板;
對話模型的基準測試環境和對相關資料的系統性評估。
併為 AI 應用開發者提供:
建立對話軟體的框架;
將應用與對應基礎建設(通訊、技術支援軟體等)相整合的工具。
專案特徵
格位填充元件(Slot filling component):基於命名實體識別(NER)神經網路和模糊 Levenshtein 搜尋,以從文字中提取歸一化的格位值(slot values)。NER 網路元件根據論文《Application of a Hybrid Bi-LSTM-CRF model to the task of Russian Named Entity Recognition》重新生成了架構,由《Neural Architectures for Named Entity Recognition》中的 LSTM+CRF 架構所啟發。
專用分類元件:基於論文《Convolutional Neural Networks for Sentence Classification》中的 shallow-and-wide CNN 架構。該模型允許語句的多標籤分類。
自動拼寫和校正元件:基於論文《An Improved Error Model for Noisy Channel Spelling Correction》,並使用基於統計學的誤差模型、一個靜態詞典和一個 ARPA 語言模型以校正拼寫錯誤。
目標導向的對話機器人:基於論文《Hybrid Code Networks: practical and efficient end-to-end dialog control with supervised and reinforcement learning》中的 Hybrid Code Networks 架構。它允許在目標導向任務的對話中預測回應。該模型是相當可定製的:嵌入、格位填充器和專用分類器可以根據需要使用或者不用。
為俄語預訓練的嵌入:在聯合俄語 Wikipedia 和 Lenta.ru 語料庫詞向量上進行預訓練得到的詞嵌入。
簡單示例
用 Telegram 部署目標導向的對話機器人和格位填充(slot-filling)的影片 demo:
用 Telegram 介面執行目標導向的對話機器人:
python deep.py interactbot skills/go_bot/config.json -t <TELEGRAM_TOKEN>
用控制檯介面執行目標導向的對話機器人:
python deep.py interact skills/go_bot/config.json
用 Telegram 介面執行格位填充模型:
python deep.py interactbot models/ner/config.json -t <TELEGRAM_TOKEN>
用控制檯介面執行格位填充模型:
python deep.py interact models/ner/config.json
概念簡述
原則
這個庫遵循以下原則設計:
將端到端學習架構作為長期目標;
目前採用混合的機器學習/深度學習/規則系統的架構;
模組化的對話系統架構;
基於元件的軟體工程,最大化複用性;
易於擴充套件和基準測試;
為單個 NLP 任務提供多個元件,透過資料驅動選擇合適的元件。
目標架構
我們的庫的目標架構:
DeepPavlov 建立在機器學習庫(TensorFlow、Keras)之上。可以用其它外部的庫建立基礎元件。
關鍵概念
Agent(智慧體):對話智慧體用自然語言(文字)和使用者進行交流。
Skill(技能):用於滿足使用者需求的互動單元。通常可以透過展示資訊或完成任務(例如,透過 FAQ 回答問題等);然而,根據經驗,某些任務的成功會被定義成連續的進展(例如,閒聊)。
Components(元件):基礎功能模組:
Rule-based Components(基於規則的元件)—無法訓練;
Machine Learning Components(機器學習元件)—僅能獨立訓練;
Deep Learning Components(深度學習元件)—可以獨立地訓練,也能以端對端的方式結合到工作鏈中。
Switcher(轉換器):智慧體排序和選擇向使用者展示的最終應答的機制。
Components Chainer(元件連結器):從各種元件(Rule-based/ml/dl)構建智慧體/元件管道的工具,允許以整體的形式訓練和推理管道。
技術概覽
專案模組
配置
NLP 的流程配置為 JSON 檔案,它包含四個元素:
{
"dataset_reader": {
},
"dataset": {
},
"vocabs": {
},
"model": {
}
}
配置檔案中每一個類都有一個 name 引數,它是註冊的程式碼名。透過重複它的__init__() 方法引數,我們可以定義其它任何引數。__init__() 引數的預設值在類的例項初始化中被配置值覆蓋。
資料集讀取器
DatasetReader 類能讀取資料並返回特定的格式。一個具體的 DatasetReader 類應該從基本的 deeppavlov.data.dataset_reader.DatasetReader 類繼承,並註冊為程式碼名:
@register('dstc2_datasetreader')
class DSTC2DatasetReader(DatasetReader):
資料集
Dataset 類構成我們所需的資料集(「訓練」、「驗證」和「測試」)和批次資料。一個具體的 Dataset 類應該註冊並可以從 deeppavlov.data.dataset_reader.Dataset 類繼承。
deeppavlov.data.dataset_reader.Dataset 類不是抽象類,它同樣可以像 Dataset 類那樣使用。
詞彙
Vocab 是一個可訓練的類,它能構建和序列化詞彙。Vocab 能索引任何資料,它能索引 X(特徵)和 y(回答)型別的資料。一個具體的 Vocab 類應該註冊並可以從 deeppavlov.data.vocab.DefaultVocabulary 類繼承。
deeppavlov.data.vocab.DefaultVocabulary 並不是一個抽象的類,它同樣可以像 Vocab 類那樣使用。
模型
Model 是制定訓練、推斷過程和生成特徵的主要類。如果模型需要其它模型生成特徵,那麼就需要將其傳遞到建構函式和配置檔案中。所有的模型可根據需要巢狀,例如 deeppavlov.skills.go_bot.go_bot.GoalOrientedBot 主要由 11 個獨立的 Model 類構建,其中有三個為神經網路:
{
"model": {
"name": "go_bot",
"network": {
"name": "go_bot_rnn"
},
"slot_filler": {
"name": "dstc_slotfilling",
"ner_network": {
"name": "ner_tagging_network",
}
},
"intent_classifier": {
"name": "intent_model",
"embedder": {
"name": "fasttext"
},
"tokenizer": {
"name": "nltk_tokenizer"
}
},
"embedder": {
"name": "fasttext"
},
"bow_encoder": {
"name": "bow"
},
"tokenizer": {
"name": "spacy_tokenizer"
},
"tracker": {
"name": "featurized_tracker"
}
}
}
所有模型都應該註冊並從 deeppavlov.core.models.inferable.Inferable 或 Inferable 和 deeppavlov.core.models.trainable.Trainable 介面繼承。從 Trainable 繼承的模型可以繼續訓練,從 Inferable 介面繼承的模型只能執行推斷。通常,Inferable 模型是基於規則的模型或從第三方庫匯入的預訓練模型。
訓練
所有從 deeppavlov.core.models.trainable.Trainable 介面繼承的模型都可訓練,訓練過程在 train() 方法中有詳細描述。
@register("my_model")
class MyModel(Inferable, Trainable):
def train(*args, **kwargs):
"""
Implement training here.
"""
所有在實驗中可以改變的訓練引數(如 Epoch 數、批次大小、容忍度、學習率個最佳化器等)都應該傳遞到模型的建構函式__init__(),且__init__() 中的預設引數值將會被 JSON 配置值覆蓋。要改變這些值,我們不需重寫程式碼,只需要修改配置檔案就行。
訓練過程由 train_now 屬性控制。如果 train_now 為真,表示模型正在執行訓練。在使用 Vocab 時,這個引數十分有用,因為可以在單個模型中訓練一些詞彙,而另一些詞彙只會在流程中的其它模型上執行推斷。JASON 配置檔案中的訓練引數以設定成:
{
"model": {
"name": "my_model",
"train_now": true,
"optimizer": "Adam",
"learning_rate": 0.2,
"num_epochs": 1000
}
}
推斷
所有從 deeppavlov.core.models.inferable.Inferable 介面繼承的模型都能執行推斷。infer() 方法應返回模型可執行的操作,例如分詞器應該返回符號、命名實體識別器應該返回識別的實體等。此外,infer() 中應該定義特定格式的返回資料。
推斷由 deeppavlov.core.commands.train.infer_model_from_config()函式觸發,並不需要單獨的 JSON 進行推斷,且 train_now 引數在推斷中也會被忽略。