深度學習近一段時間以來在圖像處理和NLP任務上都取得了不俗的成績。通常,圖像處理的任務是借助CNN來完成的,其特有的卷積、池化結構能夠提取圖像中各種不同程度的紋理、結構,並最終結合全連接網絡實現信息的匯總和輸出。RNN由於其記憶功能為處理NLP中的上下文提供了途徑。
在短文本分析任務中,由於句子句長長度有限、結構緊湊、能夠獨立表達意思,使得CNN在處理這一類問題上成為可能。論文Convolutional Neural Networks for Sentence Classification(論文作者Yoon Kim)即在這一類問題上做了嘗試。首先來看看論文中介紹的模型結構及原理:
CNN模型結構如下:
一共包括4部分:
1、 輸入層:
如圖所示,輸入層是句子中的詞語對應的wordvector依次(從上到下)排列的矩陣,假設句子有 n 個詞,vector的維數為 k ,那么這個矩陣就是 n × k 的(在CNN中可以看作一副高度為n、寬度為k的圖像)。
這個矩陣的類型可以是靜態的(static),也可以是動態的(non static)。靜態就是word vector是固定不變的,而動態則是在模型訓練過程中,word vector也當做是可優化的參數,通常把反向誤差傳播導致word vector中值發生變化的這一過程稱為Fine tune。(這里如果word vector如果是隨機初始化的,不僅訓練得到了CNN分類模型,還得到了word2vec這個副產品了,如果已經有訓練的word vector,那么其實是一個遷移學習的過程)
對於未登錄詞的vector,可以用0或者隨機小的正數來填充。
2、 第一層卷積層:
輸入層通過卷積操作得到若干個Feature Map,卷積窗口的大小為 h ×k ,其中 h 表示縱向詞語的個數,而 k 表示word vector的維數。通過這樣一個大型的卷積窗口,將得到若干個列數為1的Feature Map。(熟悉NLP中N-GRAM模型的讀者應該懂得這個意思)。
3、 池化層:
接下來的池化層,文中用了一種稱為Max-over-timePooling的方法。這種方法就是簡單地從之前一維的Feature Map中提出最大的值,文中解釋最大值代表着最重要的信號。可以看出,這種Pooling方式可以解決可變長度的句子輸入問題(因為不管Feature Map中有多少個值,只需要提取其中的最大值)。最終池化層的輸出為各個Feature Map的最大值們,即一個一維的向量。
4、 全連接+softmax層:
池化層的一維向量的輸出通過全連接的方式,連接一個Softmax層,Softmax層可根據任務的需要設置(通常反映着最終類別上的概率分布)。
訓練方案:
在倒數第二層的全連接部分上使用Dropout技術,Dropout是指在模型訓練時隨機讓網絡某些隱含層節點的權重不工作,不工作的那些節點可以暫時認為不是網絡結構的一部分,但是它的權重得保留下來(只是暫時不更新而已),因為下次樣本輸入時它可能又得工作了,它是防止模型過擬合的一種常用的trikc。同時對全連接層上的權值參數給予L2正則化的限制。這樣做的好處是防止隱藏層單元自適應(或者對稱),從而減輕過擬合的程度。
在樣本處理上使用minibatch方式來降低一次模型擬合計算量,使用shuffle_batch的方式來降低各批次輸入樣本之間的相關性(在機器學習中,如果訓練數據之間相關性很大,可能會讓結果很差、泛化能力得不到訓練、這時通常需要將訓練數據打散,稱之為shuffle_batch)。
論文作者也公布了自己的實現程序(下載戳這里),同時有一位同行對上述論文給出了解讀並基於上述程序做了對比實驗(論文解讀戳這里)。本人上面的分析也是基於原始論文和解讀,算是錦上添花吧。
實驗流程及結果:
參考上述論文和源程序,本人對其在中文短文本分類問題上進行了實驗。
實驗要求:
Python環境
安裝結巴分析的python版本
安裝numpy、pandas等一系列科學計算相關庫,windows下借助Anaconda進行安裝比較方便
安裝theano,這個參考各種安裝、使用教程吧。
語料庫:使用的是搜狗語料庫,搜索SogouC.reduced可找到下載連接。
文本預處理:
使用jieba分詞后將一些實詞漢詞提取出來,同時,由於CNN輸入窗口的大小是一定的,對於長度小於N的句子,使用Pad with zeroes的方式,對於長度大於N的句子,將其切分為若干段長度小於等於N的句子。使用軍事和教育兩個題材的預料進行處理后,樣本總數量大致在2W的樣子。
訓練調參:
模型結構與trikc均與原文一直,在處理word vector size時,采用原始論文采用的300時,效果不是太理想,將該參數調低,采用szie=50、size=100,最終效果還算可以。同時,feature_map的數量要比word vector size值大一些,以盡可能提取更為豐富的句子信息。
下面是訓練過程中的一些結果:

word vector size=50& feature_maps size = 100
來看看訓練得到的wordvector在語義空間的映射效果如果,以該詞對應的向量空間的余弦積的形式衡量詞之間的相似性:
左:word vector size=50 & feature_maps size= 100 右:word vector size=100& feature_maps size = 100
軍事題材類的詞,語義表達的效果較好,而醫療衛生相關的則效果一般。如果原始預料集更大,可能效果還會進一步提升的。同時,也可以考慮使用word2vec模型訓練得到word vector,在使用上述模型訓練CNN分類模型,同時更新word vector。
本文同時在知加發表,歡迎圍觀。
最后,進過本人使用的實驗代碼可從github下載(Theano),對作者的原始代碼做了比較詳盡的注釋,同時增加漢語的分詞預處理模塊和后面的word vector展現模塊。
個人采用Tensorflow實現的版本:github (Tensorflow版本),歡迎一起交流學習~~~