一文讀懂CNN如何用於NLP

原文:一文讀懂CNN如何用於NLPphp

做者:Denny Britzhtml

翻譯:Kaisergit


當咱們聽到「卷積神經網絡」(CNN,固然,不是特朗普說Fake News那個CNN),一般會想到計算機視覺。圖像分類的重大突破,以及當下大多數計算機視覺系統的核心,都要歸功於CNN,從{:facebook:}的自動照片打標籤到自動駕駛汽車不外如是。github


關於卷積處理圖像相關問題,以前已有若干文章,感興趣的讀者可查看:web

最近咱們也開始把CNN應用在天然語言處理問題上,而且搞出一些挺有意思的結果。本文我會總結CNN是什麼,以及如何用於NLP。CNN背後的原理從計算機視覺角度可能更好理解,因此我會先從CV開始講,而後過渡到NLP。網絡


什麼是卷積?

理解卷積最簡單的方式,就是把它想象成一個掃過矩陣的滑動窗口函數。聽起來仍是有點迷糊,可是能夠化以後就清楚多了:架構

Convolution with 3×3 Filter. Source: http://deeplearning.stanford.edu/wiki/index.php/Feature_extraction_using_convolution


想象左邊的矩陣表示黑白圖片。每一個元素對應一個像素,0是黑,1是白(通常來講是0-255之間的數字,表示灰度圖片)。滑動窗口是卷積核(kernel),濾波器(filter),或者「特徵探測器」(feature detector)。機器學習

上圖用的是3x3的卷積核,與原矩陣對應元素相乘(注意不是矩陣乘法)而後求和,讓濾波器掃遍整個矩陣獲得最終的完整卷積。你可能會奇怪這有毛用,如下是幾個直觀的例子。ide


圖像模糊:求每一個像素與鄰近像素地平均值


邊緣檢測:求像素與相鄰像素地差

若是一張圖片是純平沒有任何色差的,那麼每個像素減去周圍像素的結果都將是0,或者黑色。若是有一個明顯的邊緣(兩側差異很大),那通過卷積以後就會留下白色。函數

GIMP manual有幾個其餘的示例,若是還想深刻了解卷積,推薦閱讀Chris Olah’s post on the topic




什麼是卷積神經網絡?

如今你已經知道什麼是卷積了,那CNN呢?CNN其實就是不少層卷積加上非線性激活函數(non-linear activation functions)好比ReLUtanh

在傳統的前饋神經網絡裏,咱們把每一個神經元都鏈接到下一層的每一個神經元上。這就是全鏈接層(fully connected layer)或仿射層(affine layer)。CNN裏咱們不這麼幹,而是對輸入層進行卷積獲得輸出,這就不是「全鏈接」而是「局部鏈接」(local connection)————輸入的一片區域鏈接到單個神經元上。每一層都應用不一樣的卷積核,像上面看到的那種,來上幾百甚至上千個,再把結果組合起來。這就是池化(pooling,下采樣)層,不事後面還會細說。


在訓練過程當中,根據任務設置,CNN會自動學習濾波器的值。好比在圖像分類當中 ,CNN可能會從第一層的原始圖片中學到邊緣檢測,而後在第二層經過邊緣學習簡單的形狀,最後用形狀檢測出人臉這樣的高級特徵、最後一層就是使用高級特徵的分類器。


這個計算過程當中還有兩個點值得注意:位置不變性(location invariance)和組合性(compositionality)。比方說你想判斷圖裏有沒有大象,其實你並不關心大象具體在哪。

第二個關鍵點就是(局部)組合性。每一個卷積核都提取出了一批低級特徵,用做以後的高級表達,這也是爲何CNN在計算機視覺上特別好使。就像點動成線,線動成面。


而後呢?怎麼用在NLP上?

回到咱們的主題——天然語言處理上面,多數任務的輸入都再也不是圖片像素,而是以矩陣表示的句子或者文檔。矩陣的每一行對應一個token,通常是一個單詞或者字符。也即每行表明一個詞向量,一般是像word2vecGloVe詞嵌入(word embedding,低維表示),但這些只能是獨熱碼向量(one-hot vector),10個單詞的句子用100維嵌入,那輸入矩陣就是10x100,這就是咱們的「圖像」。

在視覺問題中,卷積核滑過的是圖像的一「塊」區域,但在天然語言領域裏咱們通常用卷積核滑過矩陣的一「行」(單詞)。而後卷積核的「寬度」就是輸入矩陣的寬度,「高度」可能會變,但通常是每次掃過2-5個單詞。

綜上所述,一個用於NLP的卷積神經網絡看起來大概是這樣:

Illustration of a Convolutional Neural Network (CNN) architecture for sentence classification. Here we depict three filter region sizes: 2, 3 and 4, each of which has 2 filters. Every filter performs convolution on the sentence matrix and generates (variable-length) feature maps. Then 1-max pooling is performed over each map, i.e., the largest number from each feature map is recorded. Thus a univariate feature vector is generated from all six maps, and these 6 features are concatenated to form a feature vector for the penultimate layer. The final softmax layer then receives this feature vector as input and uses it to classify the sentence; here we assume binary classification and hence depict two possible output states. Source: Zhang, Y., & Wallace, B. (2015). A Sensitivity Analysis of (and Practitioners’ Guide to) Convolutional Neural Networks for Sentence Classification.


前面提到的「位置不變性」和「局部組合性」對於圖像而言很直觀,但在NLP裏就有點隱晦了。你關心的多是一個單詞出如今句子的什麼位置。相鄰的圖像像素在語義上也是有關聯的(都屬於同一個物體),但對單詞來說卻不是。在不少語言中,一個短語可能被好幾個別的單詞分割開。

組合性也不是很明顯,雖然咱們都知道意思是通過詞彙組合表達出來的,好比形容詞修飾名詞,可是低級表徵如何組成高級表徵並不像圖像那樣是簡單的空間幾何關係。


這樣看來CNN可能不是很適合作NLP?循環神經網絡, Recurrent Neural Networks彷佛更合適。RNN很像咱們人類處理語言(至少是咱們自認爲處理語言):從左到右順序閱讀。

所幸,這並非說CNN就不能用,俗話說得好,All models are wrong, but some are useful.。實際上CNN在NLP問題上表現得還很是好,一個簡單Bag of Words model看起來顯然過於簡單了,並且理論前提就很不靠譜,但卻已是多年來的標準模式,並且產生的結果也很好。

CNN的一大優點在於快,很是快,卷積是計算機圖形學的核心部分,已經能夠經過GPU硬件級實現。與n-grams等方法相比,CNN在表徵方面也更加高效。隨着詞彙量愈來愈大,計算任何多於3-grams的東西都會很是昂貴。即使是{:google:}都沒有提供出超過5-grams。卷積濾波器自動學習表徵,不須要表示全部詞彙,而大於5的卷積核是很日常的事。我以爲第一層的不少卷積核都是捕捉了與n-grams類似的特徵,可是以更簡潔的形式表達了出來。




卷積神經網絡超參數

在解釋CNN如何用於NLP任務以前,先來看看你在搭建CNN時都須要作哪些選擇,但願這些可以幫助你更好的理解。


卷積:寬vs.窄

以前在解釋卷積的時候我省略了應用核的一個小細節。3x3的核在圖像中心沒問題,那若是是邊緣呢?對於矩陣的第一個元素,左方和上方沒有臨近元素怎麼辦?咱們可使用zero-padding。全部(其實並不存在)掉在矩陣以外的元素都用0填充。這樣就能夠對輸入矩陣的全部元素使用卷積核,獲得更大或一樣大小的輸出。zero-padding也叫寬卷積,若是不用zero-padding就是窄卷積。1D的例子以下圖:

Narrow vs. Wide Convolution. Filter size 5, input size 7. Source: A Convolutional Neural Network for Modelling Sentences (2014)


若是你有一個挺大的卷積核(相對於輸入尺寸而言),那寬卷積仍是頗有效、甚至必要的。在上圖中,窄卷積輸出尺寸是(7-5)+1=3,而寬卷積輸出的是(7+2*4-5)+1=11。輸出尺寸的通常計算公式是:n_{out}=(n_{in}+2*n_{padding}-n_{filter})+1


步幅(stride size)

卷積核的另外一個超參數是步幅,也就是每一步移動卷積核的距離。以前的例子中,步幅都是1,相連的卷積核互相重疊。步幅越大,卷積計算次數越少,輸出尺寸越小。來自Stanford cs231 website的下圖表示1D輸入中,步幅分別爲1和2的效果。

Convolution Stride Size. Left: Stride size 1. Right: Stride size 2. Source: http://cs231n.github.io/convolutional-networks/

1是最多見的步幅,而更大的步幅能夠用來搭建相似Recursive Neural Network的模型,如同樹狀。


池化層

爲何要池化?緣由有多重。一是池化能夠保持輸出尺寸固定,對分類來講這是必要的。好比你有1000個卷積核,分別做max pooling,不論輸入層或濾波器多大,獲得的都是1000維的輸出。

池化層(pooling layer)也是卷積神經網絡裏的一個核心概念,在卷積層以後應用。池化層對他的輸入進行「下采樣」,最經常使用的方法是max操做,也就是隻保留最大值,固然不是非要在整個矩陣上進行,也能夠是通過分割窗口。好比下面的例子展現的是2x2窗口的最大池化(但在NLP中咱們通常對整個矩陣進行池化,每一個卷積核只保留一個數):

Max pooling in CNN. Source: http://cs231n.github.io/convolutional-networks/#pool

池化也減少了輸出維度但(但願可以)保留最顯著的信息。你能夠認爲每一個卷積核的使命是發現一種特徵,好比探測一句話是否含有"not amazing",若是這個短語在句子中出現,卷積在這一部分的結果數值就會比較大,其餘部分較小。而執行了max操做以後,獲得的只有這一特徵是否存在,具體的位置信息便丟失了。那麼這個位置信息重要嗎?其實沒那麼重要,就像是n-grams模型作的那樣。你失去了關於位置的全局信息(在句子的哪一個地方發生),可是保留了濾波器獲得的局部信息,也就是"not amazing"出沒出現,這跟"amazing not"意義徹底不一樣。

在圖像識別當中,池化也提供了平移和旋轉的不變性。當你對一片區域作池化時,平移仍是旋轉幾個像素的影響不大,由於max仍是會選擇原來的值。


通道

最後一個咱們須要瞭解的概念是通道(channel)。通道就是輸入數據的不一樣「視圖」,好比在圖像識別裏,通道常常是RGB(red, green, blue)通道,能夠對每一個通道分別進行卷積操做,會獲得不一樣的權重。

在NLP當中也能夠想象咱們擁有多個通道:不一樣的詞嵌入(word2vec和GloVe)有不一樣的通道,或者同一句話用不一樣語言表述造成多個通道,或者是一個意思的多種表達方式。




用於天然語言處理的卷積神經網絡

來看看CNN在NLP中的應用,我會先總結一些研究成果。固然不少有意思的應用這裏講不到,可是我但願能至少涵蓋比較熱門的幾個。

最自然適合於CNN的應該是分類任務,好比情感分析(Sentiment Analysis),垃圾檢測(Spam Detection)和主題分類(Topic Categorization)。卷積和池化丟失了詞的局部順序信息,因此單純用CNN作序列標註好比 PoS Tagging 或 Entity Extraction 就稍微難點兒(但也不是不行,能夠把位置特徵也加入到輸入裏)。

[1]在多個分類數據集上評估了CNN架構,這些數據集主要是情感分析和主題分類任務。CNN取得了很好的成果,甚至在個別數據集上達到了先進水平。特別是,這篇論文中所用到的CNN結構很是簡單,卻很強力。輸入層是由word2vec詞嵌入組成的語句,而後是若干個卷積核,再來最大池化,最後 softmax 分類。論文還試驗了兩種不一樣的通道:靜態與動態詞嵌入,一個通道隨着訓練不斷調整,另外一個保持不變。[2]提到了一個相似但稍微複雜點的架構,[6]又在網絡里加了一層「語義聚類」。

Kim, Y. (2014). Convolutional Neural Networks for Sentence Classification


[4]從零訓練了一個卷積神經網絡,不須要預訓練詞向量好比word2vec或GloVe,而是直接對獨熱碼向量作卷積。做者還提出了一種相似詞袋模型的空間高效表徵方式用於輸入數據,減小了網絡須要學習的參數數量。[5]的做者拓展了這個模型,加入了無監督的「區域嵌入」,用CNN預測上下文。這些論文中的方法都在長文章上表現良好(好比{:video-camera:}影評),可是對短文章(好比{:twitter:}tweets)尚不清楚。根據直覺來看,引入預訓練詞嵌入對模型在短文數據集上的表現幫助會更大。

搭建CNN架構意味着有不少超參數要選擇,有些是以前提到過的:

  • 輸入表徵(word2vec, GloVe, one-hot)
  • 卷積核的數量、尺寸
  • 池化策略(max, average)
  • 激活函數(ReLU, tanh)

[7]對CNN的不一樣超參數作了個經驗評估,調研它們的表現和屢次運行之間的變化,若是你想部署本身的CNN用做文本分類,這篇論文能夠當作起始參考。有些結果很顯著,好比最大池化老是好於平均池化,理想的卷積核尺寸很重要,可是每一個任務卻都不同,正則化在NLP裏起到的做用不大。這些數據在文檔長度上都比較接近,因此對於文本量差別很大的數據,這裏的經驗未必適用。

[8]把CNN用於關係提取(Relation Extraction)和關係分類(Relation Classification)任務。除了詞向量之外,做者還用了詞的相對位置做爲卷積層輸入。這個模型假設詞的位置肯定以後,每一個樣例就會含有一種關係。[9]和[10]也探索了相似模型。

另外一個把CNN用在NLP上的有趣實例可見於[11]和[12],來自微軟研究院。這些論文描述了句子的語義表徵可用於信息檢索(Information Retrieval)。論文中給出的例子是根據用戶正在閱讀的材料,推薦他們可能感興趣的文檔。句子表徵基於搜索引擎日誌數據訓練。

大多數CNN架構學習的是在訓練過程中的嵌入(低維表徵),但並不是全部論文都集中在訓練或研究學習出來的嵌入有多少意義。[13]用CNN預測Facebook posts的標籤,同時爲詞句生成有意義的嵌入。這些學得的嵌入還能夠用在其餘任務——基於點擊流數據的興趣推薦。


字符級卷積神經網絡

至此,大部分介紹過的模型都是基於詞彙的。可是還有些研究將CNN直接用到字符層面上。[14]學習出了字符級的前途,把他們加入到詞嵌入當中,而後把CNN用到語音標籤當中。[15][16]讓CNN直接從字符裏學習,連預訓練嵌入都不用。注意,做者用了相對深得網絡(9層),而後用於情感分析和文本分類。結果顯示在大型數據集上還不錯(上百萬樣本),但在小數據集上反而不如簡單模型(十萬級樣本)。[17]用字符級CNN的輸出看成LSTM每一個時間步的輸入,這個模型也用在了多種語言上。

好消息是,上面咱們提到的論文都是近1-2年發佈的(如今要在往前推一年了),雖然以前已經有了一些很讚的成果好比Natural Language Processing (almost) from Scratch,但新成果的發表和系統應用仍在持續加速發展。


推薦閱讀

「女生科技體驗節」 TensorFlow Workshop

這評論有毒!——文本分類的通常套路

我作了一個叫「瑟曦」的機器人,但是她動不動就想讓格雷果爵士弄死我。



參考文獻

相關文章
相關標籤/搜索