原文位址:http://www.leiphone.com/news/201702/4ozau7ofcno0v1u5.html
資料預處理
【圖 3-1】 語料預處理, ref. #7
下面主要介紹兩個内容:
中文分詞
# coding:utf8 ''' segmenter with chinese ''' import jieba import langid def segment_chinese_sentence(sentence): ''' return segmented sentence. seg_list = jieba.cut(sentence, cut_all=false) seg_sentence = u" ".join(seg_list) return seg_sentence.strip().encode('utf8') def process_sentence(sentence): only process chinese sentence. if langid.classify(sentence)[0] == 'zh': return segment_chinese_sentence(sentence) return sentence if __name__ == "__main__": print(process_sentence('飛雪連天射白鹿')) print(process_sentence('i have a pen.'))
在功能上,jieba分詞支援全切分模式,精确模式和搜尋引擎模式。
全切分:輸出所有分詞。
精确:機率上的最佳分詞。
所有引擎模式:對精确切分後的長句再進行分詞。
jieba分詞的實作
主要是分成下面三步:
1、加載字典,在記憶體中建立字典空間。
字典的構造是每行一個詞,空格,詞頻,空格,詞性。
上訴書 3 n 上訴人 3 n 上訴期 3 b 上訴狀 4 n 上課 650 v
建立字典空間的是使用python的dict,采用字首數組的方式。
使用字首數組的原因是樹結構隻有一層 - word:freq,效率高,節省空間。比如單詞"dog", 字典中将這樣存儲:
{ "d": 0, "do": 0, "dog": 1 # value為詞頻 }
字典空間的主要用途是對輸入句子建立有向無環圖,然後根據算法進行切分。算法的取舍主要是根據模式 - 全切,精确還是搜尋。
2、對輸入的語句分詞,首先是建立一個有向無環圖。
【圖 3-2】 dag
dag對于後面計算最大機率路徑和使用hnn模型識别新詞有直接關系。
3、按照模式,對有向無環圖進行周遊,比如,在精确模式下,便利就是求最大權重和的路徑,權重來自于在字典中定義的詞頻。對于沒有出現在詞典中的詞,連續的單個字元也許會構成新詞。然後用hmm模型和viterbi算法識别新詞。
最大機率路徑:求route = (w1, w2, w3 ,.., wn),使得Σweight(wi)最大。wi為該詞的詞頻。
自定義字典
jieba分詞預設的字典是:1998人民日報的切分語料還有一個msr的切分語料和一些txt小說。開發者可以自行添加字典,隻要符合字典建構的格式就行。
jieba分詞同時提供接口添加詞彙。
word embedding
【圖 3-3】 word embedding, ref. #7
word embedding是文本的數值化表示方法。表示法包括one-hot,bag of words,n-gram,分布式表示,共現矩陣等。
word2vec
使用word2vec
word2vec -train "data/review.txt" \ -output "data/review.model" \ -cbow 1 \ -size 100 \ -window 8 \ -negative 25 \ -hs 0 \ -sample 1e-4 \ -threads 20 \ -binary 1 \ -iter 15
-train "data/review.txt" 表示在指定的語料庫上訓練模型
-cbow 1 表示用cbow模型,設成0表示用skip-gram模型
-size 100 詞向量的次元為100
-window 8 訓練視窗的大小為8 即考慮一個單詞的前八個和後八個單詞
-negative 25 -hs 0 是使用negative sample還是hs算法
-sample 1e-4 采用門檻值
-threads 20 線程數
-binary 1 輸出model儲存成2進制
-iter 15 疊代次數
在訓練完成後,就得到一個model,用該model可以查詢每個詞的詞向量,在詞和詞之間求距離,将不同詞放在數學公式中計算輸出相關性的詞。比如:
vector("法國") - vector("巴黎) + vector("英國") = vector("倫敦")"
對于訓練不同的語料庫,可以單獨的訓練詞向量模型,可以利用已經訓練好的模型。
seq2seq
+ decoder -> target】的映射,在上面的論文中,清晰的介紹了實作方式。
【圖 3-4】 seq2seq, ref. #1
也有很多文章解讀它的原理。在使用seq2seq的過程中,雖然也研究了它的結構,但我還不認為能了解和解釋它。下面談兩點感受:
a. rnn儲存了語言順序的特點,這和cnn在處理帶有形狀的模型時如出一轍,就是數學模型的設計符合實體模型。
【圖 3-5】 rnn, ref. #6
b. lstm cell的複雜度對應了自然語言處理的複雜度。
【圖 3-6】 lstm, ref. #6
理由是,有人将lstm cell嘗試了多種其它方案傳遞狀态,結果也很好。
【圖 3-7】 gru, ref. #6
lstm的一個替代方案:gru。隻要rnn的cell足夠複雜,它就能工作的很好。
使用deepqa2訓練語言模型
準備工作,下載下傳項目:
git clone https://github.com/samurais/deepqa2.git cd deepqa2 open readme.md # 根據readme.md安裝依賴包
deepqa2将工作分成三個過程:
資料預處理:從語料庫到資料字典。
訓練模型:從資料字典到語言模型。
提供服務:從語言模型到rest api。
預處理
train_max_length_enco就是問題的長度,train_max_length_deco就是答案的長度。在語料庫中,大于該長度的部分會被截斷。
程式運作後,會生成dataset-cornell-20.pkl檔案,它加載到python中是一個字典:
word2id存儲了{word: id},其中word是一個單詞,id是int數字,代表這個單詞的id。
id2word存儲了{id: word}。
trainingsamples存儲了問答的對話對。
比如 [[[1,2,3],[4,5,6]], [[7,8,9], [10, 11, 12]]]
1,2,3 ... 12 都是word id。
[1,2,3] 和 [4,5,6] 構成一個問答。 [7,8,9] 和 [10, 11, 12] 構成一個問答。
開始訓練
cp config.sample.ini config.ini # modify keys python deepqa2/train.py
config.ini是配置檔案, 根據config.sample.ini進行修改。訓練的時間由epoch,learning rate, maxlength和對話對的數量而定。
session是網絡圖,由placeholder, variable, cell, layer, output 組成。
saver是儲存model的,也可以用來恢複model。model就是執行個體化variable的session。
writer是檢視loss fn或者其他開發者感興趣的資料的收集器。writer的結果會被saver儲存,然後使用tensorboard檢視。
【圖 3-8】 tensorboard
model
model的建構要考慮輸入,狀态,softmax,輸出。
定義損耗函數,使用adamoptimizer進行疊代。
最後,參考一下訓練的loop部分。
每次訓練,model會被存儲在 save路徑下,檔案夾的命名根據機器的hostname,時間戳生成。
提供服務
在tensorflow中,提供了标準的serving子產品 - tensorflow serving。但研究了很久,還專門看了一遍 《c++ essentials》,還沒有将它搞定,社群也普遍抱怨tensorflow serving不好學,不好用。訓練結束後,使用下面的腳本啟動服務,deepqa2的serve部分還是調用tensorflow的python api。
cd deepqa2/save/deeplearning.cobra.vulcan.20170127.175256/deepqa2/serve cp db.sample.sqlite3 db.sqlite3 python manage.py runserver 0.0.0.0:8000
測試
post /api/v1/question http/1.1 host: 127.0.0.1:8000 content-type: application/json authorization: basic ywrtaw46cgfzc3dvcmqxmjm= cache-control: no-cache {"message": "good to know"} response "rc": 0, "msg": "hello"
使用腳本
對模型的評價
目前代碼具有很高的維護性,這也是從deepqa項目進行重構的原因,更清晰的資料預處理、訓練和服務。有新的變更可以添加到deepqa2/models中,然後在train.py和chatbotmanager.py變更一下。
有待改進的地方
a. 建立models/rnn2.py, 使用dropout。目前deepqa中已經使用了drop.
b. tensorflow rc0.12.x中已經提供了seq2seq network,可以更新成tf版本.
d. 代碼支援多機多gpu運作。
e. 目前訓練的結果都是qa對,對于一個問題,可以有多個答案。
f. 目前沒有一個方法進行accuracy測試,一個思路是在訓練中就提供幹擾項,因為目前隻有正确的答案,如果提供錯誤的答案(而且越多越好),就可以使用recall_at_k方法進行測試。
最後
歡迎聯系我,尤其是業内人士,給予指正,一起優化。
本系列完結。
references