本文從最簡單的QA系統入手來逐步深入。最簡單的QA系統原理,就是假定蒐集了一批問答對(暫且認為這裡所有的答案都是正確的)。那麼,當一個新問題輸入系統之後,系統拿這個問題,和所有庫存的問題比較,找到一個最接近的問答對,把答案返回來。

怎麼找?

第一步是建立詞向量矩陣,Word2Vec演算法目前在Spark ML,Ski-learn,以及Tensorflow教程裏到處都有。我打算先把程序調試出來,因此先用Tensorflow上提供的源代碼來做。語料庫呢,先用那個著名的保險問答語料庫(Samurais/insuranceqa-corpus-zh)。從這個語料庫中可以抽出14萬個句子,22000個單詞,100維的embedding向量。最後只需要把訓練出來的embedding矩陣保存到numpy存檔文件中即可,這個存檔文件有8M多。

對這個embedding做點可視化(用TSNE把100維向量壓縮成2維向量,然後畫到坐標繫上):

第二步,是把句子轉換成低維度的矩陣。這一步參考了[Socher, 2012]的自編碼器模型。文中用了Stanford parser,Stanford parser生成的是依存樹,而文中需要的是二叉樹。考慮了一下午如何把一顆依存樹(或者說是個有向無環圖)轉成二叉樹的問題,形成如下演算法:

transform_binary_tree(Node):
如果此Node有孩子節點:
對每一個孩子節點Child_node,依次:
transform_binary_tree(Child_node)
否則:
找到自己的父節點Parent_node
如果Node和Parent_node的編號是連續的,則刪掉自己,自己與父節點做一次combine操作。

combine(child, parent):
在老樹上,刪除parent。
在新樹上,如果沒有這兩個節點,則加上,然後以這兩個節點為葉節點,生成一個新的父節點。

main():
循環執行transform_binary_tree(根節點),直到整棵樹只有一個節點。

參考文獻:

[Socher, 2012] Dynamic Pooling and Unfolding Recursive Auto-encoders for Paraphrase Detection

推薦閱讀:

相關文章