譯:Tensorflow實現的CNN文本分類

翻譯自博客:IMPLEMENTING A CNN FOR TEXT CLASSIFICATION IN TENSORFLOWgit

原博文:http://www.wildml.com/2015/12/implementing-a-cnn-for-text-classification-in-tensorflow/github

github:https://github.com/dennybritz/cnn-text-classification-tf網絡

在這篇文章中,咱們將實現一個相似於Kim Yoon的卷積神經網絡語句分類的模型。 本文提出的模型在一系列文本分類任務(如情感分析)中實現了良好的分類性能,並已成爲新的文本分類架構的標準基準。session

本文假設你已經熟悉了應用於NLP的卷積神經網絡的基礎知識。 若是沒有,建議先閱讀Understanding Convolutional Neural Networks for NLP 以得到必要的背景。架構

1. 數據和預處理

咱們將在這篇文章中使用的數據集是 Movie Review data from Rotten Tomatoes,也是原始文獻中使用的數據集之一。 數據集包含10,662個示例評論句子,正負向各佔一半。 數據集的大小約爲20k。 請注意,因爲這個數據集很小,咱們極可能會使用強大的模型。 此外,數據集不附帶拆分的訓練/測試集,所以咱們只需將10%的數據用做 dev set。 原始文獻展現了對數據進行10倍交叉驗證的結果。ide

這裏不討論數據預處理代碼,代碼能夠在 Github 上得到,並執行如下操做:函數

  • 從原始數據文件中加載正負向情感的句子。性能

  • 使用與原始文獻相同的代碼清理文本數據。學習

  • 將每一個句子加到最大句子長度(59)。咱們向全部其餘句子添加特殊的操做,使其成爲59個字。填充句子相同的長度是有用的,由於這樣就容許咱們有效地批量咱們的數據,由於批處理中的每一個示例必須具備相同的長度。測試

  • 構建詞彙索引,並將每一個單詞映射到0到18,765之間的整數(詞庫大小)。 每一個句子都成爲一個整數向量。

2. 模型

原始文獻的網絡結構以下圖:
watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

第一層將單詞嵌入到低維向量中。 下一層使用多個過濾器大小對嵌入的字矢量執行卷積。 例如,一次滑過3,4或5個字。 接下來,咱們將卷積層的max_pooling結果做爲一個長的特徵向量,添加dropout正則,並使用softmax層對結果進行分類。

由於這是是一篇教學性質的博客,因此對於原始文獻的模型進行一下簡化:

  1. 咱們不會對咱們的詞嵌入使用預先訓練的word2vec向量。 相反,咱們從頭開始學習嵌入。

  2. 咱們不會對權重向量執行L2規範約束。 《A Sensitivity Analysis of (and Practitioners’ Guide to) Convolutional Neural Networks for Sentence Classification》這篇文章中發現約束對最終結果幾乎沒有影響。(關注公衆號輸入cnn獲取)

  3. 原始實驗用兩個輸入數據通道 - 靜態和非靜態字矢量。 咱們只使用一個通道。

將這些擴展代碼添加到這裏是比較簡單的(幾十行代碼)。 看看帖子結尾的練習。

3. 代碼實現

爲了容許各類超參數配置,咱們將代碼放入TextCNN類中,在init函數中生成模型圖。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

爲了實例化類,咱們傳遞如下參數:

  • sequence_length - 句子的長度。注意:咱們將全部句子填充到相同的長度(咱們的數據集爲59)。

  • num_classes - 輸出層中的類數,在咱們的例子中爲(消極,積極)。

  • vocab_size - 咱們的詞彙量的大小。 這須要定義咱們的嵌入層的大小,它將具備[vocabulary_size,embedding_size]的形狀。

  • embedding_size - 嵌入的維度。

  • filter_sizes - 咱們想要卷積過濾器覆蓋的字數。 咱們將爲此處指定的每一個大小設置num_filters。 例如,[3,4,5]意味着咱們將有一個過濾器,分別滑過3,4和5個字,總共有3 * num_filters個過濾器。

  • num_filters - 每一個過濾器大小的過濾器數量(見上文)。

3.1 INPUT PLACEHOLDERS

首先定義網絡的輸入數據

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

tf.placeholder建立一個佔位符變量,當咱們在訓練集或測試時間執行它時,咱們將其饋送到網絡。 第二個參數是輸入張量的形狀:None意味着該維度的長度能夠是任何東西。 在咱們的狀況下,第一個維度是批量大小,而且使用「None」容許網絡處理任意大小的批次。

將神經元保留在丟失層中的機率也是網絡的輸入,由於咱們僅在訓練期間使用dropout。 咱們在評估模型時禁用它(稍後再說)。

3.2 EMBEDDING LAYER

咱們定義的第一層是嵌入層,它將詞彙詞索引映射到低維向量表示中。 它本質上是一個從數據中學習的lookup table。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

咱們在這裏使用了幾個功能:

  • tf.device(「/ cpu:0」)強制在CPU上執行操做。 默認狀況下,TensorFlow將嘗試將操做放在GPU上(若是有的話)可用,可是嵌入式實現當前沒有GPU支持,而且若是放置在GPU上會引起錯誤。

  • tf.name_scope建立一個名稱範圍,名稱爲「embedding」。 範圍將全部操做添加到名爲「嵌入」的頂級節點中,以便在TensorBoard中可視化網絡時得到良好的層次結構。

W是咱們在訓練中學習的嵌入矩陣。 咱們使用隨機均勻分佈來初始化它。 tf.nn.embedding_lookup建立實際的嵌入操做。 嵌入操做的結果是形狀爲[None,sequence_length,embedding_size]的三維張量。

TensorFlow的卷積轉換操做具備對應於批次,寬度,高度和通道的尺寸的4維張量。 咱們嵌入的結果不包含通道尺寸,因此咱們手動添加,留下一層shape爲[None,sequence_length,embedding_size,1]。

3.3 CONVOLUTION AND MAX-POOLING LAYERS

如今咱們已經準備好構建卷積層,而後再進行max-pooling。 注意:咱們使用不一樣大小的filter。 由於每一個卷積產生不一樣形狀的張量,咱們須要迭代它們,爲它們中的每個建立一個層,而後將結果合併成一個大特徵向量。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

這裏,W是咱們的濾波器矩陣,h是將非線性應用於卷積輸出的結果。 每一個過濾器在整個嵌入中滑動,可是它涵蓋的字數有所不一樣。 「VALID」填充意味着咱們在沒有填充邊緣的狀況下將過濾器滑過咱們的句子,執行給咱們輸出形狀[1,sequence_length - filter_size + 1,1,1]的窄卷積。 在特定過濾器大小的輸出上執行最大值池將留下一張張量的形狀[batch_size,1,num_filters]。 這本質上是一個特徵向量,其中最後一個維度對應於咱們的特徵。 一旦咱們從每一個過濾器大小獲得全部的彙總輸出張量,咱們將它們組合成一個長形特徵向量[batch_size,num_filters_total]。 在tf.reshape中使用-1能夠告訴TensorFlow在可能的狀況下平坦化維度。

3.4 DROPOUT LAYER

Dropout多是卷積神經網絡正則最流行的方法。Dropout背後的想法很簡單。Dropout層隨機地「禁用」其神經元的一部分。 這能夠防止神經元共同適應(co-adapting),並迫使他們學習個別有用的功能。 咱們保持啓用的神經元的分數由咱們網絡的dropout_keep_prob輸入定義。 在訓練過程當中,咱們將其設置爲0.5,在評估過程當中設置爲1(禁用Dropout)。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.5 SCORES AND PREDICTIONS

使用max-pooling(with dropout )的特徵向量,咱們能夠經過執行矩陣乘法並選擇具備最高分數的類來生成預測。 咱們還能夠應用softmax函數將原始分數轉換爲歸一化機率,但這不會改變咱們的最終預測。

這裏,tf.nn.xw_plus_b是執行Wx + b矩陣乘法的便利包裝器。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.6 LOSS AND ACCURACY

使用分數咱們能夠定義損失函數。 損失是對咱們網絡錯誤的衡量,咱們的目標是將其最小化。分類問題的標準損失函數是交叉熵損失 cross-entropy loss。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

這裏,tf.nn.softmax_cross_entropy_with_logits是一個方便的函數,計算每一個類的交叉熵損失,給定咱們的分數和正確的輸入標籤。 而後求損失的平均值。 咱們也可使用總和,但這比較難以比較不一樣批量大小和訓練/測試集數據的損失。

咱們還爲精度定義一個表達式,這是在訓練和測試期間跟蹤的有用數值。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

TensorFlow能夠看到其結構圖以下:

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.7 TRAINING PROCEDURE

在咱們爲網絡定義訓練程序以前,咱們須要瞭解一些關於TensorFlow如何使用Sessions和Graphs的基礎知識。若是您已經熟悉這些概念,請隨時跳過本節。

在TensorFlow中, Session是正在執行graph 操做的環境,它包含有關變量和隊列的狀態。每一個 Session都在單個graph上運行。若是在建立變量和操做時未明確使用 Session,則使用TensorFlow建立的當前默認 Session。您能夠經過在session.as_default()塊中執行命令來更改默認 Session(見下文)。

Graph包含操做和張量。您能夠在程序中使用多個Graph,但大多數程序只須要一個Graph。您能夠在多個 Session中使用相同的Graph,但在一個 Session中不能使用多Graph。 TensorFlow始終建立一個默認Graph,但您也能夠手動建立一個Graph,並將其設置爲新的默認Graph,以下圖所示。顯式建立 Session和Graph可確保在再也不須要資源時正確釋放資源。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

當優選設備不存在時,allow_soft_placement設置容許TensorFlow回退到具備特定操做的設備上。 例如,若是咱們的代碼在GPU上放置一個操做,而且咱們在沒有GPU的機器上運行代碼,則不使用allow_soft_placement將致使錯誤。 若是設置了log_device_placement,TensorFlow會登陸那些設備(CPU或GPU)進行操做。 這對調試很是有用。 標記是咱們程序的命令行參數。

3.8 INSTANTIATING THE CNN AND MINIMIZING THE LOSS

當咱們實例化咱們的TextCNN模型時,全部定義的變量和操做將被放置在上面建立的默認圖和會話中。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

接下來,咱們定義如何優化網絡的損失函數。 TensorFlow有幾個內置優化器。 咱們正在使用Adam優化器。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

在這裏,train_op這裏是一個新建立的操做,咱們能夠運行它們來對咱們的參數執行更新。 train_op的每次執行都是一個訓練步驟。 TensorFlow自動計算哪些變量是「可訓練的」並計算它們的梯度。 經過定義一個global_step變量並將其傳遞給優化器,讓TensorFlow對訓練步驟進行計數。 每次執行train_op時,global step 將自動遞增1。

3.9 SUMMARIES

TensorFlow有一個概述(summaries),能夠在訓練和評估過程當中跟蹤和查看各類數值。 例如,您可能但願跟蹤您的損失和準確性隨時間的變化。您還能夠跟蹤更復雜的數值,例如圖層激活的直方圖。 summaries是序列化對象,並使用SummaryWriter寫入磁盤。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

在這裏,咱們分別跟蹤培訓和評估的總結。 在咱們的狀況下,這些數值是相同的,可是您可能只有在訓練過程當中跟蹤的數值(如參數更新值)。 tf.merge_summary是將多個摘要操做合併到能夠執行的單個操做中的便利函數。

3.10 CHECKPOINTING

一般使用TensorFlow的另外一個功能是checkpointing- 保存模型的參數以便稍後恢復。Checkpoints 可用於在之後的時間繼續訓練,或使用 early stopping選擇最佳參數設置。 使用Saver對象建立 Checkpoints。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.11 INITIALIZING THE VARIABLES

在訓練模型以前,咱們還須要在圖中初始化變量。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

global_variables_initializer函數是一個方便函數,它運行咱們爲變量定義的全部初始值。也能夠手動調用變量的初始化程序。 若是但願使用預先訓練的值初始化嵌入,這頗有用。

3.12 DEFINING A SINGLE TRAINING STEP

如今咱們來定義一個訓練步驟的函數,評估一批數據上的模型並更新模型參數。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

feed_dict包含咱們傳遞到咱們網絡的佔位符節點的數據。您必須爲全部佔位符節點提供值,不然TensorFlow將拋出錯誤。使用輸入數據的另外一種方法是使用隊列,但這超出了這篇文章的範圍。

接下來,咱們使用session.run執行咱們的train_op,它返回咱們要求它進行評估的全部操做的值。請注意,train_op什麼都不返回,它只是更新咱們網絡的參數。最後,咱們打印當前培訓批次的丟失和準確性,並將摘要保存到磁盤。請注意,若是批量過小,訓練批次的損失和準確性可能會在批次間顯着變化。並且由於咱們使用dropout,您的訓練指標可能開始比您的評估指標更糟。

咱們寫一個相似的函數來評估任意數據集的丟失和準確性,例如驗證集或整個訓練集。本質上這個功能與上述相同,但沒有訓練操做。它也禁用退出。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

3.13 TRAINING LOOP

最後,準備編寫訓練循環。 迭代數據的批次,調用每一個批次的train_step函數,偶爾評估和檢查咱們的模型:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

這裏,batch_iter是一個批處理數據的幫助函數,而tf.train.global_step是返回global_step值的便利函數。

3.14 VISUALIZING RESULTS IN TENSORBOARD

咱們的訓練腳本將summaries寫入輸出目錄,並將TensorBoard指向該目錄,咱們能夠將圖和咱們建立的summaries可視化。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

有幾件事情脫穎而出:

  • 咱們的訓練指標並不平滑,由於咱們使用小批量。 若是咱們使用較大的批次(或在整個訓練集上評估),咱們會獲得一個更平滑的藍線。

  • 由於測試者的準確性顯着低於訓練準確度,咱們的網絡在訓練數據彷佛過擬合了,這代表咱們須要更多的數據(MR數據集很是小),更強的正則化或更少的模型參數。 例如,我嘗試在最後一層爲重量添加額外的L2正則,而且可以將準確度提升到76%,接近於原始文獻。

  • 由於使用了dropout,訓練損失和準確性開始大大低於測試指標。

您可使用代碼進行操做,並嘗試使用各類參數配置運行模型。 Github提供了代碼和說明。

4. EXTENSIONS AND EXERCISES

如下是一些的練習,能夠提升模型的性能:

  • 使用預先訓練的word2vec向量初始化嵌入。 爲了可以起做用,您須要使用300維嵌入,並用預先訓練的值初始化它們。

  • 限制最後一層權重向量的L2範數,就像原始文獻同樣。 您能夠經過定義一個新的操做,在每次訓練步驟以後更新權重值。

  • 將L2正規化添加到網絡以防止過擬合,同時也提升dropout比率。 (Github上的代碼已經包括L2正則化,但默認狀況下禁用)

  • 添加權重更新和圖層操做的直方圖summaries,並在TensorBoard中進行可視化。

 

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

相關文章
相關標籤/搜索